From 9219cbf9d13df3455314b73ea0ded886a7cc0ea8 Mon Sep 17 00:00:00 2001 From: Jay Bryant Date: Wed, 21 Apr 2021 16:01:26 -0500 Subject: [PATCH 1/7] Editing pass I went through everything to get it to fit with Spring's docuemntation standard. Lots of small changes for punctuation, grammar, usage, voice, and so on. Also added some links, mostly to the API Javadoc. --- 0001-master-main.patch | 254 + ...kie-secure-flag-configurable-WebFlux.patch | 271 + 0003-Editing-pass.patch | 23196 ++++++++++++++++ .../authentication/password-storage.adoc | 165 +- .../about/authentication/supported.adoc | 4 +- .../_includes/about/exploits/csrf.adoc | 188 +- .../_includes/about/exploits/headers.adoc | 218 +- .../_includes/about/exploits/http.adoc | 20 +- .../_includes/about/exploits/index.adoc | 2 +- .../asciidoc/_includes/about/features.adoc | 1 + .../about/getting-spring-security.adoc | 60 +- .../asciidoc/_includes/about/modules.adoc | 30 +- .../_includes/reactive/exploits/csrf.adoc | 125 +- .../_includes/reactive/exploits/headers.adoc | 69 +- .../_includes/reactive/exploits/http.adoc | 14 +- .../asciidoc/_includes/reactive/method.adoc | 13 +- .../reactive/oauth2/access-token.adoc | 11 +- .../_includes/reactive/oauth2/login.adoc | 49 +- .../reactive/oauth2/resource-server.adoc | 377 +- .../registered-oauth2-authorized-client.adoc | 23 +- .../asciidoc/_includes/reactive/rsocket.adoc | 115 +- .../asciidoc/_includes/reactive/test.adoc | 292 +- .../_includes/reactive/webclient.adoc | 34 +- .../asciidoc/_includes/reactive/webflux.adoc | 37 +- .../asciidoc/_includes/reactive/x509.adoc | 15 +- .../servlet/appendix/database-schema.adoc | 85 +- .../_includes/servlet/appendix/faq.adoc | 483 +- .../_includes/servlet/appendix/index.adoc | 2 + .../_includes/servlet/appendix/namespace.adoc | 2036 +- .../architecture/delegating-filter-proxy.adoc | 16 +- .../exception-translation-filter.adoc | 22 +- .../architecture/filter-chain-proxy.adoc | 2 + .../servlet/architecture/filters.adoc | 20 +- .../_includes/servlet/architecture/index.adoc | 4 +- .../architecture/security-filter-chain.adoc | 40 +- .../architecture/security-filters.adoc | 62 +- .../servlet/authentication/anonymous.adoc | 74 +- ...ract-authentication-processing-filter.adoc | 20 +- .../authentication-entry-point.adoc | 10 +- .../architecture/authentication-manager.adoc | 4 +- .../architecture/authentication-provider.adoc | 4 +- .../architecture/authentication.adoc | 16 +- .../architecture/granted-authority.adoc | 18 +- .../architecture/provider-manager.adoc | 26 +- .../architecture/security-context-holder.adoc | 34 +- .../_includes/servlet/authentication/cas.adoc | 286 +- .../servlet/authentication/events.adoc | 14 +- .../servlet/authentication/index.adoc | 44 +- .../servlet/authentication/jaas.adoc | 92 +- .../servlet/authentication/logout.adoc | 65 +- .../servlet/authentication/openid.adoc | 40 +- .../servlet/authentication/preauth.adoc | 88 +- .../servlet/authentication/rememberme.adoc | 75 +- .../servlet/authentication/runas.adoc | 38 +- .../authentication/session-management.adoc | 161 +- .../servlet/authentication/unpwd/basic.adoc | 43 +- .../unpwd/dao-authentication-provider.adoc | 12 +- .../servlet/authentication/unpwd/digest.adoc | 20 +- .../servlet/authentication/unpwd/form.adoc | 91 +- .../authentication/unpwd/in-memory.adoc | 15 +- .../servlet/authentication/unpwd/index.adoc | 10 +- .../servlet/authentication/unpwd/jdbc.adoc | 30 +- .../servlet/authentication/unpwd/ldap.adoc | 100 +- .../unpwd/password-encoder.adoc | 4 +- .../unpwd/user-details-service.adoc | 4 +- .../servlet/authentication/x509.adoc | 53 +- .../_includes/servlet/authorization/acls.adoc | 197 +- .../servlet/authorization/architecture.adoc | 145 +- .../authorization/authorize-requests.adoc | 45 +- .../authorization/expression-based.adoc | 212 +- .../servlet/authorization/index.adoc | 7 +- .../authorization/method-security.adoc | 87 +- .../servlet/authorization/secure-objects.adoc | 55 +- .../_includes/servlet/crypto/index.adoc | 80 +- .../_includes/servlet/exploits/csrf.adoc | 156 +- .../_includes/servlet/exploits/firewall.adoc | 90 +- .../_includes/servlet/exploits/headers.adoc | 82 +- .../_includes/servlet/exploits/http.adoc | 10 +- .../_includes/servlet/exploits/index.adoc | 2 + .../_includes/servlet/hello/index.adoc | 12 +- .../servlet/integrations/concurrency.adoc | 116 +- .../_includes/servlet/integrations/cors.adoc | 20 +- .../_includes/servlet/integrations/data.adoc | 19 +- .../_includes/servlet/integrations/index.adoc | 2 + .../servlet/integrations/jackson.adoc | 14 +- .../servlet/integrations/jsp-taglibs.adoc | 94 +- .../servlet/integrations/localization.adoc | 32 +- .../_includes/servlet/integrations/mvc.adoc | 153 +- .../servlet/integrations/servlet-api.adoc | 100 +- .../servlet/integrations/websocket.adoc | 204 +- .../servlet/java-configuration/index.adoc | 139 +- .../servlet/kotlin-configuration/index.adoc | 39 +- .../_includes/servlet/namespace/index.adoc | 216 +- .../_includes/servlet/oauth2/index.adoc | 2 + .../servlet/oauth2/oauth2-client.adoc | 318 +- .../servlet/oauth2/oauth2-login.adoc | 172 +- .../servlet/oauth2/oauth2-resourceserver.adoc | 526 +- .../_includes/servlet/saml2/index.adoc | 5 +- .../_includes/servlet/saml2/saml2-login.adoc | 401 +- .../_includes/servlet/test/index.adoc | 5 +- .../_includes/servlet/test/method.adoc | 177 +- .../_includes/servlet/test/mockmvc.adoc | 488 +- docs/manual/src/docs/asciidoc/index.adoc | 7 +- 103 files changed, 29230 insertions(+), 5045 deletions(-) create mode 100644 0001-master-main.patch create mode 100644 0002-Make-Csrf-cookie-secure-flag-configurable-WebFlux.patch create mode 100644 0003-Editing-pass.patch diff --git a/0001-master-main.patch b/0001-master-main.patch new file mode 100644 index 00000000000..943b460b697 --- /dev/null +++ b/0001-master-main.patch @@ -0,0 +1,254 @@ +From 006b9b960797d279b31cf8c8d16f1549c5632b2c Mon Sep 17 00:00:00 2001 +From: Rob Winch +Date: Mon, 26 Apr 2021 16:50:35 -0500 +Subject: [PATCH 1/3] master->main + +Closes gh-9683 +--- + .github/workflows/continuous-integration-workflow.yml | 10 +++++----- + CONTRIBUTING.adoc | 6 +++--- + README.adoc | 6 +++--- + .../org/springframework/gradle/sagan/SaganApi.java | 2 +- + docs/guides/spring-security-docs-guides.gradle | 2 +- + docs/guides/src/docs/asciidoc/Guardfile | 2 +- + docs/manual/spring-security-docs-manual.gradle | 2 +- + .../src/docs/asciidoc/_includes/about/community.adoc | 2 +- + .../src/docs/asciidoc/_includes/reactive/x509.adoc | 2 +- + .../asciidoc/_includes/servlet/appendix/namespace.adoc | 2 +- + .../_includes/servlet/integrations/servlet-api.adoc | 1 - + .../_includes/servlet/integrations/websocket.adoc | 2 -- + .../_includes/servlet/java-configuration/index.adoc | 2 +- + .../_includes/servlet/kotlin-configuration/index.adoc | 2 +- + 14 files changed, 20 insertions(+), 23 deletions(-) + +diff --git a/.github/workflows/continuous-integration-workflow.yml b/.github/workflows/continuous-integration-workflow.yml +index 58358c6e59..65201e4596 100644 +--- a/.github/workflows/continuous-integration-workflow.yml ++++ b/.github/workflows/continuous-integration-workflow.yml +@@ -3,7 +3,7 @@ name: CI + on: + push: + branches: +- - master ++ - main + schedule: + - cron: '0 10 * * *' # Once per day at 10am UTC + workflow_dispatch: # Manual trigger +@@ -102,16 +102,16 @@ jobs: + uses: actions/setup-java@v1 + with: + java-version: '11' +- - name: Run Sonar on given (non-master) branch +- if: ${{ github.ref != 'refs/heads/master' }} ++ - name: Run Sonar on given (non-main) branch ++ if: ${{ github.ref != 'refs/heads/main' }} + run: | + export BRANCH=${GITHUB_REF#refs/heads/} + export GRADLE_ENTERPRISE_CACHE_USERNAME="$GRADLE_ENTERPRISE_CACHE_USER" + export GRADLE_ENTERPRISE_CACHE_PASSWORD="$GRADLE_ENTERPRISE_CACHE_PASSWORD" + export GRADLE_ENTERPRISE_ACCESS_KEY="$GRADLE_ENTERPRISE_SECRET_ACCESS_KEY" + ./gradlew sonarqube -PartifactoryUsername="$ARTIFACTORY_USERNAME" -PartifactoryPassword="$ARTIFACTORY_PASSWORD" -PexcludeProjects='**/samples/**' -Dsonar.projectKey="spring-security-${GITHUB_REF#refs/heads/}" -Dsonar.projectName="spring-security-${GITHUB_REF#refs/heads/}" -Dsonar.host.url="$SONAR_URL" -Dsonar.login="$SONAR_TOKEN" --stacktrace +- - name: Run Sonar on master +- if: ${{ github.ref == 'refs/heads/master' }} ++ - name: Run Sonar on main ++ if: ${{ github.ref == 'refs/heads/main' }} + run: | + export GRADLE_ENTERPRISE_CACHE_USERNAME="$GRADLE_ENTERPRISE_CACHE_USER" + export GRADLE_ENTERPRISE_CACHE_PASSWORD="$GRADLE_ENTERPRISE_CACHE_PASSWORD" +diff --git a/CONTRIBUTING.adoc b/CONTRIBUTING.adoc +index e951f69040..0599fb99ec 100644 +--- a/CONTRIBUTING.adoc ++++ b/CONTRIBUTING.adoc +@@ -4,7 +4,7 @@ _Please refer back to this document as a checklist before issuing any pull reque + + = Code of Conduct + +-Please see our https://github.com/spring-projects/.github/blob/master/CODE_OF_CONDUCT.md[code of conduct]. ++Please see our https://github.com/spring-projects/.github/blob/main/CODE_OF_CONDUCT.md[code of conduct]. + + = Similar but different + +@@ -43,9 +43,9 @@ If you're considering anything more than correcting a typo or fixing a minor bug + + If you have not previously done so, please fill out and submit the https://cla.pivotal.io/sign/spring[Contributor License Agreement]. + +-= Create your branch from master ++= Create your branch from main + +-Create your topic branch to be submitted as a pull request from master. The Spring team will consider your pull request for backporting on a case-by-case basis; you don't need to worry about submitting anything for backporting. ++Create your topic branch to be submitted as a pull request from main. The Spring team will consider your pull request for backporting on a case-by-case basis; you don't need to worry about submitting anything for backporting. + + = Use short branch names + +diff --git a/README.adoc b/README.adoc +index 4fda007d1a..6cb3f95061 100644 +--- a/README.adoc ++++ b/README.adoc +@@ -1,6 +1,6 @@ + image::https://badges.gitter.im/Join%20Chat.svg[Gitter,link=https://gitter.im/spring-projects/spring-security?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge] + +-image:https://github.com/spring-projects/spring-security/workflows/CI/badge.svg?branch=master["Build Status", link="https://github.com/spring-projects/spring-security/actions?query=workflow%3ACI"] ++image:https://github.com/spring-projects/spring-security/workflows/CI/badge.svg?branch=main["Build Status", link="https://github.com/spring-projects/spring-security/actions?query=workflow%3ACI"] + + image:https://img.shields.io/badge/Revved%20up%20by-Gradle%20Enterprise-06A0CE?logo=Gradle&labelColor=02303A["Revved up by Gradle Enterprise", link="https://ge.spring.io/scans?search.rootProjectNames=spring-security"] + +@@ -12,7 +12,7 @@ a minimum and also requires Java 8. + For a detailed list of features and access to the latest release, please visit https://spring.io/projects[Spring projects]. + + == Code of Conduct +-Please see our https://github.com/spring-projects/.github/blob/master/CODE_OF_CONDUCT.md[code of conduct] ++Please see our https://github.com/spring-projects/.github/blob/main/CODE_OF_CONDUCT.md[code of conduct] + + == Downloading Artifacts + See https://docs.spring.io/spring-security/site/docs/current/reference/html5/#getting[Getting Spring Security] for how to obtain Spring Security. +@@ -60,7 +60,7 @@ Check out the https://stackoverflow.com/questions/tagged/spring-security[Spring + https://spring.io/services[Commercial support] is available too. + + == Contributing +-https://help.github.com/articles/creating-a-pull-request[Pull requests] are welcome; see the https://github.com/spring-projects/spring-security/blob/master/CONTRIBUTING.adoc[contributor guidelines] for details. ++https://help.github.com/articles/creating-a-pull-request[Pull requests] are welcome; see the https://github.com/spring-projects/spring-security/blob/main/CONTRIBUTING.adoc[contributor guidelines] for details. + + == License + Spring Security is Open Source software released under the +diff --git a/buildSrc/src/main/java/org/springframework/gradle/sagan/SaganApi.java b/buildSrc/src/main/java/org/springframework/gradle/sagan/SaganApi.java +index d40f296c20..24eeb3111c 100644 +--- a/buildSrc/src/main/java/org/springframework/gradle/sagan/SaganApi.java ++++ b/buildSrc/src/main/java/org/springframework/gradle/sagan/SaganApi.java +@@ -23,7 +23,7 @@ import java.io.IOException; + import java.util.Base64; + + /** +- * Implements necessary calls to the Sagan API See https://github.com/spring-io/sagan/blob/master/sagan-site/src/docs/asciidoc/index.adoc ++ * Implements necessary calls to the Sagan API See https://spring.io/restdocs/index.html + */ + public class SaganApi { + private String baseUrl = "https://spring.io/api"; +diff --git a/docs/guides/spring-security-docs-guides.gradle b/docs/guides/spring-security-docs-guides.gradle +index 6c337c030a..8876dddd93 100644 +--- a/docs/guides/spring-security-docs-guides.gradle ++++ b/docs/guides/spring-security-docs-guides.gradle +@@ -28,7 +28,7 @@ ext.spec = copySpec { + } + + def getDownloadUrl() { +- snapshotBuild ? "https://github.com/spring-projects/spring-security/archive/master.zip" : "https://github.com/spring-projects/spring-security/archive/${project.version}.zip" ++ snapshotBuild ? "https://github.com/spring-projects/spring-security/archive/main.zip" : "https://github.com/spring-projects/spring-security/archive/${project.version}.zip" + } + + +diff --git a/docs/guides/src/docs/asciidoc/Guardfile b/docs/guides/src/docs/asciidoc/Guardfile +index ec57b640f2..1075c0114c 100644 +--- a/docs/guides/src/docs/asciidoc/Guardfile ++++ b/docs/guides/src/docs/asciidoc/Guardfile +@@ -5,7 +5,7 @@ guard 'shell' do + watch(/^.*\.asc$/) {|m| + Asciidoctor.render_file(m[0], :to_dir => "build/", :safe => Asciidoctor::SafeMode::UNSAFE, :attributes=> {'toc' => '', 'idprefix' => '', 'idseparator' => '-', 'copycss' => '', 'icons' => 'font', 'source-highlighter' => 'prettify', 'sectanchors' => '', 'toc-placement' => 'preamble', 'revnumber' => '3.2.0.CI-SNAPSHOT', + 'spring-security-version' => '3.2.0.CI-SNAPSHOT', +- 'download-url' => 'https://github.com/spring-projects/spring-security/archive/master.zip', ++ 'download-url' => 'https://github.com/spring-projects/spring-security/archive/main.zip', + 'include-maven-repository' => '_includes/maven-repository-snapshot.asc' }) + } + end +diff --git a/docs/manual/spring-security-docs-manual.gradle b/docs/manual/spring-security-docs-manual.gradle +index a0a2ececd9..75c245f7de 100644 +--- a/docs/manual/spring-security-docs-manual.gradle ++++ b/docs/manual/spring-security-docs-manual.gradle +@@ -14,7 +14,7 @@ asciidoctor { + } + + asciidoctorj { +- def ghTag = snapshotBuild ? 'master' : project.version ++ def ghTag = snapshotBuild ? 'main' : project.version + def ghUrl = "https://github.com/spring-projects/spring-security/tree/$ghTag" + attributes 'spring-security-version' : project.version, + 'spring-boot-version' : springBootVersion, +diff --git a/docs/manual/src/docs/asciidoc/_includes/about/community.adoc b/docs/manual/src/docs/asciidoc/_includes/about/community.adoc +index dc83c0c68c..893d17727b 100644 +--- a/docs/manual/src/docs/asciidoc/_includes/about/community.adoc ++++ b/docs/manual/src/docs/asciidoc/_includes/about/community.adoc +@@ -19,7 +19,7 @@ The following are some of the best ways to get help: + == Becoming Involved + We welcome your involvement in the Spring Security project. + There are many ways to contribute, including answering questions on Stack Overflow, writing new code, improving existing code, assisting with documentation, developing samples or tutorials, reporting bugs, or simply making suggestions. +-For more information, see our https://github.com/spring-projects/spring-security/blob/master/CONTRIBUTING.adoc[Contributing] documentation. ++For more information, see our https://github.com/spring-projects/spring-security/blob/main/CONTRIBUTING.adoc[Contributing] documentation. + + [[community-source]] + == Source Code +diff --git a/docs/manual/src/docs/asciidoc/_includes/reactive/x509.adoc b/docs/manual/src/docs/asciidoc/_includes/reactive/x509.adoc +index 4dc59526cc..694b905093 100644 +--- a/docs/manual/src/docs/asciidoc/_includes/reactive/x509.adoc ++++ b/docs/manual/src/docs/asciidoc/_includes/reactive/x509.adoc +@@ -49,4 +49,4 @@ public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) { + + In this example, a username is extracted from the OU field of a client certificate instead of CN, and account lookup using `ReactiveUserDetailsService` is not performed at all. Instead, if the provided certificate issued to an OU named "Trusted Org Unit", a request will be authenticated. + +-For an example of configuring Netty and `WebClient` or `curl` command-line tool to use mutual TLS and enable X.509 authentication, please refer to https://github.com/spring-projects/spring-security/tree/master/samples/boot/webflux-x509. ++For an example of configuring Netty and `WebClient` or `curl` command-line tool to use mutual TLS and enable X.509 authentication, please refer to https://github.com/spring-projects/spring-security-samples/tree/main/servlet/java-configuration/authentication/x509. +diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/appendix/namespace.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/appendix/namespace.adoc +index a9e321ff59..87d802ca8e 100644 +--- a/docs/manual/src/docs/asciidoc/_includes/servlet/appendix/namespace.adoc ++++ b/docs/manual/src/docs/asciidoc/_includes/servlet/appendix/namespace.adoc +@@ -4,7 +4,7 @@ This appendix provides a reference to the elements available in the security nam + If you haven't used the namespace before, please read the <> on namespace configuration, as this is intended as a supplement to the information there. + Using a good quality XML editor while editing a configuration based on the schema is recommended as this will provide contextual information on which elements and attributes are available as well as comments explaining their purpose. + The namespace is written in https://relaxng.org/[RELAX NG] Compact format and later converted into an XSD schema. +-If you are familiar with this format, you may wish to examine the https://raw.githubusercontent.com/spring-projects/spring-security/master/config/src/main/resources/org/springframework/security/config/spring-security-4.1.rnc[schema file] directly. ++If you are familiar with this format, you may wish to examine the https://raw.githubusercontent.com/spring-projects/spring-security/main/config/src/main/resources/org/springframework/security/config/spring-security-4.1.rnc[schema file] directly. + + [[nsa-web]] + === Web Application Security +diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/servlet-api.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/servlet-api.adoc +index e57d545c15..5e4077c3f9 100644 +--- a/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/servlet-api.adoc ++++ b/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/servlet-api.adoc +@@ -1,7 +1,6 @@ + [[servletapi]] + == Servlet API integration + This section describes how Spring Security is integrated with the Servlet API. +-The https://github.com/spring-projects/spring-security/tree/master/samples/xml/servletapi[servletapi-xml] sample application demonstrates the usage of each of these methods. + + + [[servletapi-25]] +diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/websocket.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/websocket.adoc +index fcd99840d9..ffcf46b5a4 100644 +--- a/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/websocket.adoc ++++ b/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/websocket.adoc +@@ -4,8 +4,6 @@ + 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. + +-NOTE: You can find a complete working sample of WebSocket security at https://github.com/spring-projects/spring-session/tree/master/spring-session-samples/spring-session-sample-boot-websocket. +- + .Direct JSR-356 Support + **** + Spring Security does not provide direct JSR-356 support because doing so would provide little value. +diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/java-configuration/index.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/java-configuration/index.adoc +index 6367f402f6..3ba5432ddc 100644 +--- a/docs/manual/src/docs/asciidoc/_includes/servlet/java-configuration/index.adoc ++++ b/docs/manual/src/docs/asciidoc/_includes/servlet/java-configuration/index.adoc +@@ -7,7 +7,7 @@ Since Spring Security 3.2 there has been Spring Security Java Configuration supp + + If you are familiar with the <> then you should find quite a few similarities between it and the Security Java Configuration support. + +-NOTE: Spring Security provides https://github.com/spring-projects/spring-security/tree/master/samples/javaconfig[lots of sample applications] which demonstrate the use of Spring Security Java Configuration. ++NOTE: Spring Security provides https://github.com/spring-projects/spring-security-samples/tree/main/servlet/java-configuration[lots of sample applications] which demonstrate the use of Spring Security Java Configuration. + + == Hello Web Security Java Configuration + +diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/kotlin-configuration/index.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/kotlin-configuration/index.adoc +index 2e38e0ec35..767ab7ed80 100644 +--- a/docs/manual/src/docs/asciidoc/_includes/servlet/kotlin-configuration/index.adoc ++++ b/docs/manual/src/docs/asciidoc/_includes/servlet/kotlin-configuration/index.adoc +@@ -4,7 +4,7 @@ + Spring Security Kotlin Configuration support has been available since Spring Security 5.3. + It enables users to easily configure Spring Security using a native Kotlin DSL. + +-NOTE: Spring Security provides https://github.com/spring-projects/spring-security/tree/master/samples/boot/kotlin[a sample application] which demonstrates the use of Spring Security Kotlin Configuration. ++NOTE: Spring Security provides https://github.com/spring-projects/spring-security-samples/tree/main/servlet/spring-boot/kotlin/hello-security[a sample application] which demonstrates the use of Spring Security Kotlin Configuration. + + [[kotlin-config-httpsecurity]] + == HttpSecurity +-- +2.24.1 + diff --git a/0002-Make-Csrf-cookie-secure-flag-configurable-WebFlux.patch b/0002-Make-Csrf-cookie-secure-flag-configurable-WebFlux.patch new file mode 100644 index 00000000000..7f2cb6a5d32 --- /dev/null +++ b/0002-Make-Csrf-cookie-secure-flag-configurable-WebFlux.patch @@ -0,0 +1,271 @@ +From e2993d93e109c1a3c9020b7ea9efb6e556751ed4 Mon Sep 17 00:00:00 2001 +From: Thomas Vitale +Date: Mon, 26 Apr 2021 18:13:20 +0200 +Subject: [PATCH 2/3] Make Csrf cookie secure flag configurable (WebFlux) + +Make the XSRF-TOKEN cookie secure flag configurable in CookieServerCsrfTokenRepository. + +Closes gh-9678 +--- + .../csrf/CookieServerCsrfTokenRepository.java | 30 ++++-- + .../CookieServerCsrfTokenRepositoryTests.java | 100 ++++++++++++++++-- + 2 files changed, 113 insertions(+), 17 deletions(-) + +diff --git a/web/src/main/java/org/springframework/security/web/server/csrf/CookieServerCsrfTokenRepository.java b/web/src/main/java/org/springframework/security/web/server/csrf/CookieServerCsrfTokenRepository.java +index 5910ff3e45..bc3a20e711 100644 +--- a/web/src/main/java/org/springframework/security/web/server/csrf/CookieServerCsrfTokenRepository.java ++++ b/web/src/main/java/org/springframework/security/web/server/csrf/CookieServerCsrfTokenRepository.java +@@ -1,5 +1,5 @@ + /* +- * Copyright 2002-2019 the original author or authors. ++ * Copyright 2002-2021 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. +@@ -34,6 +34,7 @@ import org.springframework.web.server.ServerWebExchange; + * AngularJS. When using with AngularJS be sure to use {@link #withHttpOnlyFalse()} . + * + * @author Eric Deandrea ++ * @author Thomas Vitale + * @since 5.1 + */ + public final class CookieServerCsrfTokenRepository implements ServerCsrfTokenRepository { +@@ -54,6 +55,8 @@ public final class CookieServerCsrfTokenRepository implements ServerCsrfTokenRep + + private boolean cookieHttpOnly = true; + ++ private Boolean secure; ++ + /** + * Factory method to conveniently create an instance that has + * {@link #setCookieHttpOnly(boolean)} set to false. +@@ -75,11 +78,16 @@ public final class CookieServerCsrfTokenRepository implements ServerCsrfTokenRep + public Mono saveToken(ServerWebExchange exchange, CsrfToken token) { + return Mono.fromRunnable(() -> { + String tokenValue = (token != null) ? token.getToken() : ""; +- int maxAge = !tokenValue.isEmpty() ? -1 : 0; +- String path = (this.cookiePath != null) ? this.cookiePath : getRequestContext(exchange.getRequest()); +- boolean secure = exchange.getRequest().getSslInfo() != null; +- ResponseCookie cookie = ResponseCookie.from(this.cookieName, tokenValue).domain(this.cookieDomain) +- .httpOnly(this.cookieHttpOnly).maxAge(maxAge).path(path).secure(secure).build(); ++ // @formatter:off ++ ResponseCookie cookie = ResponseCookie ++ .from(this.cookieName, tokenValue) ++ .domain(this.cookieDomain) ++ .httpOnly(this.cookieHttpOnly) ++ .maxAge(!tokenValue.isEmpty() ? -1 : 0) ++ .path((this.cookiePath != null) ? this.cookiePath : getRequestContext(exchange.getRequest())) ++ .secure((this.secure != null) ? this.secure : (exchange.getRequest().getSslInfo() != null)) ++ .build(); ++ // @formatter:on + exchange.getResponse().addCookie(cookie); + }); + } +@@ -146,6 +154,16 @@ public final class CookieServerCsrfTokenRepository implements ServerCsrfTokenRep + this.cookieDomain = cookieDomain; + } + ++ /** ++ * Sets the cookie secure flag. If not set, the value depends on ++ * {@link ServerHttpRequest#getSslInfo()}. ++ * @param secure The value for the secure flag ++ * @since 5.5 ++ */ ++ public void setSecure(boolean secure) { ++ this.secure = secure; ++ } ++ + private CsrfToken createCsrfToken() { + return createCsrfToken(createNewToken()); + } +diff --git a/web/src/test/java/org/springframework/security/web/server/csrf/CookieServerCsrfTokenRepositoryTests.java b/web/src/test/java/org/springframework/security/web/server/csrf/CookieServerCsrfTokenRepositoryTests.java +index d16f131920..7160337053 100644 +--- a/web/src/test/java/org/springframework/security/web/server/csrf/CookieServerCsrfTokenRepositoryTests.java ++++ b/web/src/test/java/org/springframework/security/web/server/csrf/CookieServerCsrfTokenRepositoryTests.java +@@ -1,5 +1,5 @@ + /* +- * Copyright 2002-2018 the original author or authors. ++ * Copyright 2002-2021 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. +@@ -16,12 +16,15 @@ + + package org.springframework.security.web.server.csrf; + ++import java.security.cert.X509Certificate; + import java.time.Duration; + ++import org.junit.Before; + import org.junit.Test; + + import org.springframework.http.HttpCookie; + import org.springframework.http.ResponseCookie; ++import org.springframework.http.server.reactive.SslInfo; + import org.springframework.mock.http.server.reactive.MockServerHttpRequest; + import org.springframework.mock.web.server.MockServerWebExchange; + import org.springframework.util.StringUtils; +@@ -30,13 +33,14 @@ import static org.assertj.core.api.Assertions.assertThat; + + /** + * @author Eric Deandrea ++ * @author Thomas Vitale + * @since 5.1 + */ + public class CookieServerCsrfTokenRepositoryTests { + +- private MockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get("/someUri")); ++ private CookieServerCsrfTokenRepository csrfTokenRepository; + +- private CookieServerCsrfTokenRepository csrfTokenRepository = new CookieServerCsrfTokenRepository(); ++ private MockServerHttpRequest.BaseBuilder request; + + private String expectedHeaderName = CookieServerCsrfTokenRepository.DEFAULT_CSRF_HEADER_NAME; + +@@ -56,6 +60,12 @@ public class CookieServerCsrfTokenRepositoryTests { + + private String expectedCookieValue = "csrfToken"; + ++ @Before ++ public void setUp() { ++ this.csrfTokenRepository = new CookieServerCsrfTokenRepository(); ++ this.request = MockServerHttpRequest.get("/someUri"); ++ } ++ + @Test + public void generateTokenWhenDefaultThenDefaults() { + generateTokenAndAssertExpectedValues(); +@@ -82,8 +92,9 @@ public class CookieServerCsrfTokenRepositoryTests { + + @Test + public void saveTokenWhenNoSubscriptionThenNotWritten() { +- this.csrfTokenRepository.saveToken(this.exchange, createToken()); +- assertThat(this.exchange.getResponse().getCookies().getFirst(this.expectedCookieName)).isNull(); ++ MockServerWebExchange exchange = MockServerWebExchange.from(this.request); ++ this.csrfTokenRepository.saveToken(exchange, createToken()); ++ assertThat(exchange.getResponse().getCookies().getFirst(this.expectedCookieName)).isNull(); + } + + @Test +@@ -112,6 +123,56 @@ public class CookieServerCsrfTokenRepositoryTests { + saveAndAssertExpectedValues(createToken()); + } + ++ @Test ++ public void saveTokenWhenSslInfoPresentThenSecure() { ++ this.request.sslInfo(new MockSslInfo()); ++ MockServerWebExchange exchange = MockServerWebExchange.from(this.request); ++ this.csrfTokenRepository.saveToken(exchange, createToken()).block(); ++ ResponseCookie cookie = exchange.getResponse().getCookies().getFirst(this.expectedCookieName); ++ assertThat(cookie).isNotNull(); ++ assertThat(cookie.isSecure()).isTrue(); ++ } ++ ++ @Test ++ public void saveTokenWhenSslInfoNullThenNotSecure() { ++ MockServerWebExchange exchange = MockServerWebExchange.from(this.request); ++ this.csrfTokenRepository.saveToken(exchange, createToken()).block(); ++ ResponseCookie cookie = exchange.getResponse().getCookies().getFirst(this.expectedCookieName); ++ assertThat(cookie).isNotNull(); ++ assertThat(cookie.isSecure()).isFalse(); ++ } ++ ++ @Test ++ public void saveTokenWhenSecureFlagTrueThenSecure() { ++ MockServerWebExchange exchange = MockServerWebExchange.from(this.request); ++ this.csrfTokenRepository.setSecure(true); ++ this.csrfTokenRepository.saveToken(exchange, createToken()).block(); ++ ResponseCookie cookie = exchange.getResponse().getCookies().getFirst(this.expectedCookieName); ++ assertThat(cookie).isNotNull(); ++ assertThat(cookie.isSecure()).isTrue(); ++ } ++ ++ @Test ++ public void saveTokenWhenSecureFlagFalseThenNotSecure() { ++ MockServerWebExchange exchange = MockServerWebExchange.from(this.request); ++ this.csrfTokenRepository.setSecure(false); ++ this.csrfTokenRepository.saveToken(exchange, createToken()).block(); ++ ResponseCookie cookie = exchange.getResponse().getCookies().getFirst(this.expectedCookieName); ++ assertThat(cookie).isNotNull(); ++ assertThat(cookie.isSecure()).isFalse(); ++ } ++ ++ @Test ++ public void saveTokenWhenSecureFlagFalseAndSslInfoThenNotSecure() { ++ MockServerWebExchange exchange = MockServerWebExchange.from(this.request); ++ this.request.sslInfo(new MockSslInfo()); ++ this.csrfTokenRepository.setSecure(false); ++ this.csrfTokenRepository.saveToken(exchange, createToken()).block(); ++ ResponseCookie cookie = exchange.getResponse().getCookies().getFirst(this.expectedCookieName); ++ assertThat(cookie).isNotNull(); ++ assertThat(cookie.isSecure()).isFalse(); ++ } ++ + @Test + public void loadTokenWhenCookieExistThenTokenFound() { + loadAndAssertExpectedValues(); +@@ -127,7 +188,8 @@ public class CookieServerCsrfTokenRepositoryTests { + + @Test + public void loadTokenWhenNoCookiesThenNullToken() { +- CsrfToken csrfToken = this.csrfTokenRepository.loadToken(this.exchange).block(); ++ MockServerWebExchange exchange = MockServerWebExchange.from(this.request); ++ CsrfToken csrfToken = this.csrfTokenRepository.loadToken(exchange).block(); + assertThat(csrfToken).isNull(); + } + +@@ -180,8 +242,8 @@ public class CookieServerCsrfTokenRepositoryTests { + private void loadAndAssertExpectedValues() { + MockServerHttpRequest.BodyBuilder request = MockServerHttpRequest.post("/someUri") + .cookie(new HttpCookie(this.expectedCookieName, this.expectedCookieValue)); +- this.exchange = MockServerWebExchange.from(request); +- CsrfToken csrfToken = this.csrfTokenRepository.loadToken(this.exchange).block(); ++ MockServerWebExchange exchange = MockServerWebExchange.from(request); ++ CsrfToken csrfToken = this.csrfTokenRepository.loadToken(exchange).block(); + if (StringUtils.hasText(this.expectedCookieValue)) { + assertThat(csrfToken).isNotNull(); + assertThat(csrfToken.getHeaderName()).isEqualTo(this.expectedHeaderName); +@@ -198,8 +260,9 @@ public class CookieServerCsrfTokenRepositoryTests { + this.expectedMaxAge = Duration.ofSeconds(0); + this.expectedCookieValue = ""; + } +- this.csrfTokenRepository.saveToken(this.exchange, token).block(); +- ResponseCookie cookie = this.exchange.getResponse().getCookies().getFirst(this.expectedCookieName); ++ MockServerWebExchange exchange = MockServerWebExchange.from(this.request); ++ this.csrfTokenRepository.saveToken(exchange, token).block(); ++ ResponseCookie cookie = exchange.getResponse().getCookies().getFirst(this.expectedCookieName); + assertThat(cookie).isNotNull(); + assertThat(cookie.getMaxAge()).isEqualTo(this.expectedMaxAge); + assertThat(cookie.getDomain()).isEqualTo(this.expectedDomain); +@@ -211,7 +274,8 @@ public class CookieServerCsrfTokenRepositoryTests { + } + + private void generateTokenAndAssertExpectedValues() { +- CsrfToken csrfToken = this.csrfTokenRepository.generateToken(this.exchange).block(); ++ MockServerWebExchange exchange = MockServerWebExchange.from(this.request); ++ CsrfToken csrfToken = this.csrfTokenRepository.generateToken(exchange).block(); + assertThat(csrfToken).isNotNull(); + assertThat(csrfToken.getHeaderName()).isEqualTo(this.expectedHeaderName); + assertThat(csrfToken.getParameterName()).isEqualTo(this.expectedParameterName); +@@ -226,4 +290,18 @@ public class CookieServerCsrfTokenRepositoryTests { + return new DefaultCsrfToken(headerName, parameterName, tokenValue); + } + ++ static class MockSslInfo implements SslInfo { ++ ++ @Override ++ public String getSessionId() { ++ return "sessionId"; ++ } ++ ++ @Override ++ public X509Certificate[] getPeerCertificates() { ++ return new X509Certificate[] {}; ++ } ++ ++ } ++ + } +-- +2.24.1 + diff --git a/0003-Editing-pass.patch b/0003-Editing-pass.patch new file mode 100644 index 00000000000..8507dffbc10 --- /dev/null +++ b/0003-Editing-pass.patch @@ -0,0 +1,23196 @@ +From db91a88e63fc810ca52e75bfc13b09a14a94b0ef Mon Sep 17 00:00:00 2001 +From: Jay Bryant +Date: Wed, 21 Apr 2021 16:01:26 -0500 +Subject: [PATCH 3/3] Editing pass + +I went through everything to get it to fit with Spring's docuemntation standard. +Lots of small changes for punctuation, grammar, usage, voice, and so on. +Also added some links, mostly to the API Javadoc. +--- + .../authentication/password-storage.adoc | 165 +- + .../about/authentication/supported.adoc | 4 +- + .../_includes/about/exploits/csrf.adoc | 188 +- + .../_includes/about/exploits/headers.adoc | 218 +- + .../_includes/about/exploits/http.adoc | 20 +- + .../_includes/about/exploits/index.adoc | 2 +- + .../asciidoc/_includes/about/features.adoc | 1 + + .../about/getting-spring-security.adoc | 60 +- + .../asciidoc/_includes/about/modules.adoc | 30 +- + .../_includes/reactive/exploits/csrf.adoc | 125 +- + .../_includes/reactive/exploits/headers.adoc | 69 +- + .../_includes/reactive/exploits/http.adoc | 14 +- + .../asciidoc/_includes/reactive/method.adoc | 13 +- + .../reactive/oauth2/access-token.adoc | 11 +- + .../_includes/reactive/oauth2/login.adoc | 49 +- + .../reactive/oauth2/resource-server.adoc | 380 +-- + .../registered-oauth2-authorized-client.adoc | 23 +- + .../asciidoc/_includes/reactive/rsocket.adoc | 115 +- + .../asciidoc/_includes/reactive/test.adoc | 292 ++- + .../_includes/reactive/webclient.adoc | 34 +- + .../asciidoc/_includes/reactive/webflux.adoc | 37 +- + .../asciidoc/_includes/reactive/x509.adoc | 15 +- + .../servlet/appendix/database-schema.adoc | 85 +- + .../_includes/servlet/appendix/faq.adoc | 483 ++-- + .../_includes/servlet/appendix/index.adoc | 2 + + .../_includes/servlet/appendix/namespace.adoc | 2052 +++++++++-------- + .../architecture/delegating-filter-proxy.adoc | 16 +- + .../exception-translation-filter.adoc | 22 +- + .../architecture/filter-chain-proxy.adoc | 2 + + .../servlet/architecture/filters.adoc | 20 +- + .../_includes/servlet/architecture/index.adoc | 4 +- + .../architecture/security-filter-chain.adoc | 40 +- + .../architecture/security-filters.adoc | 62 +- + .../servlet/authentication/anonymous.adoc | 74 +- + ...ract-authentication-processing-filter.adoc | 20 +- + .../authentication-entry-point.adoc | 10 +- + .../architecture/authentication-manager.adoc | 4 +- + .../architecture/authentication-provider.adoc | 4 +- + .../architecture/authentication.adoc | 16 +- + .../architecture/granted-authority.adoc | 18 +- + .../architecture/provider-manager.adoc | 26 +- + .../architecture/security-context-holder.adoc | 34 +- + .../_includes/servlet/authentication/cas.adoc | 286 +-- + .../servlet/authentication/events.adoc | 14 +- + .../servlet/authentication/index.adoc | 44 +- + .../servlet/authentication/jaas.adoc | 92 +- + .../servlet/authentication/logout.adoc | 65 +- + .../servlet/authentication/openid.adoc | 40 +- + .../servlet/authentication/preauth.adoc | 88 +- + .../servlet/authentication/rememberme.adoc | 75 +- + .../servlet/authentication/runas.adoc | 38 +- + .../authentication/session-management.adoc | 161 +- + .../servlet/authentication/unpwd/basic.adoc | 43 +- + .../unpwd/dao-authentication-provider.adoc | 12 +- + .../servlet/authentication/unpwd/digest.adoc | 20 +- + .../servlet/authentication/unpwd/form.adoc | 91 +- + .../authentication/unpwd/in-memory.adoc | 15 +- + .../servlet/authentication/unpwd/index.adoc | 10 +- + .../servlet/authentication/unpwd/jdbc.adoc | 30 +- + .../servlet/authentication/unpwd/ldap.adoc | 100 +- + .../unpwd/password-encoder.adoc | 4 +- + .../unpwd/user-details-service.adoc | 4 +- + .../servlet/authentication/x509.adoc | 53 +- + .../_includes/servlet/authorization/acls.adoc | 197 +- + .../servlet/authorization/architecture.adoc | 145 +- + .../authorization/authorize-requests.adoc | 45 +- + .../authorization/expression-based.adoc | 212 +- + .../servlet/authorization/index.adoc | 7 +- + .../authorization/method-security.adoc | 87 +- + .../servlet/authorization/secure-objects.adoc | 55 +- + .../_includes/servlet/crypto/index.adoc | 80 +- + .../_includes/servlet/exploits/csrf.adoc | 156 +- + .../_includes/servlet/exploits/firewall.adoc | 90 +- + .../_includes/servlet/exploits/headers.adoc | 82 +- + .../_includes/servlet/exploits/http.adoc | 10 +- + .../_includes/servlet/exploits/index.adoc | 2 + + .../_includes/servlet/hello/index.adoc | 12 +- + .../servlet/integrations/concurrency.adoc | 116 +- + .../_includes/servlet/integrations/cors.adoc | 20 +- + .../_includes/servlet/integrations/data.adoc | 19 +- + .../_includes/servlet/integrations/index.adoc | 2 + + .../servlet/integrations/jackson.adoc | 14 +- + .../servlet/integrations/jsp-taglibs.adoc | 94 +- + .../servlet/integrations/localization.adoc | 32 +- + .../_includes/servlet/integrations/mvc.adoc | 153 +- + .../servlet/integrations/servlet-api.adoc | 100 +- + .../servlet/integrations/websocket.adoc | 204 +- + .../servlet/java-configuration/index.adoc | 139 +- + .../servlet/kotlin-configuration/index.adoc | 39 +- + .../_includes/servlet/namespace/index.adoc | 216 +- + .../_includes/servlet/oauth2/index.adoc | 2 + + .../servlet/oauth2/oauth2-client.adoc | 334 ++- + .../servlet/oauth2/oauth2-login.adoc | 172 +- + .../servlet/oauth2/oauth2-resourceserver.adoc | 529 ++--- + .../_includes/servlet/saml2/index.adoc | 5 +- + .../_includes/servlet/saml2/saml2-login.adoc | 405 ++-- + .../_includes/servlet/test/index.adoc | 5 +- + .../_includes/servlet/test/method.adoc | 177 +- + .../_includes/servlet/test/mockmvc.adoc | 488 ++-- + docs/manual/src/docs/asciidoc/index.adoc | 7 +- + 100 files changed, 5530 insertions(+), 5066 deletions(-) + +diff --git a/docs/manual/src/docs/asciidoc/_includes/about/authentication/password-storage.adoc b/docs/manual/src/docs/asciidoc/_includes/about/authentication/password-storage.adoc +index 7770eb6b5a..a0cec811ed 100644 +--- a/docs/manual/src/docs/asciidoc/_includes/about/authentication/password-storage.adoc ++++ b/docs/manual/src/docs/asciidoc/_includes/about/authentication/password-storage.adoc +@@ -1,70 +1,69 @@ + [[authentication-password-storage]] + = Password Storage + +-Spring Security's `PasswordEncoder` interface is used to perform a one way transformation of a password to allow the password to be stored securely. +-Given `PasswordEncoder` is a one way transformation, it is not intended when the password transformation needs to be two way (i.e. storing credentials used to authenticate to a database). +-Typically `PasswordEncoder` is used for storing a password that needs to be compared to a user provided password at the time of authentication. ++Spring Security's `PasswordEncoder` interface is used to perform a one-way transformation of a password to let the password be stored securely. ++Given `PasswordEncoder` is a one-way transformation, it is not useful when the password transformation needs to be two-way (such as storing credentials used to authenticate to a database). ++Typically, `PasswordEncoder` is used for storing a password that needs to be compared to a user-provided password at the time of authentication. + + [[authentication-password-storage-history]] + == Password Storage History + +-Throughout the years the standard mechanism for storing passwords has evolved. +-In the beginning passwords were stored in plain text. ++Throughout the years, the standard mechanism for storing passwords has evolved. ++In the beginning, passwords were stored in plain text. + The passwords were assumed to be safe because the data store the passwords were saved in required credentials to access it. +-However, malicious users were able to find ways to get large "data dumps" of usernames and passwords using attacks like SQL Injection. +-As more and more user credentials became public security experts realized we needed to do more to protect users' passwords. ++However, malicious users were able to find ways to get large "`data dumps`" of usernames and passwords by using attacks such as SQL Injection. ++As more and more user credentials became public, security experts realized that we needed to do more to protect users' passwords. + +-Developers were then encouraged to store passwords after running them through a one way hash such as SHA-256. ++Developers were then encouraged to store passwords after running them through a one way hash, such as SHA-256. + When a user tried to authenticate, the hashed password would be compared to the hash of the password that they typed. +-This meant that the system only needed to store the one way hash of the password. +-If a breach occurred, then only the one way hashes of the passwords were exposed. +-Since the hashes were one way and it was computationally difficult to guess the passwords given the hash, it would not be worth the effort to figure out each password in the system. +-To defeat this new system malicious users decided to create lookup tables known as https://en.wikipedia.org/wiki/Rainbow_table[Rainbow Tables]. ++This meant that the system only needed to store the one-way hash of the password. ++If a breach occurred, only the one-way hashes of the passwords were exposed. ++Since the hashes were one-way and it was computationally difficult to guess the passwords given the hash, it would not be worth the effort to figure out each password in the system. ++To defeat this new system, malicious users decided to create lookup tables known as https://en.wikipedia.org/wiki/Rainbow_table[Rainbow Tables]. + Rather than doing the work of guessing each password every time, they computed the password once and stored it in a lookup table. + + To mitigate the effectiveness of Rainbow Tables, developers were encouraged to use salted passwords. +-Instead of using just the password as input to the hash function, random bytes (known as salt) would be generated for every users' password. +-The salt and the user's password would be ran through the hash function which produced a unique hash. ++Instead of using just the password as input to the hash function, random bytes (known as salt) would be generated for every user's password. ++The salt and the user's password would be run through the hash function to produce a unique hash. + The salt would be stored alongside the user's password in clear text. +-Then when a user tried to authenticate, the hashed password would be compared to the hash of the stored salt and the password that they typed. +-The unique salt meant that Rainbow Tables were no longer effective because the hash was different for every salt and password combination. ++Then, when a user tried to authenticate, the hashed password would be compared to the hash of the stored salt and the password that they typed. ++The unique salt meant that Rainbow Tables were no longer effective, because the hash was different for every salt and password combination. + +-In modern times we realize that cryptographic hashes (like SHA-256) are no longer secure. ++In modern times, we realize that cryptographic hashes (like SHA-256) are no longer secure. + The reason is that with modern hardware we can perform billions of hash calculations a second. + This means that we can crack each password individually with ease. + + Developers are now encouraged to leverage adaptive one-way functions to store a password. +-Validation of passwords with adaptive one-way functions are intentionally resource (i.e. CPU, memory, etc) intensive. +-An adaptive one-way function allows configuring a "work factor" which can grow as hardware gets better. +-It is recommended that the "work factor" be tuned to take about 1 second to verify a password on your system. +-This trade off is to make it difficult for attackers to crack the password, but not so costly it puts excessive burden on your own system. +-Spring Security has attempted to provide a good starting point for the "work factor", but users are encouraged to customize the "work factor" for their own system since the performance will vary drastically from system to system. ++Validation of passwords with adaptive one-way functions are intentionally resource-intensive (they intentionally use a lot of CPU, memory, or other resources). ++An adaptive one-way function allows configuring a "`work factor`" that can grow as hardware gets better. ++We recommend that the "`work factor`" be tuned to take about one second to verify a password on your system. ++This trade off is to make it difficult for attackers to crack the password, but not so costly that it puts excessive burden on your own system or irritates users. ++Spring Security has attempted to provide a good starting point for the "`work factor`", but we encourage users to customize the "`work factor`" for their own system, since the performance varies drastically from system to system. + Examples of adaptive one-way functions that should be used include <>, <>, <>, and <>. + +-Because adaptive one-way functions are intentionally resource intensive, validating a username and password for every request will degrade performance of an application significantly. +-There is nothing Spring Security (or any other library) can do to speed up the validation of the password since security is gained by making the validation resource intensive. +-Users are encouraged to exchange the long term credentials (i.e. username and password) for a short term credential (i.e. session, OAuth Token, etc). ++Because adaptive one-way functions are intentionally resource intensive, validating a username and password for every request can significantly degrade the performance of an application. ++There is nothing Spring Security (or any other library) can do to speed up the validation of the password, since security is gained by making the validation resource intensive. ++Users are encouraged to exchange the long term credentials (that is, username and password) for a short term credential (such as a session, and OAuth Token, and so on). + The short term credential can be validated quickly without any loss in security. + +- + [[authentication-password-storage-dpe]] + == DelegatingPasswordEncoder + +-Prior to Spring Security 5.0 the default `PasswordEncoder` was `NoOpPasswordEncoder` which required plain text passwords. +-Based upon the <> section you might expect that the default `PasswordEncoder` is now something like `BCryptPasswordEncoder`. ++Prior to Spring Security 5.0, the default `PasswordEncoder` was `NoOpPasswordEncoder`, which required plain-text passwords. ++Based on the <> section, you might expect that the default `PasswordEncoder` would now be something like `BCryptPasswordEncoder`. + However, this ignores three real world problems: + +-- There are many applications using old password encodings that cannot easily migrate ++- Many applications use old password encodings that cannot easily migrate. + - The best practice for password storage will change again. +-- As a framework Spring Security cannot make breaking changes frequently ++- As a framework, Spring Security cannot make breaking changes frequently. + +-Instead Spring Security introduces `DelegatingPasswordEncoder` which solves all of the problems by: ++Instead Spring Security introduces `DelegatingPasswordEncoder`, which solves all of the problems by: + +-- Ensuring that passwords are encoded using the current password storage recommendations ++- Ensuring that passwords are encoded by using the current password storage recommendations + - Allowing for validating passwords in modern and legacy formats + - Allowing for upgrading the encoding in the future + +-You can easily construct an instance of `DelegatingPasswordEncoder` using `PasswordEncoderFactories`. ++You can easily construct an instance of `DelegatingPasswordEncoder` by using `PasswordEncoderFactories`: + + .Create Default DelegatingPasswordEncoder + ==== +@@ -82,7 +81,7 @@ val passwordEncoder: PasswordEncoder = PasswordEncoderFactories.createDelegating + ---- + ==== + +-Alternatively, you may create your own custom instance. For example: ++Alternatively, you can create your own custom instance: + + .Create Custom DelegatingPasswordEncoder + ==== +@@ -129,11 +128,11 @@ The general format for a password is: + ---- + ==== + +-Such that `id` is an identifier used to look up which `PasswordEncoder` should be used and `encodedPassword` is the original encoded password for the selected `PasswordEncoder`. +-The `id` must be at the beginning of the password, start with `{` and end with `}`. +-If the `id` cannot be found, the `id` will be null. +-For example, the following might be a list of passwords encoded using different `id`. +-All of the original passwords are "password". ++`id` is an identifier that is used to look up which `PasswordEncoder` should be used and `encodedPassword` is the original encoded password for the selected `PasswordEncoder`. ++The `id` must be at the beginning of the password, start with `{`, and end with `}`. ++If the `id` cannot be found, the `id` is set to null. ++For example, the following might be a list of passwords encoded using different `id` values. ++All of the original passwords are `password`. + + .DelegatingPasswordEncoder Encoded Passwords Example + ==== +@@ -147,16 +146,16 @@ All of the original passwords are "password". + ---- + ==== + +-<1> The first password would have a `PasswordEncoder` id of `bcrypt` and encodedPassword of `$2a$10$dXJ3SW6G7P50lGmMkkmwe.20cQQubK3.HZWzG3YB1tlRy.fqvM/BG`. +-When matching it would delegate to `BCryptPasswordEncoder` +-<2> The second password would have a `PasswordEncoder` id of `noop` and encodedPassword of `password`. +-When matching it would delegate to `NoOpPasswordEncoder` +-<3> The third password would have a `PasswordEncoder` id of `pbkdf2` and encodedPassword of `5d923b44a6d129f3ddf3e3c8d29412723dcbde72445e8ef6bf3b508fbf17fa4ed4d6b99ca763d8dc`. +-When matching it would delegate to `Pbkdf2PasswordEncoder` +-<4> The fourth password would have a `PasswordEncoder` id of `scrypt` and encodedPassword of `$e0801$8bWJaSu2IKSn9Z9kM+TPXfOc/9bdYSrN1oD9qfVThWEwdRTnO7re7Ei+fUZRJ68k9lTyuTeUp4of4g24hHnazw==$OAOec05+bXxvuu/1qZ6NUR+xQYvYv7BeL1QxwRpY5Pc=` +-When matching it would delegate to `SCryptPasswordEncoder` +-<5> The final password would have a `PasswordEncoder` id of `sha256` and encodedPassword of `97cde38028ad898ebc02e690819fa220e88c62e0699403e94fff291cfffaf8410849f27605abcbc0`. +-When matching it would delegate to `StandardPasswordEncoder` ++<1> The first password has a `PasswordEncoder` id of `bcrypt` and an encoded password value of `$2a$10$dXJ3SW6G7P50lGmMkkmwe.20cQQubK3.HZWzG3YB1tlRy.fqvM/BG`. ++When matching, it would delegate to `BCryptPasswordEncoder` ++<2> The second password has a `PasswordEncoder` id of `noop` and encoded password value of `password`. ++When matching, it would delegate to `NoOpPasswordEncoder` ++<3> The third password has a `PasswordEncoder` id of `pbkdf2` and encoded password value of `5d923b44a6d129f3ddf3e3c8d29412723dcbde72445e8ef6bf3b508fbf17fa4ed4d6b99ca763d8dc`. ++When matching, it would delegate to `Pbkdf2PasswordEncoder` ++<4> The fourth password has a `PasswordEncoder` id of `scrypt` and encoded password value of `$e0801$8bWJaSu2IKSn9Z9kM+TPXfOc/9bdYSrN1oD9qfVThWEwdRTnO7re7Ei+fUZRJ68k9lTyuTeUp4of4g24hHnazw==$OAOec05+bXxvuu/1qZ6NUR+xQYvYv7BeL1QxwRpY5Pc=` ++When matching, it would delegate to `SCryptPasswordEncoder` ++<5> The final password has a `PasswordEncoder` id of `sha256` and encoded password value of `97cde38028ad898ebc02e690819fa220e88c62e0699403e94fff291cfffaf8410849f27605abcbc0`. ++When matching, it would delegate to `StandardPasswordEncoder` + + [NOTE] + ==== +@@ -169,9 +168,9 @@ For example, BCrypt passwords often start with `$2a$`. + [[authentication-password-storage-dpe-encoding]] + === Password Encoding + +-The `idForEncode` passed into the constructor determines which `PasswordEncoder` will be used for encoding passwords. +-In the `DelegatingPasswordEncoder` we constructed above, that means that the result of encoding `password` would be delegated to `BCryptPasswordEncoder` and be prefixed with `+{bcrypt}+`. +-The end result would look like: ++The `idForEncode` passed into the constructor determines which `PasswordEncoder` is used for encoding passwords. ++In the `DelegatingPasswordEncoder` we constructed earlier, that means that the result of encoding `password` is delegated to `BCryptPasswordEncoder` and be prefixed with `+{bcrypt}+`. ++The end result looks like the following example: + + .DelegatingPasswordEncoder Encode Example + ==== +@@ -184,15 +183,15 @@ The end result would look like: + [[authentication-password-storage-dpe-matching]] + === Password Matching + +-Matching is done based upon the `+{id}+` and the mapping of the `id` to the `PasswordEncoder` provided in the constructor. ++Matching is based upon the `+{id}+` and the mapping of the `id` to the `PasswordEncoder` provided in the constructor. + Our example in <> provides a working example of how this is done. +-By default, the result of invoking `matches(CharSequence, String)` with a password and an `id` that is not mapped (including a null id) will result in an `IllegalArgumentException`. +-This behavior can be customized using `DelegatingPasswordEncoder.setDefaultPasswordEncoderForMatches(PasswordEncoder)`. ++By default, the result of invoking `matches(CharSequence, String)` with a password and an `id` that is not mapped (including a null id) results in an `IllegalArgumentException`. ++This behavior can be customized by using `DelegatingPasswordEncoder.setDefaultPasswordEncoderForMatches(PasswordEncoder)`. + +-By using the `id` we can match on any password encoding, but encode passwords using the most modern password encoding. +-This is important, because unlike encryption, password hashes are designed so that there is no simple way to recover the plaintext. +-Since there is no way to recover the plaintext, it makes it difficult to migrate the passwords. +-While it is simple for users to migrate `NoOpPasswordEncoder`, we chose to include it by default to make it simple for the getting started experience. ++By using the `id`, we can match on any password encoding but encode passwords by using the most modern password encoding. ++This is important, because unlike encryption, password hashes are designed so that there is no simple way to recover the plain text. ++Since there is no way to recover the plain text, it is difficult to migrate the passwords. ++While it is simple for users to migrate `NoOpPasswordEncoder`, we chose to include it by default to make it simple for the getting-started experience. + + [[authentication-password-storage-dep-getting-started]] + === Getting Started Experience +@@ -227,7 +226,7 @@ println(user.password) + ---- + ==== + +-If you are creating multiple users, you can also reuse the builder. ++If you are creating multiple users, you can also reuse the builder: + + .withDefaultPasswordEncoder Reusing the Builder + ==== +@@ -273,7 +272,7 @@ For production, you should <>: ++For example, the following example encodes the password of `password` for use with <>: + + .Spring Boot CLI encodepassword Example + ==== +@@ -287,44 +286,48 @@ spring encodepassword password + [[authentication-password-storage-dpe-troubleshoot]] + === Troubleshooting + +-The following error occurs when one of the passwords that are stored has no id as described in <>. ++The following error occurs when one of the passwords that are stored has no `id`, as described in <>. + ++==== + ---- + java.lang.IllegalArgumentException: There is no PasswordEncoder mapped for the id "null" + at org.springframework.security.crypto.password.DelegatingPasswordEncoder$UnmappedIdPasswordEncoder.matches(DelegatingPasswordEncoder.java:233) + at org.springframework.security.crypto.password.DelegatingPasswordEncoder.matches(DelegatingPasswordEncoder.java:196) + ---- ++==== + +-The easiest way to resolve the error is to switch to explicitly provide the `PasswordEncoder` that you passwords are encoded with. + The easiest way to resolve it is to figure out how your passwords are currently being stored and explicitly provide the correct `PasswordEncoder`. + +-If you are migrating from Spring Security 4.2.x you can revert to the previous behavior by <>. ++If you are migrating from Spring Security 4.2.x, you can revert to the previous behavior by <>. + +-Alternatively, you can prefix all of your passwords with the correct id and continue to use `DelegatingPasswordEncoder`. ++Alternatively, you can prefix all of your passwords with the correct `id` and continue to use `DelegatingPasswordEncoder`. + For example, if you are using BCrypt, you would migrate your password from something like: + ++==== + ---- + $2a$10$dXJ3SW6G7P50lGmMkkmwe.20cQQubK3.HZWzG3YB1tlRy.fqvM/BG + ---- ++==== + + to + +- ++==== + [source,attrs="-attributes"] + ---- + {bcrypt}$2a$10$dXJ3SW6G7P50lGmMkkmwe.20cQQubK3.HZWzG3YB1tlRy.fqvM/BG + ---- ++==== + +-For a complete listing of the mappings refer to the Javadoc on +-https://docs.spring.io/spring-security/site/docs/5.0.x/api/org/springframework/security/crypto/factory/PasswordEncoderFactories.html[PasswordEncoderFactories]. ++For a complete listing of the mappings, see the Javadoc for ++https://docs.spring.io/spring-security/site/docs/5.0.x/api/org/springframework/security/crypto/factory/PasswordEncoderFactories.html[`PasswordEncoderFactories`]. + + [[authentication-password-storage-bcrypt]] + == BCryptPasswordEncoder + + The `BCryptPasswordEncoder` implementation uses the widely supported https://en.wikipedia.org/wiki/Bcrypt[bcrypt] algorithm to hash the passwords. +-In order to make it more resistent to password cracking, bcrypt is deliberately slow. ++To make it more resistant to password cracking, bcrypt is deliberately slow. + Like other adaptive one-way functions, it should be tuned to take about 1 second to verify a password on your system. +-The default implementation of `BCryptPasswordEncoder` uses strength 10 as mentioned in the Javadoc of https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/crypto/bcrypt/BCryptPasswordEncoder.html[BCryptPasswordEncoder]. You are encouraged to ++The default implementation of `BCryptPasswordEncoder` uses strength 10 as mentioned in the Javadoc of https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/crypto/bcrypt/BCryptPasswordEncoder.html[`BCryptPasswordEncoder`]. You are encouraged to + tune and test the strength parameter on your own system so that it takes roughly 1 second to verify a password. + + .BCryptPasswordEncoder +@@ -353,7 +356,7 @@ assertTrue(encoder.matches("myPassword", result)) + + The `Argon2PasswordEncoder` implementation uses the https://en.wikipedia.org/wiki/Argon2[Argon2] algorithm to hash the passwords. + Argon2 is the winner of the https://en.wikipedia.org/wiki/Password_Hashing_Competition[Password Hashing Competition]. +-In order to defeat password cracking on custom hardware, Argon2 is a deliberately slow algorithm that requires large amounts of memory. ++To defeat password cracking on custom hardware, Argon2 is a deliberately slow algorithm that requires large amounts of memory. + Like other adaptive one-way functions, it should be tuned to take about 1 second to verify a password on your system. + The current implementation of the `Argon2PasswordEncoder` requires BouncyCastle. + +@@ -382,7 +385,7 @@ assertTrue(encoder.matches("myPassword", result)) + == Pbkdf2PasswordEncoder + + The `Pbkdf2PasswordEncoder` implementation uses the https://en.wikipedia.org/wiki/PBKDF2[PBKDF2] algorithm to hash the passwords. +-In order to defeat password cracking PBKDF2 is a deliberately slow algorithm. ++To defeat password cracking, PBKDF2 is a deliberately slow algorithm. + Like other adaptive one-way functions, it should be tuned to take about 1 second to verify a password on your system. + This algorithm is a good choice when FIPS certification is required. + +@@ -410,8 +413,8 @@ assertTrue(encoder.matches("myPassword", result)) + [[authentication-password-storage-scrypt]] + == SCryptPasswordEncoder + +-The `SCryptPasswordEncoder` implementation uses https://en.wikipedia.org/wiki/Scrypt[scrypt] algorithm to hash the passwords. +-In order to defeat password cracking on custom hardware scrypt is a deliberately slow algorithm that requires large amounts of memory. ++The `SCryptPasswordEncoder` implementation uses the https://en.wikipedia.org/wiki/Scrypt[scrypt] algorithm to hash the passwords. ++To defeat password cracking on custom hardware, scrypt is a deliberately slow algorithm that requires large amounts of memory. + Like other adaptive one-way functions, it should be tuned to take about 1 second to verify a password on your system. + + .SCryptPasswordEncoder +@@ -436,20 +439,19 @@ assertTrue(encoder.matches("myPassword", result)) + ==== + + [[authentication-password-storage-other]] +-== Other PasswordEncoders ++== Other Password Encoders + + There are a significant number of other `PasswordEncoder` implementations that exist entirely for backward compatibility. + They are all deprecated to indicate that they are no longer considered secure. +-However, there are no plans to remove them since it is difficult to migrate existing legacy systems. ++However, there are no plans to remove them, since it is difficult to migrate existing legacy systems. + + [[authentication-password-storage-configuration]] + == Password Storage Configuration + + Spring Security uses <> by default. +-However, this can be customized by exposing a `PasswordEncoder` as a Spring bean. +- ++However, you can customize this by exposing a `PasswordEncoder` as a Spring bean. + +-If you are migrating from Spring Security 4.2.x you can revert to the previous behavior by exposing a `NoOpPasswordEncoder` bean. ++If you are migrating from Spring Security 4.2.x, you can revert to the previous behavior by exposing a `NoOpPasswordEncoder` bean. + + [WARNING] + ==== +@@ -485,7 +487,4 @@ fun passwordEncoder(): PasswordEncoder { + ---- + ==== + +-[NOTE] +-==== +-XML Configuration requires the `NoOpPasswordEncoder` bean name to be `passwordEncoder`. +-==== ++NOTE: XML Configuration requires the `NoOpPasswordEncoder` bean name to be `passwordEncoder`. +diff --git a/docs/manual/src/docs/asciidoc/_includes/about/authentication/supported.adoc b/docs/manual/src/docs/asciidoc/_includes/about/authentication/supported.adoc +index 85bd943456..67c03c68fe 100644 +--- a/docs/manual/src/docs/asciidoc/_includes/about/authentication/supported.adoc ++++ b/docs/manual/src/docs/asciidoc/_includes/about/authentication/supported.adoc +@@ -1,5 +1,5 @@ + [[authentication-support]] + = Authentication Support + +-Spring Security provides built in support for authenticating users. +-Refer to the sections on authentication for <> and WebFlux for details on what is supported for each stack. ++Spring Security provides built-in support for authenticating users. ++See the sections on authentication for <> and <> for details on what is supported for each stack. +diff --git a/docs/manual/src/docs/asciidoc/_includes/about/exploits/csrf.adoc b/docs/manual/src/docs/asciidoc/_includes/about/exploits/csrf.adoc +index 0a7a98b561..67728e135b 100644 +--- a/docs/manual/src/docs/asciidoc/_includes/about/exploits/csrf.adoc ++++ b/docs/manual/src/docs/asciidoc/_includes/about/exploits/csrf.adoc +@@ -1,21 +1,15 @@ +-// FIXME: Add links to Servlet and WebFlux support +- + [[csrf]] + = Cross Site Request Forgery (CSRF) + + Spring provides comprehensive support for protecting against https://en.wikipedia.org/wiki/Cross-site_request_forgery[Cross Site Request Forgery (CSRF)] attacks. +-In the following sections we will explore: ++In the following sections, we explore: + + * <> + * <> + * <> + +-// FIXME: Add WebFlux csrf documentation (the link below is broken) +-[NOTE] +-==== +-This portion of the documentation discusses the general topic of CSRF protection. +-Refer to the relevant sections for specific information on CSRF protection for <> and <> based applications. +-==== ++NOTE: This portion of the documentation discusses the general topic of CSRF protection. ++See the relevant sections for specific information on CSRF protection for <>- and <>-based applications. + + [[csrf-explained]] + == What is a CSRF Attack? +@@ -85,52 +79,49 @@ You like to win money, so you click on the submit button. + In the process, you have unintentionally transferred $100 to a malicious user. + This happens because, while the evil website cannot see your cookies, the cookies associated with your bank are still sent along with the request. + +-Worst yet, this whole process could have been automated using JavaScript. +-This means you didn't even need to click on the button. ++Worse yet, this whole process could have been automated by using JavaScript. ++This means you did not even need to click on the button. + Furthermore, it could just as easily happen when visiting an honest site that is a victim of a https://www.owasp.org/index.php/Cross-site_Scripting_(XSS)[XSS attack]. + So how do we protect our users from such attacks? + + [[csrf-protection]] + == Protecting Against CSRF Attacks + The reason that a CSRF attack is possible is that the HTTP request from the victim's website and the request from the attacker's website are exactly the same. +-This means there is no way to reject requests coming from the evil website and allow requests coming from the bank's website. +-To protect against CSRF attacks we need to ensure there is something in the request that the evil site is unable to provide so we can differentiate the two requests. ++This means there is no way to reject requests coming from the evil website and allow only requests coming from the bank's website. ++To protect against CSRF attacks, we need to ensure there is something in the request that the evil site is unable to provide so we can differentiate the two requests. + + Spring provides two mechanisms to protect against CSRF attacks: + + * The <> + * Specifying the <> on your session cookie + +-[NOTE] +-==== +-Both protections require that <> +-==== ++NOTE: Both protections require that <>. + + [[csrf-protection-idempotent]] + === Safe Methods Must be Idempotent + +-In order for <> against CSRF to work, the application must ensure that https://tools.ietf.org/html/rfc7231#section-4.2.1["safe" HTTP methods are idempotent]. +-This means that requests with the HTTP method `GET`, `HEAD`, `OPTIONS`, and `TRACE` should not change the state of the application. ++For <> against CSRF to work, the application must ensure that https://tools.ietf.org/html/rfc7231#section-4.2.1["safe" HTTP methods are idempotent]. ++This means that requests with the HTTP `GET`, `HEAD`, `OPTIONS`, and `TRACE` methods should not change the state of the application. + + [[csrf-protection-stp]] + === Synchronizer Token Pattern + The predominant and most comprehensive way to protect against CSRF attacks is to use the https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)_Prevention_Cheat_Sheet#General_Recommendation:_Synchronizer_Token_Pattern[Synchronizer Token Pattern]. +-This solution is to ensure that each HTTP request requires, in addition to our session cookie, a secure random generated value called a CSRF token must be present in the HTTP request. ++This solution is to ensure that each HTTP request requires, in addition to our session cookie, a secure random generated value called a CSRF token be present in the HTTP request. + + When an HTTP request is submitted, the server must look up the expected CSRF token and compare it against the actual CSRF token in the HTTP request. + If the values do not match, the HTTP request should be rejected. + + The key to this working is that the actual CSRF token should be in a part of the HTTP request that is not automatically included by the browser. +-For example, requiring the actual CSRF token in an HTTP parameter or an HTTP header will protect against CSRF attacks. ++For example, requiring the actual CSRF token in an HTTP parameter or an HTTP header protects against CSRF attacks. + Requiring the actual CSRF token in a cookie does not work because cookies are automatically included in the HTTP request by the browser. + +-We can relax the expectations to only require the actual CSRF token for each HTTP request that updates state of the application. ++We can relax the expectations to require only the actual CSRF token for each HTTP request that updates the state of the application. + For that to work, our application must ensure that <>. +-This improves usability since we want to allow linking to our website using links from external sites. +-Additionally, we do not want to include the random token in HTTP GET as this can cause the tokens to be leaked. ++This improves usability, since we want to allow linking to our website from external sites. ++Additionally, we do not want to include the random token in HTTP GET, as this can cause the tokens to be leaked. + +-Let's take a look at how <> would change when using the Synchronizer Token Pattern. +-Assume the actual CSRF token is required to be in an HTTP parameter named `_csrf`. ++Consider how <> would change when we use the Synchronizer Token Pattern. ++Assume that the actual CSRF token is required to be in an HTTP parameter named `_csrf`. + Our application's transfer form would look like: + + .Synchronizer Token Form +@@ -173,22 +164,19 @@ amount=100.00&routingNumber=1234&account=9876&_csrf=4bfd1575-3ad1-4d21-96c7-4ef2 + ==== + + +-You will notice that the HTTP request now contains the `_csrf` parameter with a secure random value. +-The evil website will not be able to provide the correct value for the `_csrf` parameter (which must be explicitly provided on the evil website) and the transfer will fail when the server compares the actual CSRF token to the expected CSRF token. ++Notice that the HTTP request now contains the `_csrf` parameter with a secure random value. ++The evil website cannot provide the correct value for the `_csrf` parameter (which must be explicitly provided on the evil website), and the transfer fails when the server compares the actual CSRF token to the expected CSRF token. + + [[csrf-protection-ssa]] + === SameSite Attribute + An emerging way to protect against <> is to specify the https://tools.ietf.org/html/draft-west-first-party-cookies[SameSite Attribute] on cookies. + A server can specify the `SameSite` attribute when setting a cookie to indicate that the cookie should not be sent when coming from external sites. + +-[NOTE] +-==== +-Spring Security does not directly control the creation of the session cookie, so it does not provide support for the SameSite attribute. +-https://spring.io/projects/spring-session[Spring Session] provides support for the `SameSite` attribute in servlet based applications. +-Spring Framework's https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/server/session/CookieWebSessionIdResolver.html[CookieWebSessionIdResolver] provides out of the box support for the `SameSite` attribute in WebFlux based applications. +-==== ++NOTE: Spring Security does not directly control the creation of the session cookie, so it does not provide support for the SameSite attribute. ++https://spring.io/projects/spring-session[Spring Session] provides support for the `SameSite` attribute in servlet-based applications. ++Spring Framework's https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/server/session/CookieWebSessionIdResolver.html[`CookieWebSessionIdResolver`] provides support for the `SameSite` attribute in WebFlux-based applications. + +-An example, HTTP response header with the `SameSite` attribute might look like: ++An example of an HTTP response header with the `SameSite` attribute might look like: + + .SameSite HTTP response + ==== +@@ -200,49 +188,45 @@ Set-Cookie: JSESSIONID=randomid; Domain=bank.example.com; Secure; HttpOnly; Same + + Valid values for the `SameSite` attribute are: + +-* `Strict` - when specified any request coming from the https://tools.ietf.org/html/draft-west-first-party-cookies-07#section-2.1[same-site] will include the cookie. +-Otherwise, the cookie will not be included in the HTTP request. +-* `Lax` - when specified cookies will be sent when coming from the https://tools.ietf.org/html/draft-west-first-party-cookies-07#section-2.1[same-site] or when the request comes from top-level navigations and the <>. +-Otherwise, the cookie will not be included in the HTTP request. ++* `Strict`: When specified, any request coming from the https://tools.ietf.org/html/draft-west-first-party-cookies-07#section-2.1[same-site] includes the cookie. ++Otherwise, the cookie is not included in the HTTP request. ++* `Lax`: When specified, cookies are sent when coming from the https://tools.ietf.org/html/draft-west-first-party-cookies-07#section-2.1[same-site] or when the request comes from top-level navigations and the <>. ++Otherwise, the cookie is not included in the HTTP request. + +-Let's take a look at how <> could be protected using the `SameSite` attribute. ++Consider how <> could be protected using the `SameSite` attribute. + The bank application can protect against CSRF by specifying the `SameSite` attribute on the session cookie. + +-With the `SameSite` attribute set on our session cookie, the browser will continue to send the `JSESSIONID` cookie with requests coming from the banking website. +-However, the browser will no longer send the `JSESSIONID` cookie with a transfer request coming from the evil website. ++With the `SameSite` attribute set on our session cookie, the browser continues to send the `JSESSIONID` cookie with requests coming from the banking website. ++However, the browser no longer sends the `JSESSIONID` cookie with a transfer request coming from the evil website. + Since the session is no longer present in the transfer request coming from the evil website, the application is protected from the CSRF attack. + +-There are some important https://tools.ietf.org/html/draft-west-first-party-cookies-07#section-5[considerations] that one should be aware about when using `SameSite` attribute to protect against CSRF attacks. +- ++There are some important https://tools.ietf.org/html/draft-west-first-party-cookies-07#section-5[considerations] to be aware of when using `SameSite` attribute to protect against CSRF attacks. + Setting the `SameSite` attribute to `Strict` provides a stronger defense but can confuse users. +-Consider a user that stays logged into a social media site hosted at https://social.example.com. ++Consider a user who stays logged into a social media site hosted at https://social.example.com. + The user receives an email at https://email.example.org that includes a link to the social media site. + If the user clicks on the link, they would rightfully expect to be authenticated to the social media site. +-However, if the `SameSite` attribute is `Strict` the cookie would not be sent and so the user would not be authenticated. ++However, if the `SameSite` attribute is `Strict`, the cookie would not be sent and the user would not be authenticated. + +-[NOTE] +-==== +-We could improve the protection and usability of `SameSite` protection against CSRF attacks by implementing https://github.com/spring-projects/spring-security/issues/7537[gh-7537]. +-==== ++NOTE: We could improve the protection and usability of `SameSite` protection against CSRF attacks by implementing https://github.com/spring-projects/spring-security/issues/7537[gh-7537]. + +-Another obvious consideration is that in order for the `SameSite` attribute to protect users, the browser must support the `SameSite` attribute. ++Another obvious consideration is that, in order for the `SameSite` attribute to protect users, the browser must support the `SameSite` attribute. + Most modern browsers do https://developer.mozilla.org/en-US/docs/Web/HTTP/headers/Set-Cookie#Browser_compatibility[support the SameSite attribute]. + However, older browsers that are still in use may not. + +-For this reason, it is generally recommended to use the `SameSite` attribute as a defense in depth rather than the sole protection against CSRF attacks. ++For this reason, we generally recommend using the `SameSite` attribute as a defense in depth rather than the sole protection against CSRF attacks. + + [[csrf-when]] + == When to use CSRF protection + When should you use CSRF protection? + Our recommendation is to use CSRF protection for any request that could be processed by a browser by normal users. +-If you are only creating a service that is used by non-browser clients, you will likely want to disable CSRF protection. ++If you are creating a service that is used only by non-browser clients, you likely want to disable CSRF protection. + + [[csrf-when-json]] + === CSRF protection and JSON +-A common question is "do I need to protect JSON requests made by javascript?" +-The short answer is, it depends. +-However, you must be very careful as there are CSRF exploits that can impact JSON requests. +-For example, a malicious user can create a http://blog.opensecurityresearch.com/2012/02/json-csrf-with-parameter-padding.html[CSRF with JSON using the following form]: ++A common question is "`do I need to protect JSON requests made by JavaScript?`" ++The short answer is: It depends. ++However, you must be very careful, as there are CSRF exploits that can impact JSON requests. ++For example, a malicious user can create a http://blog.opensecurityresearch.com/2012/02/json-csrf-with-parameter-padding.html[CSRF with JSON by using the following form]: + + .CSRF with JSON form + ==== +@@ -257,7 +241,7 @@ For example, a malicious user can create a http://blog.opensecurityresearch.com/ + ==== + + +-This will produce the following JSON structure ++This produces the following JSON structure + + .CSRF with JSON request + ==== +@@ -271,8 +255,8 @@ This will produce the following JSON structure + ---- + ==== + +-If an application were not validating the Content-Type, then it would be exposed to this exploit. +-Depending on the setup, a Spring MVC application that validates the Content-Type could still be exploited by updating the URL suffix to end with `.json` as shown below: ++If an application were not validating the `Content-Type` header, it would be exposed to this exploit. ++Depending on the setup, a Spring MVC application that validates the Content-Type could still be exploited by updating the URL suffix to end with `.json`, as follows: + + .CSRF with JSON Spring MVC form + ==== +@@ -289,15 +273,15 @@ Depending on the setup, a Spring MVC application that validates the Content-Type + [[csrf-when-stateless]] + === CSRF and Stateless Browser Applications + What if my application is stateless? +-That doesn't necessarily mean you are protected. ++That does not necessarily mean you are protected. + In fact, if a user does not need to perform any actions in the web browser for a given request, they are likely still vulnerable to CSRF attacks. + +-For example, consider an application that uses a custom cookie that contains all the state within it for authentication instead of the JSESSIONID. +-When the CSRF attack is made the custom cookie will be sent with the request in the same manner that the JSESSIONID cookie was sent in our previous example. +-This application will be vulnerable to CSRF attacks. ++For example, consider an application that uses a custom cookie that contains all the state within it for authentication (instead of the JSESSIONID). ++When the CSRF attack is made, the custom cookie is sent with the request in the same manner that the JSESSIONID cookie was sent in our previous example. ++This application is vulnerable to CSRF attacks. + + Applications that use basic authentication are also vulnerable to CSRF attacks. +-The application is vulnerable since the browser will automatically include the username and password in any requests in the same manner that the JSESSIONID cookie was sent in our previous example. ++The application is vulnerable since the browser automatically includes the username and password in any requests in the same manner that the JSESSIONID cookie was sent in our previous example. + + [[csrf-considerations]] + == CSRF Considerations +@@ -308,89 +292,87 @@ There are a few special considerations to consider when implementing protection + [[csrf-considerations-login]] + === Logging In + +-In order to protect against https://en.wikipedia.org/wiki/Cross-site_request_forgery#Forging_login_requests[forging log in requests] the log in HTTP request should be protected against CSRF attacks. +-Protecting against forging log in requests is necessary so that a malicious user cannot read a victim's sensitive information. ++To protect against https://en.wikipedia.org/wiki/Cross-site_request_forgery#Forging_login_requests[forging login requests], the login HTTP request should be protected against CSRF attacks. ++Protecting against forging login requests is necessary so that a malicious user cannot read a victim's sensitive information. + The attack is performed as follows: + +-* A malicious user performs a CSRF log in using the malicious user's credentials. ++. A malicious user performs a CSRF login with the malicious user's credentials. + The victim is now authenticated as the malicious user. +-* The malicious user then tricks the victim to visit the compromised website and enter sensitive information +-* The information is associated to the malicious user's account so the malicious user can log in with their own credentials and view the vicitim's sensitive information ++. The malicious user then tricks the victim into visiting the compromised website and entering sensitive information. ++. The information is associated to the malicious user's account so the malicious user can log in with their own credentials and view the victim's sensitive information. + +-A possible complication to ensuring log in HTTP requests are protected against CSRF attacks is that the user might experience a session timeout that causes the request to be rejected. +-A session timeout is surprising to users who do not expect to need to have a session in order to log in. ++A possible complication to ensuring login HTTP requests are protected against CSRF attacks is that the user might experience a session timeout that causes the request to be rejected. ++A session timeout is surprising to users who do not expect to need to have a session to log in. + For more information refer to <>. + + [[csrf-considerations-logout]] + === Logging Out + +-In order to protect against forging log out requests, the log out HTTP request should be protected against CSRF attacks. +-Protecting against forging log out requests is necessary so a malicious user cannot read a victim's sensitive information. +-For details on the attack refer to https://labs.detectify.com/2017/03/15/loginlogout-csrf-time-to-reconsider/[this blog post]. ++To protect against forging logout requests, the logout HTTP request should be protected against CSRF attacks. ++Protecting against forging logout requests is necessary so that a malicious user cannot read a victim's sensitive information. ++For details on the attack, see https://labs.detectify.com/2017/03/15/loginlogout-csrf-time-to-reconsider/[this blog post]. + +-A possible complication to ensuring log out HTTP requests are protected against CSRF attacks is that the user might experience a session timeout that causes the request to be rejected. +-A session timeout is surprising to users who do not expect to need to have a session in order to log out. +-For more information refer to <>. ++A possible complication to ensuring logout HTTP requests are protected against CSRF attacks is that the user might experience a session timeout that causes the request to be rejected. ++A session timeout is surprising to users who do not expect to have a session to log out. ++For more information, see <>. + + [[csrf-considerations-timeouts]] + === CSRF and Session Timeouts + More often than not, the expected CSRF token is stored in the session. +-This means that as soon as the session expires the server will not find an expected CSRF token and reject the HTTP request. +-There are a number of options to solve timeouts each of which come with trade offs. ++This means that, as soon as the session expires, the server does not find an expected CSRF token and rejects the HTTP request. ++There are a number of options (each of which come with trade offs) to solve timeouts: + + * The best way to mitigate the timeout is by using JavaScript to request a CSRF token on form submission. + The form is then updated with the CSRF token and submitted. + * Another option is to have some JavaScript that lets the user know their session is about to expire. + The user can click a button to continue and refresh the session. + * Finally, the expected CSRF token could be stored in a cookie. +-This allows the expected CSRF token to outlive the session. ++This lets the expected CSRF token outlive the session. + + +-One might ask why the expected CSRF token isn't stored in a cookie by default. ++One might ask why the expected CSRF token is not stored in a cookie by default. + This is because there are known exploits in which headers (for example, to specify the cookies) can be set by another domain. +-This is the same reason Ruby on Rails https://weblog.rubyonrails.org/2011/2/8/csrf-protection-bypass-in-ruby-on-rails/[no longer skips CSRF checks when the header X-Requested-With is present]. ++This is the same reason Ruby on Rails https://weblog.rubyonrails.org/2011/2/8/csrf-protection-bypass-in-ruby-on-rails/[no longer skips a CSRF checks when the header X-Requested-With is present]. + See http://lists.webappsec.org/pipermail/websecurity_lists.webappsec.org/2011-February/007533.html[this webappsec.org thread] for details on how to perform the exploit. + Another disadvantage is that by removing the state (that is, the timeout), you lose the ability to forcibly invalidate the token if it is compromised. + +-// FIXME: Document timeout with lengthy form expire. We do not want to automatically replay that request because it can lead to exploit ++// FIXME: Document timeout with lengthy form expire. We do not want to automatically replay that request because it can lead to an exploit. + + [[csrf-considerations-multipart]] + === Multipart (file upload) + +-Protecting multipart requests (file uploads) from CSRF attacks causes a https://en.wikipedia.org/wiki/Chicken_or_the_egg[chicken and the egg] problem. +-In order to prevent a CSRF attack from occurring, the body of the HTTP request must be read to obtain actual CSRF token. +-However, reading the body means that the file will be uploaded which means an external site can upload a file. ++Protecting multipart requests (file uploads) from CSRF attacks causes a https://en.wikipedia.org/wiki/Chicken_or_the_egg[chicken or the egg] problem. ++To prevent a CSRF attack from occurring, the body of the HTTP request must be read to obtain the actual CSRF token. ++However, reading the body means that the file is uploaded, which means an external site can upload a file. + +-There are two options to using CSRF protection with multipart/form-data. +-Each option has its trade-offs. ++There are two options to using CSRF protection with multipart/form-data: + + * <> + * <> + +-[NOTE] +-==== +-Before you integrate Spring Security's CSRF protection with multipart file upload, ensure that you can upload without the CSRF protection first. +-More information about using multipart forms with Spring can be found within the https://docs.spring.io/spring/docs/5.2.x/spring-framework-reference/web.html#mvc-multipart[1.1.11. Multipart Resolver] section of the Spring reference and the https://docs.spring.io/spring/docs/5.2.x/javadoc-api/org/springframework/web/multipart/support/MultipartFilter.html[MultipartFilter javadoc]. +-==== ++Each option has its trade-offs. ++ ++NOTE: Before you integrate Spring Security's CSRF protection with multipart file upload, you should first ensure that you can upload without the CSRF protection. ++More information about using multipart forms with Spring, see the https://docs.spring.io/spring/docs/5.2.x/spring-framework-reference/web.html#mvc-multipart[1.1.11. Multipart Resolver] section of the Spring reference and the https://docs.spring.io/spring/docs/5.2.x/javadoc-api/org/springframework/web/multipart/support/MultipartFilter.html[`MultipartFilter` Javadoc]. + + [[csrf-considerations-multipart-body]] + ==== Place CSRF Token in the Body + The first option is to include the actual CSRF token in the body of the request. +-By placing the CSRF token in the body, the body will be read before authorization is performed. ++By placing the CSRF token in the body, the body is read before authorization is performed. + This means that anyone can place temporary files on your server. +-However, only authorized users will be able to submit a File that is processed by your application. +-In general, this is the recommended approach because the temporary file upload should have a negligible impact on most servers. ++However, only authorized users can submit a file that is processed by your application. ++In general, this is the recommended approach, because the temporary file upload should have a negligible impact on most servers. + + [[csrf-considerations-multipart-url]] + ==== Include CSRF Token in URL +-If allowing unauthorized users to upload temporary files is not acceptable, an alternative is to include the expected CSRF token as a query parameter in the action attribute of the form. ++If letting unauthorized users upload temporary files is not acceptable, an alternative is to include the expected CSRF token as a query parameter in the action attribute of the form. + The disadvantage to this approach is that query parameters can be leaked. + More generally, it is considered best practice to place sensitive data within the body or headers to ensure it is not leaked. +-Additional information can be found in https://www.w3.org/Protocols/rfc2616/rfc2616-sec15.html#sec15.1.3[RFC 2616 Section 15.1.3 Encoding Sensitive Information in URI's]. ++You can find additional information in https://www.w3.org/Protocols/rfc2616/rfc2616-sec15.html#sec15.1.3[RFC 2616 Section 15.1.3 Encoding Sensitive Information in URI's]. + + [[csrf-considerations-override-method]] + ==== HiddenHttpMethodFilter +-In some applications a form parameter can be used to override the HTTP method. +-For example, the form below could be used to treat the HTTP method as a `delete` rather than a `post`. ++Some applications can use a form parameter to override the HTTP method. ++For example, the following form can treat the HTTP method as a `delete` rather than a `post`. + + .CSRF Hidden HTTP Method Form + ==== +@@ -409,5 +391,5 @@ For example, the form below could be used to treat the HTTP method as a `delete` + + Overriding the HTTP method occurs in a filter. + That filter must be placed before Spring Security's support. +-Note that overriding only happens on a `post`, so this is actually unlikely to cause any real problems. +-However, it is still best practice to ensure it is placed before Spring Security's filters. ++Note that overriding happens only on a `post`, so this is actually unlikely to cause any real problems. ++However, it is still best practice to ensure that it is placed before Spring Security's filters. +diff --git a/docs/manual/src/docs/asciidoc/_includes/about/exploits/headers.adoc b/docs/manual/src/docs/asciidoc/_includes/about/exploits/headers.adoc +index ee3639d937..babd63026f 100644 +--- a/docs/manual/src/docs/asciidoc/_includes/about/exploits/headers.adoc ++++ b/docs/manual/src/docs/asciidoc/_includes/about/exploits/headers.adoc +@@ -1,23 +1,17 @@ + [[headers]] + = Security HTTP Response Headers + +-[NOTE] +-==== +-This portion of the documentation discusses the general topic of Security HTTP Response Headers. +-Refer to the relevant sections for specific information on Security HTTP Response Headers <> and <> based applications. +-==== ++NOTE: This portion of the documentation discusses the general topic of Security HTTP Response Headers. ++See the relevant sections for specific information on Security HTTP Response Headers in <>- and <>-based applications. + +-There are many https://www.owasp.org/index.php/OWASP_Secure_Headers_Project#tab=Headers[HTTP response headers] that can be used to increase the security of web applications. +-This section is dedicated to the various HTTP response headers that Spring Security provides explicit support for. +-If necessary, Spring Security can also be configured to provide <>. ++You can use https://www.owasp.org/index.php/OWASP_Secure_Headers_Project#tab=Headers[HTTP response headers] in many ways to increase the security of web applications. ++This section is dedicated to the various HTTP response headers for which Spring Security provides explicit support. ++If necessary, you can also configure Spring Security to provide <>. + + [[headers-default]] + == Default Security Headers + +-[NOTE] +-==== +-Refer to the relevant sections to see how to customize the defaults for both <> and <> based applications. +-==== ++NOTE: See the relevant sections for how to customize the defaults for both <>- and <>-based applications. + + Spring Security provides a default set of security related HTTP response headers to provide secure defaults. + +@@ -37,10 +31,10 @@ X-XSS-Protection: 1; mode=block + ---- + ==== + +-NOTE: Strict-Transport-Security is only added on HTTPS requests ++NOTE: Strict-Transport-Security is added only on HTTPS requests + + If the defaults do not meet your needs, you can easily remove, modify, or add headers from these defaults. +-For additional details on each of these headers, refer to the corresponding sections: ++For additional details on each of these headers, see the corresponding sections: + + * <> + * <> +@@ -51,14 +45,11 @@ For additional details on each of these headers, refer to the corresponding sect + [[headers-cache-control]] + == Cache Control + +-[NOTE] +-==== +-Refer to the relevant sections to see how to customize the defaults for both <> and <> based applications. +-==== ++NOTE: See the relevant sections for how to customize the defaults for both <>- and <>-based applications. + +-Spring Security's default is to disable caching to protect user's content. ++Spring Security's default is to disable caching to protect the user's content. + +-If a user authenticates to view sensitive information and then logs out, we don't want a malicious user to be able to click the back button to view the sensitive information. ++If a user authenticates to view sensitive information and then logs out, we do not want a malicious user to be able to click the back button to view the sensitive information. + The cache control headers that are sent by default are: + + .Default Cache Control HTTP Response Headers +@@ -71,35 +62,29 @@ Expires: 0 + ---- + ==== + +-In order to be secure by default, Spring Security adds these headers by default. +-However, if your application provides its own cache control headers Spring Security will back out of the way. +-This allows for applications to ensure that static resources like CSS and JavaScript can be cached. ++To be secure by default, Spring Security adds these headers by default. ++However, if your application provides its own cache control headers, Spring Security backs out of the way. ++This allows for applications to ensure that static resources (such as CSS and JavaScript) can be cached. + + + [[headers-content-type-options]] + == Content Type Options + +-[NOTE] +-==== +-Refer to the relevant sections to see how to customize the defaults for both <> and <> based applications. +-==== ++NOTE: See the relevant sections for how to customize the defaults for both <>- and <>-based applications. + +-Historically browsers, including Internet Explorer, would try to guess the content type of a request using https://en.wikipedia.org/wiki/Content_sniffing[content sniffing]. +-This allowed browsers to improve the user experience by guessing the content type on resources that had not specified the content type. ++Historically, browsers, including Internet Explorer, would try to guess the content type of a request by using https://en.wikipedia.org/wiki/Content_sniffing[content sniffing]. ++This let browsers improve the user experience by guessing the content type on resources that had not specified the content type. + For example, if a browser encountered a JavaScript file that did not have the content type specified, it would be able to guess the content type and then run it. + +-[NOTE] +-==== +-There are many additional things one should do (i.e. only display the document in a distinct domain, ensure Content-Type header is set, sanitize the document, etc) when allowing content to be uploaded. ++NOTE: There are many additional things one should do (such as only display the document in a distinct domain, ensure Content-Type header is set, sanitize the document, and others) when allowing content to be uploaded. + However, these measures are out of the scope of what Spring Security provides. +-It is also important to point out when disabling content sniffing, you must specify the content type in order for things to work properly. +-==== ++It is also important to point out that, when disabling content sniffing, you must specify the content type in order for things to work properly. + +-The problem with content sniffing is that this allowed malicious users to use polyglots (i.e. a file that is valid as multiple content types) to perform XSS attacks. ++The problem with content sniffing is that this allowed malicious users to use polyglots (that is, a file that is valid as multiple content types) to perform XSS attacks. + For example, some sites may allow users to submit a valid postscript document to a website and view it. +-A malicious user might create a http://webblaze.cs.berkeley.edu/papers/barth-caballero-song.pdf[postscript document that is also a valid JavaScript file] and perform a XSS attack with it. ++A malicious user might create a http://webblaze.cs.berkeley.edu/papers/barth-caballero-song.pdf[postscript document that is also a valid JavaScript file] and perform an XSS attack with it. + +-Spring Security disables content sniffing by default by adding the following header to HTTP responses: ++By default, Spring Security disables content sniffing by adding the following header to HTTP responses: + + .nosniff HTTP Response Header + ==== +@@ -112,28 +97,22 @@ X-Content-Type-Options: nosniff + [[headers-hsts]] + == HTTP Strict Transport Security (HSTS) + +-[NOTE] +-==== +-Refer to the relevant sections to see how to customize the defaults for both <> and <> based applications. +-==== ++NOTE: Refer to the relevant sections to see how to customize the defaults for both <> and <> based applications. + +-When you type in your bank's website, do you enter mybank.example.com or do you enter https://mybank.example.com[]? +-If you omit the https protocol, you are potentially vulnerable to https://en.wikipedia.org/wiki/Man-in-the-middle_attack[Man in the Middle attacks]. +-Even if the website performs a redirect to https://mybank.example.com a malicious user could intercept the initial HTTP request and manipulate the response (e.g. redirect to https://mibank.example.com and steal their credentials). ++When you type in your bank's website, do you enter `mybank.example.com` or do you enter `https://mybank.example.com`? ++If you omit the `https` protocol, you are potentially vulnerable to https://en.wikipedia.org/wiki/Man-in-the-middle_attack[Man-in-the-Middle attacks]. ++Even if the website performs a redirect to https://mybank.example.com, a malicious user could intercept the initial HTTP request and manipulate the response (for example, redirect to https://mibank.example.com and steal their credentials). + +-Many users omit the https protocol and this is why https://tools.ietf.org/html/rfc6797[HTTP Strict Transport Security (HSTS)] was created. +-Once mybank.example.com is added as a https://tools.ietf.org/html/rfc6797#section-5.1[HSTS host], a browser can know ahead of time that any request to mybank.example.com should be interpreted as https://mybank.example.com. +-This greatly reduces the possibility of a Man in the Middle attack occurring. ++Many users omit the `https` protocol, and this is why https://tools.ietf.org/html/rfc6797[HTTP Strict Transport Security (HSTS)] was created. ++Once `mybank.example.com` is added as a https://tools.ietf.org/html/rfc6797#section-5.1[HSTS host], a browser can know ahead of time that any request to mybank.example.com should be interpreted as https://mybank.example.com. ++This greatly reduces the possibility of a Man-in-the-Middle attack occurring. + +-[NOTE] +-==== +-In accordance with https://tools.ietf.org/html/rfc6797#section-7.2[RFC6797], the HSTS header is only injected into HTTPS responses. +-In order for the browser to acknowledge the header, the browser must first trust the CA that signed the SSL certificate used to make the connection (not just the SSL certificate). +-==== ++NOTE: In accordance with https://tools.ietf.org/html/rfc6797#section-7.2[RFC6797], the HSTS header is injected only into HTTPS responses. ++For the browser to acknowledge the header, the browser must first trust the CA that signed the SSL certificate used to make the connection (not just the SSL certificate). + + One way for a site to be marked as a HSTS host is to have the host preloaded into the browser. +-Another is to add the `Strict-Transport-Security` header to the response. +-For example, Spring Security's default behavior is to add the following header which instructs the browser to treat the domain as an HSTS host for a year (there are approximately 31536000 seconds in a year): ++Another way is to add the `Strict-Transport-Security` header to the response. ++For example, Spring Security's default behavior is to add the following header, which instructs the browser to treat the domain as an HSTS host for a year (there are 31536000 seconds in a non-leap year): + + + .Strict Transport Security HTTP Response Header +@@ -144,99 +123,83 @@ Strict-Transport-Security: max-age=31536000 ; includeSubDomains ; preload + ---- + ==== + +-The optional `includeSubDomains` directive instructs the browser that subdomains (e.g. secure.mybank.example.com) should also be treated as an HSTS domain. ++The optional `includeSubDomains` directive instructs the browser that subdomains (such as `secure.mybank.example.com`) should also be treated as an HSTS domain. + +-The optional `preload` directive instructs the browser that domain should be preloaded in browser as HSTS domain. +-For more details on HSTS preload please see https://hstspreload.org. ++The optional `preload` directive instructs the browser that the domain should be preloaded in browser as an HSTS domain. ++For more details on HSTS preload, see https://hstspreload.org. + + [[headers-hpkp]] + == HTTP Public Key Pinning (HPKP) + +-[NOTE] +-==== +-In order to remain passive Spring Security still provides <>, but for the reasons listed above HPKP is no longer recommended by the security team. +-==== ++NOTE: To remain passive, Spring Security still provides <>. However, for the reasons listed earlier, HPKP is no longer recommended by the Spring Security team. + +-https://developer.mozilla.org/en-US/docs/Web/HTTP/Public_Key_Pinning[HTTP Public Key Pinning (HPKP)] specifies to a web client which public key to use with certain web server to prevent Man in the Middle (MITM) attacks with forged certificates. ++https://developer.mozilla.org/en-US/docs/Web/HTTP/Public_Key_Pinning[HTTP Public Key Pinning (HPKP)] specifies to a web client which public key to use with a certain web server to prevent Man-in-the-Middle (MITM) attacks with forged certificates. + When used correctly, HPKP could add additional layers of protection against compromised certificates. +-However, due to the complexity of HPKP many experts no longer recommend using it and https://www.chromestatus.com/feature/5903385005916160[Chrome has even removed support] for it. ++However, due to the complexity of HPKP, many experts no longer recommend using it and https://www.chromestatus.com/feature/5903385005916160[Chrome has even removed support] for it. + + [[headers-hpkp-deprecated]] +-For additional details around why HPKP is no longer recommended read https://blog.qualys.com/ssllabs/2016/09/06/is-http-public-key-pinning-dead[ +-Is HTTP Public Key Pinning Dead?] and https://scotthelme.co.uk/im-giving-up-on-hpkp/[I'm giving up on HPKP]. ++For additional details around why HPKP is no longer recommended, read https://blog.qualys.com/ssllabs/2016/09/06/is-http-public-key-pinning-dead[Is HTTP Public Key Pinning Dead?] and https://scotthelme.co.uk/im-giving-up-on-hpkp/[I'm giving up on HPKP]. + + [[headers-frame-options]] + == X-Frame-Options + +-[NOTE] +-==== +-Refer to the relevant sections to see how to customize the defaults for both <> and <> based applications. +-==== ++NOTE: See the relevant sections to see how to customize the defaults for both <> and <> based applications. + +-Allowing your website to be added to a frame can be a security issue. +-For example, using clever CSS styling users could be tricked into clicking on something that they were not intending. ++Letting your website be added to a frame can be a security issue. ++For example, by using clever CSS styling, users could be tricked into clicking on something that they were not intending. + For example, a user that is logged into their bank might click a button that grants access to other users. + This sort of attack is known as https://en.wikipedia.org/wiki/Clickjacking[Clickjacking]. + +-[NOTE] +-==== +-Another modern approach to dealing with clickjacking is to use <>. +-==== ++NOTE: Another modern approach to dealing with clickjacking is to use <>. + + There are a number ways to mitigate clickjacking attacks. +-For example, to protect legacy browsers from clickjacking attacks you can use https://www.owasp.org/index.php/Clickjacking_Defense_Cheat_Sheet#Best-for-now_Legacy_Browser_Frame_Breaking_Script[frame breaking code]. ++For example, to protect legacy browsers from clickjacking attacks, you can use https://www.owasp.org/index.php/Clickjacking_Defense_Cheat_Sheet#Best-for-now_Legacy_Browser_Frame_Breaking_Script[frame breaking code]. + While not perfect, the frame breaking code is the best you can do for the legacy browsers. + + A more modern approach to address clickjacking is to use https://developer.mozilla.org/en-US/docs/HTTP/X-Frame-Options[X-Frame-Options] header. +-By default Spring Security disables rendering pages within an iframe using with the following header: ++By default, Spring Security disables rendering pages within an iframe by using with the following header: + ++==== + [source] + ---- + X-Frame-Options: DENY + ---- ++==== + + [[headers-xss-protection]] + == X-XSS-Protection + +-[NOTE] +-==== +-Refer to the relevant sections to see how to customize the defaults for both <> and <> based applications. +-==== ++NOTE: See the relevant sections to see how to customize the defaults for both <>- and <>-based applications. + +-Some browsers have built in support for filtering out https://www.owasp.org/index.php/Testing_for_Reflected_Cross_site_scripting_(OWASP-DV-001)[reflected XSS attacks]. +-This is by no means foolproof, but does assist in XSS protection. ++Some browsers have built-in support for filtering out https://www.owasp.org/index.php/Testing_for_Reflected_Cross_site_scripting_(OWASP-DV-001)[reflected XSS attacks]. ++This is by no means foolproof but does assist in XSS protection. + + The filtering is typically enabled by default, so adding the header typically just ensures it is enabled and instructs the browser what to do when a XSS attack is detected. + For example, the filter might try to change the content in the least invasive way to still render everything. +-At times, this type of replacement can become a https://hackademix.net/2009/11/21/ies-xss-filter-creates-xss-vulnerabilities/[XSS vulnerability in itself]. ++At times, this type of replacement can become an https://hackademix.net/2009/11/21/ies-xss-filter-creates-xss-vulnerabilities/[XSS vulnerability in itself]. + Instead, it is best to block the content rather than attempt to fix it. +-By default Spring Security blocks the content using the following header: ++By default, Spring Security blocks the content by using the following header: + ++==== + [source] + ---- + X-XSS-Protection: 1; mode=block + ---- +- ++==== + + [[headers-csp]] + == Content Security Policy (CSP) + +-[NOTE] +-==== +-Refer to the relevant sections to see how to configure both <> and <> based applications. +-==== ++NOTE: See the relevant sections to see how to configure both <>- and <>-based applications. + +-https://www.w3.org/TR/CSP2/[Content Security Policy (CSP)] is a mechanism that web applications can leverage to mitigate content injection vulnerabilities, such as cross-site scripting (XSS). ++https://www.w3.org/TR/CSP2/[Content Security Policy (CSP)] is a mechanism that web applications can use to mitigate content injection vulnerabilities, such as cross-site scripting (XSS). + CSP is a declarative policy that provides a facility for web application authors to declare and ultimately inform the client (user-agent) about the sources from which the web application expects to load resources. + +-[NOTE] +-==== +-Content Security Policy is not intended to solve all content injection vulnerabilities. +-Instead, CSP can be leveraged to help reduce the harm caused by content injection attacks. ++NOTE: Content Security Policy is not intended to solve all content injection vulnerabilities. ++Instead, you can use CSP to help reduce the harm caused by content injection attacks. + As a first line of defense, web application authors should validate their input and encode their output. +-==== + +-A web application may employ the use of CSP by including one of the following HTTP headers in the response: ++A web application can use CSP by including one of the following HTTP headers in the response: + + * `Content-Security-Policy` + * `Content-Security-Policy-Report-Only` +@@ -244,7 +207,7 @@ A web application may employ the use of CSP by including one of the following HT + Each of these headers are used as a mechanism to deliver a security policy to the client. + A security policy contains a set of security policy directives, each responsible for declaring the restrictions for a particular resource representation. + +-For example, a web application can declare that it expects to load scripts from specific, trusted sources, by including the following header in the response: ++For example, a web application can declare that it expects to load scripts from specific, trusted sources by including the following header in the response: + + .Content Security Policy Example + ==== +@@ -254,10 +217,10 @@ Content-Security-Policy: script-src https://trustedscripts.example.com + ---- + ==== + +-An attempt to load a script from another source other than what is declared in the `script-src` directive will be blocked by the user-agent. +-Additionally, if the https://www.w3.org/TR/CSP2/#directive-report-uri[report-uri] directive is declared in the security policy, then the violation will be reported by the user-agent to the declared URL. ++An attempt to load a script from another source other than what is declared in the `script-src` directive is blocked by the user-agent. ++Additionally, if the https://www.w3.org/TR/CSP2/#directive-report-uri[report-uri] directive is declared in the security policy, the violation will be reported by the user-agent to the declared URL. + +-For example, if a web application violates the declared security policy, the following response header will instruct the user-agent to send violation reports to the URL specified in the policy's `report-uri` directive. ++For example, if a web application violates the declared security policy, the following response header instructs the user-agent to send violation reports to the URL specified in the policy's `report-uri` directive. + + .Content Security Policy with report-uri + ==== +@@ -267,13 +230,13 @@ Content-Security-Policy: script-src https://trustedscripts.example.com; report-u + ---- + ==== + +-https://www.w3.org/TR/CSP2/#violation-reports[Violation reports] are standard JSON structures that can be captured either by the web application's own API or by a publicly hosted CSP violation reporting service, such as, https://report-uri.io/. ++https://www.w3.org/TR/CSP2/#violation-reports[Violation reports] are standard JSON structures that can be captured either by the web application's own API or by a publicly hosted CSP violation reporting service, such as https://report-uri.io/. + +-The `Content-Security-Policy-Report-Only` header provides the capability for web application authors and administrators to monitor security policies, rather than enforce them. +-This header is typically used when experimenting and/or developing security policies for a site. ++The `Content-Security-Policy-Report-Only` header provides the capability for web application authors and administrators to monitor security policies rather than enforce them. ++This header is typically used when experimenting or developing security policies for a site. + When a policy is deemed effective, it can be enforced by using the `Content-Security-Policy` header field instead. + +-Given the following response header, the policy declares that scripts may be loaded from one of two possible sources. ++Given the following response header, the policy declares that scripts can be loaded from one of two possible sources. + + .Content Security Policy Report Only + ==== +@@ -283,10 +246,10 @@ Content-Security-Policy-Report-Only: script-src 'self' https://trustedscripts.ex + ---- + ==== + +-If the site violates this policy, by attempting to load a script from _evil.com_, the user-agent will send a violation report to the declared URL specified by the _report-uri_ directive, but still allow the violating resource to load nevertheless. ++If the site violates this policy, by attempting to load a script from evil.com, the user-agent sends a violation report to the declared URL specified by the `report-uri` directive but still lets the violating resource load. + + Applying Content Security Policy to a web application is often a non-trivial undertaking. +-The following resources may provide further assistance in developing effective security policies for your site. ++The following resources may provide further assistance in developing effective security policies for your site: + + https://www.html5rocks.com/en/tutorials/security/content-security-policy/[An Introduction to Content Security Policy] + +@@ -297,15 +260,12 @@ https://www.w3.org/TR/CSP2/[W3C Candidate Recommendation] + [[headers-referrer]] + == Referrer Policy + +-[NOTE] +-==== +-Refer to the relevant sections to see how to configure both <> and <> based applications. +-==== ++NOTE: See the relevant sections to see how to configure both <>- and <>-based applications. + +-https://www.w3.org/TR/referrer-policy[Referrer Policy] is a mechanism that web applications can leverage to manage the referrer field, which contains the last ++https://www.w3.org/TR/referrer-policy[Referrer Policy] is a mechanism that web applications can use to manage the referrer field, which contains the last + page the user was on. + +-Spring Security's approach is to use https://www.w3.org/TR/referrer-policy/[Referrer Policy] header, which provides different https://www.w3.org/TR/referrer-policy/#referrer-policies[policies]: ++Spring Security's approach is to use the https://www.w3.org/TR/referrer-policy/[Referrer Policy] header, which provides different https://www.w3.org/TR/referrer-policy/#referrer-policies[policies]: + + .Referrer Policy Example + ==== +@@ -320,12 +280,9 @@ The Referrer-Policy response header instructs the browser to let the destination + [[headers-feature]] + == Feature Policy + +-[NOTE] +-==== +-Refer to the relevant sections to see how to configure both <> and <> based applications. +-==== ++NOTE: See the relevant sections to see how to configure both <>- and <>-based applications. + +-https://wicg.github.io/feature-policy/[Feature Policy] is a mechanism that allows web developers to selectively enable, disable, and modify the behavior of certain APIs and web features in the browser. ++https://wicg.github.io/feature-policy/[Feature Policy] is a mechanism that lets web developers selectively enable, disable, and modify the behavior of certain APIs and web features in the browser. + + .Feature Policy Example + ==== +@@ -335,19 +292,16 @@ Feature-Policy: geolocation 'self' + ---- + ==== + +-With Feature Policy, developers can opt-in to a set of "policies" for the browser to enforce on specific features used throughout your site. ++With Feature Policy, developers can opt-in to a set of "`policies`" for the browser to enforce on specific features used throughout your site. + These policies restrict what APIs the site can access or modify the browser's default behavior for certain features. + + + [[headers-permissions]] + == Permissions Policy + +-[NOTE] +-==== +-Refer to the relevant sections to see how to configure both <> and <> based applications. +-==== ++NOTE: See the relevant sections to see how to configure both <>- and <>-based applications. + +-https://w3c.github.io/webappsec-permissions-policy/[Permissions Policy] is a mechanism that allows web developers to selectively enable, disable, and modify the behavior of certain APIs and web features in the browser. ++https://w3c.github.io/webappsec-permissions-policy/[Permissions Policy] is a mechanism that lets web developers selectively enable, disable, and modify the behavior of certain APIs and web features in the browser. + + .Permissions Policy Example + ==== +@@ -357,24 +311,23 @@ Permissions-Policy: geolocation=(self) + ---- + ==== + +-With Permissions Policy, developers can opt-in to a set of "policies" for the browser to enforce on specific features used throughout your site. ++With a Permissions Policy, developers can opt-in to a set of "`policies`" for the browser to enforce on specific features used throughout your site. + These policies restrict what APIs the site can access or modify the browser's default behavior for certain features. + + + [[headers-clear-site-data]] + == Clear Site Data + +-[NOTE] +-==== +-Refer to the relevant sections to see how to configure both <> and <> based applications. +-==== ++NOTE: See the relevant sections to see how to configure both <> and <> based applications. + +-https://www.w3.org/TR/clear-site-data/[Clear Site Data] is a mechanism by which any browser-side data - cookies, local storage, and the like - can be removed when an HTTP response contains this header: ++https://www.w3.org/TR/clear-site-data/[Clear Site Data] is a mechanism by which any browser-side data (cookies, local storage, and the like) can be removed when an HTTP response contains this header: + ++==== + [source] + ---- + Clear-Site-Data: "cache", "cookies", "storage", "executionContexts" + ---- ++==== + + This is a nice clean-up action to perform on logout. + +@@ -382,10 +335,7 @@ This is a nice clean-up action to perform on logout. + [[headers-custom]] + == Custom Headers + +-[NOTE] +-==== +-Refer to the relevant sections to see how to configure both <> based applications. +-==== ++NOTE: See the relevant sections to see how to configure both <> based applications. + + Spring Security has mechanisms to make it convenient to add the more common security headers to your application. + However, it also provides hooks to enable adding custom headers. +diff --git a/docs/manual/src/docs/asciidoc/_includes/about/exploits/http.adoc b/docs/manual/src/docs/asciidoc/_includes/about/exploits/http.adoc +index 5d0dfa6c32..68f6631e6f 100644 +--- a/docs/manual/src/docs/asciidoc/_includes/about/exploits/http.adoc ++++ b/docs/manual/src/docs/asciidoc/_includes/about/exploits/http.adoc +@@ -1,7 +1,7 @@ + [[http]] + = HTTP + +-All HTTP based communication, including https://www.troyhunt.com/heres-why-your-static-website-needs-https/[static resources], should be protected https://cheatsheetseries.owasp.org/cheatsheets/Transport_Layer_Protection_Cheat_Sheet.html[using TLS]. ++All HTTP-based communication, including https://www.troyhunt.com/heres-why-your-static-website-needs-https/[static resources], should be protected by https://cheatsheetseries.owasp.org/cheatsheets/Transport_Layer_Protection_Cheat_Sheet.html[using TLS]. + + As a framework, Spring Security does not handle HTTP connections and thus does not provide support for HTTPS directly. + However, it does provide a number of features that help with HTTPS usage. +@@ -9,7 +9,7 @@ However, it does provide a number of features that help with HTTPS usage. + [[http-redirect]] + == Redirect to HTTPS + +-When a client uses HTTP, Spring Security can be configured to redirect to HTTPS both <> and <> environments. ++When a client uses HTTP, you can configure Spring Security to redirect to HTTPS in both <> and <> environments. + + [[http-hsts]] + == Strict Transport Security +@@ -19,14 +19,14 @@ Spring Security provides support for <> + [[http-proxy-server]] + == 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 +-Without proper configuration, the application server will not know that the load balancer exists and treat the request as though https://192.168.1:8080 was requested by the client. ++When using a proxy server, it is important to ensure that you have configured your application properly. ++For example, many applications 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 ++Without proper configuration, the application server can not know that the load balancer exists and treats the request as though https://192.168.1:8080 was requested by the client. + +-To fix this you can use https://tools.ietf.org/html/rfc7239[RFC 7239] to specify that a load balancer is being used. +-To make the application aware of this, you need to either configure your application server aware of the X-Forwarded headers. +-For example Tomcat uses the https://tomcat.apache.org/tomcat-8.0-doc/api/org/apache/catalina/valves/RemoteIpValve.html[RemoteIpValve] and Jetty uses https://download.eclipse.org/jetty/stable-9/apidocs/org/eclipse/jetty/server/ForwardedRequestCustomizer.html[ForwardedRequestCustomizer]. +-Alternatively, Spring users can leverage https://github.com/spring-projects/spring-framework/blob/v4.3.3.RELEASE/spring-web/src/main/java/org/springframework/web/filter/ForwardedHeaderFilter.java[ForwardedHeaderFilter]. ++To fix this, you can use https://tools.ietf.org/html/rfc7239[RFC 7239] to specify that a load balancer is being used. ++To make the application aware of this, you need to configure your application server to be aware of the X-Forwarded headers. ++For example, Tomcat uses https://tomcat.apache.org/tomcat-8.0-doc/api/org/apache/catalina/valves/RemoteIpValve.html[`RemoteIpValve`] and Jetty uses https://download.eclipse.org/jetty/stable-9/apidocs/org/eclipse/jetty/server/ForwardedRequestCustomizer.html[`ForwardedRequestCustomizer`]. ++Alternatively, Spring users can use https://github.com/spring-projects/spring-framework/blob/v4.3.3.RELEASE/spring-web/src/main/java/org/springframework/web/filter/ForwardedHeaderFilter.java[`ForwardedHeaderFilter`]. + +-Spring Boot users may use the `server.use-forward-headers` property to configure the application. ++Spring Boot users can use the `server.use-forward-headers` property to configure the application. + See the https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#howto-use-tomcat-behind-a-proxy-server[Spring Boot documentation] for further details. +diff --git a/docs/manual/src/docs/asciidoc/_includes/about/exploits/index.adoc b/docs/manual/src/docs/asciidoc/_includes/about/exploits/index.adoc +index bb8abc73dc..eb5ef9b637 100644 +--- a/docs/manual/src/docs/asciidoc/_includes/about/exploits/index.adoc ++++ b/docs/manual/src/docs/asciidoc/_includes/about/exploits/index.adoc +@@ -3,7 +3,7 @@ + + Spring Security provides protection against common exploits. + Whenever possible, the protection is enabled by default. +-Below you will find high level description of the various exploits that Spring Security protects against. ++This section describes the various exploits that Spring Security protects against. + + include::csrf.adoc[leveloffset=+1] + +diff --git a/docs/manual/src/docs/asciidoc/_includes/about/features.adoc b/docs/manual/src/docs/asciidoc/_includes/about/features.adoc +index c08113ae5e..9ce044b519 100644 +--- a/docs/manual/src/docs/asciidoc/_includes/about/features.adoc ++++ b/docs/manual/src/docs/asciidoc/_includes/about/features.adoc +@@ -1,6 +1,7 @@ + [[features]] + = Features + ++// FIXME: Add a link for authorization + Spring Security provides comprehensive support for <>, authorization, and protection against <>. + It also provides integration with other libraries to simplify its usage. + +diff --git a/docs/manual/src/docs/asciidoc/_includes/about/getting-spring-security.adoc b/docs/manual/src/docs/asciidoc/_includes/about/getting-spring-security.adoc +index c2b64f113a..464ee567dc 100644 +--- a/docs/manual/src/docs/asciidoc/_includes/about/getting-spring-security.adoc ++++ b/docs/manual/src/docs/asciidoc/_includes/about/getting-spring-security.adoc +@@ -1,7 +1,7 @@ + [[getting]] + = Getting Spring Security + +-This section discusses all you need to know about getting the Spring Security binaries. ++This section describes how to get the Spring Security binaries. + See <> for how to obtain the source code. + + == Release Numbering +@@ -10,7 +10,7 @@ Spring Security versions are formatted as MAJOR.MINOR.PATCH such that: + + * MAJOR versions may contain breaking changes. + Typically, these are done to provide improved security to match modern security practices. +-* MINOR versions contain enhancements but are considered passive updates ++* MINOR versions contain enhancements but are considered passive updates. + * PATCH level should be perfectly compatible, forwards and backwards, with the possible exception of changes that fix bugs. + + +@@ -18,13 +18,13 @@ Typically, these are done to provide improved security to match modern security + == Usage with Maven + + As most open source projects, Spring Security deploys its dependencies as Maven artifacts. +-The topics in this section provide detail on how to consume Spring Security when using Maven. ++The topics in this section describe how to consume Spring Security when using Maven. + + [[getting-maven-boot]] + === Spring Boot with Maven + +-Spring Boot provides a `spring-boot-starter-security` starter that aggregates Spring Security-related dependencies together. +-The simplest and preferred way to use the starter is to use https://docs.spring.io/initializr/docs/current/reference/htmlsingle/[Spring Initializr] by using an IDE integration (https://joshlong.com/jl/blogPost/tech_tip_geting_started_with_spring_boot.html[Eclipse], https://www.jetbrains.com/help/idea/spring-boot.html#d1489567e2[IntelliJ], https://github.com/AlexFalappa/nb-springboot/wiki/Quick-Tour[NetBeans]) or through https://start.spring.io. ++Spring Boot provides a `spring-boot-starter-security` starter that aggregates Spring Security-related dependencies. ++The simplest and preferred way to use the starter is to use https://docs.spring.io/initializr/docs/current/reference/htmlsingle/[Spring Initializr] by using an IDE integration in (https://joshlong.com/jl/blogPost/tech_tip_geting_started_with_spring_boot.html[Eclipse] or https://www.jetbrains.com/help/idea/spring-boot.html#d1489567e2[IntelliJ], https://github.com/AlexFalappa/nb-springboot/wiki/Quick-Tour[NetBeans]) or through https://start.spring.io. + + Alternatively, you can manually add the starter, as the following example shows: + +@@ -44,7 +44,7 @@ Alternatively, you can manually add the starter, as the following example shows: + ==== + + Since Spring Boot provides a Maven BOM to manage dependency versions, you do not need to specify a version. +-If you wish to override the Spring Security version, you may do so by providing a Maven property, as the following example shows: ++If you wish to override the Spring Security version, you can do so by providing a Maven property: + + .pom.xml + ==== +@@ -57,9 +57,9 @@ If you wish to override the Spring Security version, you may do so by providing + ---- + ==== + +-Since Spring Security makes breaking changes only in major releases, it is safe to use a newer version of Spring Security with Spring Boot. ++Since Spring Security makes breaking changes only in major releases, you can safely use a newer version of Spring Security with Spring Boot. + However, at times, you may need to update the version of Spring Framework as well. +-You can do so by adding a Maven property, as the following example shows: ++You can do so by adding a Maven property: + + .pom.xml + ==== +@@ -72,12 +72,12 @@ You can do so by adding a Maven property, as the following example shows: + ---- + ==== + +-If you use additional features (such as LDAP, OpenID, and others), you need to also include the appropriate <>. ++If you use additional features (such as LDAP, OpenID, and others), you need to also include the appropriate <>. + + [[getting-maven-no-boot]] + === Maven Without Spring Boot + +-When you use Spring Security without Spring Boot, the preferred way is to use Spring Security's BOM to ensure a consistent version of Spring Security is used throughout the entire project. The following example shows how to do so: ++When you use Spring Security without Spring Boot, the preferred way is to use Spring Security's BOM to ensure that a consistent version of Spring Security is used throughout the entire project. The following example shows how to do so: + + .pom.xml + ==== +@@ -98,7 +98,7 @@ When you use Spring Security without Spring Boot, the preferred way is to use Sp + ---- + ==== + +-A minimal Spring Security Maven set of dependencies typically looks like the following: ++A minimal Spring Security Maven set of dependencies typically looks like the following example: + + .pom.xml + ==== +@@ -118,11 +118,11 @@ A minimal Spring Security Maven set of dependencies typically looks like the fol + ---- + ==== + +-If you use additional features (such as LDAP, OpenID, and others), you need to also include the appropriate <>. ++If you use additional features (such as LDAP, OpenID, and others), you need to also include the appropriate <>. + + Spring Security builds against Spring Framework {spring-core-version} but should generally work with any newer version of Spring Framework 5.x. + Many users are likely to run afoul of the fact that Spring Security's transitive dependencies resolve Spring Framework {spring-core-version}, which can cause strange classpath problems. +-The easiest way to resolve this is to use the `spring-framework-bom` within the `` section of your `pom.xml` as the following example shows: ++The easiest way to resolve this is to use the `spring-framework-bom` within the `` section of your `pom.xml`: + + .pom.xml + ==== +@@ -150,9 +150,9 @@ For additional details about how dependencies are resolved, see https://maven.ap + + [[maven-repositories]] + === Maven Repositories +-All GA releases (that is, versions ending in .RELEASE) are deployed to Maven Central, so no additional Maven repositories need to be declared in your pom. ++All GA releases (that is, versions ending in .RELEASE) are deployed to Maven Central, so you need not declare additional Maven repositories in your pom. + +-If you use a SNAPSHOT version, you need to ensure that you have the Spring Snapshot repository defined, as the following example shows: ++If you use a SNAPSHOT version, you need to ensure that you have the Spring Snapshot repository defined: + + .pom.xml + ==== +@@ -190,15 +190,15 @@ If you use a milestone or release candidate version, you need to ensure that you + == Gradle + + As most open source projects, Spring Security deploys its dependencies as Maven artifacts, which allows for first-class Gradle support. +-The following topics provide detail on how to consume Spring Security when using Gradle. ++The following topics describe how to consume Spring Security when using Gradle. + + [[getting-gradle-boot]] + === Spring Boot with Gradle + +-Spring Boot provides a `spring-boot-starter-security` starter that aggregates Spring Security related dependencies together. +-The simplest and preferred method to use the starter is to use https://docs.spring.io/initializr/docs/current/reference/htmlsingle/[Spring Initializr] by using an IDE integration (https://joshlong.com/jl/blogPost/tech_tip_geting_started_with_spring_boot.html[Eclipse], https://www.jetbrains.com/help/idea/spring-boot.html#d1489567e2[IntelliJ], https://github.com/AlexFalappa/nb-springboot/wiki/Quick-Tour[NetBeans]) or through https://start.spring.io. ++Spring Boot provides a `spring-boot-starter-security` starter that aggregates Spring Security related dependencies. ++The simplest and preferred method to use the starter is to use https://docs.spring.io/initializr/docs/current/reference/htmlsingle/[Spring Initializr] by using an IDE integration in (https://joshlong.com/jl/blogPost/tech_tip_geting_started_with_spring_boot.html[Eclipse] or https://www.jetbrains.com/help/idea/spring-boot.html#d1489567e2[IntelliJ], https://github.com/AlexFalappa/nb-springboot/wiki/Quick-Tour[NetBeans]) or through https://start.spring.io. + +-Alternatively, you can manually add the starter, as the following example shows: ++Alternatively, you can manually add the starter: + + .build.gradle + ==== +@@ -212,7 +212,7 @@ dependencies { + ==== + + Since Spring Boot provides a Maven BOM to manage dependency versions, you need not specify a version. +-If you wish to override the Spring Security version, you may do so by providing a Gradle property, as the following example shows: ++If you wish to override the Spring Security version, you can do so by providing a Gradle property: + + .build.gradle + ==== +@@ -223,9 +223,9 @@ ext['spring-security.version']='{spring-security-version}' + ---- + ==== + +-Since Spring Security makes breaking changes only in major releases, it is safe to use a newer version of Spring Security with Spring Boot. ++Since Spring Security makes breaking changes only in major releases, you can safely use a newer version of Spring Security with Spring Boot. + However, at times, you may need to update the version of Spring Framework as well. +-You can do so by adding a Gradle property, as the following example shows: ++You can do so by adding a Gradle property: + + .build.gradle + ==== +@@ -236,12 +236,12 @@ ext['spring.version']='{spring-core-version}' + ---- + ==== + +-If you use additional features (such as LDAP, OpenID, and others), you need to also include the appropriate <>. ++If you use additional features (such as LDAP, OpenID, and others), you need to also include the appropriate <>. + + === Gradle Without Spring Boot + + When you use Spring Security without Spring Boot, the preferred way is to use Spring Security's BOM to ensure a consistent version of Spring Security is used throughout the entire project. +-You can do so by using the https://github.com/spring-gradle-plugins/dependency-management-plugin[Dependency Management Plugin], as the following example shows: ++You can do so by using the https://github.com/spring-gradle-plugins/dependency-management-plugin[Dependency Management Plugin]: + + .build.gradle + ==== +@@ -260,7 +260,7 @@ dependencyManagement { + ---- + ==== + +-A minimal Spring Security Maven set of dependencies typically looks like the following: ++A minimal Spring Security Maven set of dependencies typically looks like the following example: + + .build.gradle + ==== +@@ -274,12 +274,12 @@ dependencies { + ---- + ==== + +-If you use additional features (such as LDAP, OpenID, and others), you need to also include the appropriate <>. ++If you use additional features (such as LDAP, OpenID, and others), you need to also include the appropriate <>. + + Spring Security builds against Spring Framework {spring-core-version} but should generally work with any newer version of Spring Framework 5.x. + Many users are likely to run afoul of the fact that Spring Security's transitive dependencies resolve Spring Framework {spring-core-version}, which can cause strange classpath problems. + The easiest way to resolve this is to use the `spring-framework-bom` within your `` section of your `pom.xml`. +-You can do so by using the https://github.com/spring-gradle-plugins/dependency-management-plugin[Dependency Management Plugin], as the following example shows: ++You can do so by using the https://github.com/spring-gradle-plugins/dependency-management-plugin[Dependency Management Plugin]: + + .build.gradle + ==== +@@ -302,7 +302,7 @@ The preceding example ensures that all the transitive dependencies of Spring Sec + + [[gradle-repositories]] + === Gradle Repositories +-All GA releases (that is, versions ending in .RELEASE) are deployed to Maven Central, so using the mavenCentral() repository is sufficient for GA releases. The following example shows how to do so: ++All GA releases (that is, versions ending in .RELEASE) are deployed to Maven Central, so using the `mavenCentral()` repository is sufficient for GA releases. The following example shows how to do so: + + .build.gradle + ==== +@@ -314,7 +314,7 @@ repositories { + ---- + ==== + +-If you use a SNAPSHOT version, you need to ensure you have the Spring Snapshot repository defined, as the following example shows: ++If you use a SNAPSHOT version, you need to ensure that you have the Spring Snapshot repository defined: + + .build.gradle + ==== +@@ -326,7 +326,7 @@ repositories { + ---- + ==== + +-If you use a milestone or release candidate version, you need to ensure that you have the Spring Milestone repository defined, as the following example shows: ++If you use a milestone or release candidate version, you need to ensure that you have the Spring Milestone repository defined: + + .build.gradle + ==== +diff --git a/docs/manual/src/docs/asciidoc/_includes/about/modules.adoc b/docs/manual/src/docs/asciidoc/_includes/about/modules.adoc +index 3503fea601..fd0c274581 100644 +--- a/docs/manual/src/docs/asciidoc/_includes/about/modules.adoc ++++ b/docs/manual/src/docs/asciidoc/_includes/about/modules.adoc +@@ -8,13 +8,13 @@ Even if you do not use Maven, we recommend that you consult the `pom.xml` files + Another good idea is to examine the libraries that are included in the sample applications. + + This section provides a reference of the modules in Spring Security and the additional dependencies that they require in order to function in a running application. +-We don't include dependencies that are only used when building or testing Spring Security itself. +-Nor do we include transitive dependencies which are required by external dependencies. ++We do not include dependencies that are used only when building or testing Spring Security itself. ++Nor do we include transitive dependencies that are required by external dependencies. + +-The version of Spring required is listed on the project website, so the specific versions are omitted for Spring dependencies below. +-Note that some of the dependencies listed as "optional" below may still be required for other non-security functionality in a Spring application. +-Also dependencies listed as "optional" may not actually be marked as such in the project's Maven POM files if they are used in most applications. +-They are "optional" only in the sense that you don't need them unless you are using the specified functionality. ++The version of Spring required is listed on the project website, so the specific versions are omitted for Spring dependencies in the examples. ++Note that some of the dependencies listed as "`optional`" in the examples may still be required for other non-security functionality in a Spring application. ++Also dependencies listed as "`optional`" may not actually be marked as such in the project's Maven POM files if they are used in most applications. ++They are "`optional`" only in the sense that you do not need them unless you use the specified functionality. + + Where a module depends on another Spring Security module, the non-optional dependencies of the module it depends on are also assumed to be required and are not listed separately. + +@@ -85,7 +85,7 @@ The main package is `org.springframework.security.remoting`. + + | spring-web + | +-| Required for clients which use HTTP remoting support. ++| Required for clients that use HTTP remoting support. + |=== + + [[spring-security-web]] +@@ -109,7 +109,7 @@ The main package is `org.springframework.security.web`. + + | spring-jdbc + | +-| Required for JDBC-based persistent remember-me token repository (optional). ++| Required for a JDBC-based persistent remember-me token repository (optional). + + | spring-tx + | +@@ -170,10 +170,9 @@ The top-level package is `org.springframework.security.ldap`. + | + | Data exception classes are required. + +-| apache-ds footnote:[The modules `apacheds-core`, `apacheds-core-entry`, `apacheds-protocol-shared`, `apacheds-protocol-ldap` and `apacheds-server-jndi` are required. +-] ++| apache-ds + | 1.5.5 +-| Required if you are using an embedded LDAP server (optional). ++| Required if you are using an embedded LDAP server (optional). If you use `apache-ds`, the `apacheds-core`, `apacheds-core-entry`, `apacheds-protocol-shared`, `apacheds-protocol-ldap` and `apacheds-server-jndi` modules are required. + + | shared-ldap + | 0.9.15 +@@ -188,7 +187,7 @@ Used for decoding LDAP password policy controls if you are using password-policy + [[spring-security-oauth2-core]] + == OAuth 2.0 Core -- `spring-security-oauth2-core.jar` + `spring-security-oauth2-core.jar` contains core classes and interfaces that provide support for the OAuth 2.0 Authorization Framework and for OpenID Connect Core 1.0. +-It is required by applications that use OAuth 2.0 or OpenID Connect Core 1.0, such as client, resource server, and authorization server. ++It is required by applications that use OAuth 2.0 or OpenID Connect Core 1.0, such as the client, the resource server, and the authorization server. + The top-level package is `org.springframework.security.oauth2.core`. + + +@@ -218,7 +217,7 @@ It contains the following top-level packages: + [[spring-security-oauth2-resource-server]] + == OAuth 2.0 Resource Server -- `spring-security-oauth2-resource-server.jar` + `spring-security-oauth2-resource-server.jar` contains Spring Security's support for OAuth 2.0 Resource Servers. +-It is used to protect APIs via OAuth 2.0 Bearer Tokens. ++It is used to protect APIs by using OAuth 2.0 Bearer Tokens. + The top-level package is `org.springframework.security.oauth2.server.resource`. + + [[spring-security-acl]] +@@ -237,7 +236,7 @@ The top-level package is `org.springframework.security.acls`. + + | ehcache + | 1.6.2 +-| Required if the Ehcache-based ACL cache implementation is used (optional if you are using your own implementation). ++| Required if the Ehcache-based ACL cache implementation is used (optional if you use your own implementation). + + | spring-jdbc + | +@@ -278,8 +277,7 @@ This is the basis of the Spring Security integration. + + [[spring-security-openid]] + == OpenID -- `spring-security-openid.jar` +-[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. ++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. + + This module contains OpenID web authentication support. + It is used to authenticate users against an external OpenID server. +diff --git a/docs/manual/src/docs/asciidoc/_includes/reactive/exploits/csrf.adoc b/docs/manual/src/docs/asciidoc/_includes/reactive/exploits/csrf.adoc +index c3a92fea4f..b0f8024220 100644 +--- a/docs/manual/src/docs/asciidoc/_includes/reactive/exploits/csrf.adoc ++++ b/docs/manual/src/docs/asciidoc/_includes/reactive/exploits/csrf.adoc +@@ -7,32 +7,32 @@ This section discusses Spring Security's <> +-* <> +-* <> ++* <> ++* <> ++* <> + + [[webflux-csrf-idempotent]] +-=== Use proper HTTP verbs ++=== Use Proper HTTP Verbs + The first step to protecting against CSRF attacks is to ensure your website uses proper HTTP verbs. + This is covered in detail in <>. + + [[webflux-csrf-configure]] + === Configure CSRF Protection + The next step is to configure Spring Security's CSRF protection within your application. +-Spring Security's CSRF protection is enabled by default, but you may need to customize the configuration. +-Below are a few common customizations. ++By default, Spring Security's CSRF protection is enabled, but you may need to customize the configuration. ++The next few subsections cover a few common customizations. + + [[webflux-csrf-configure-custom-repository]] + ==== Custom CsrfTokenRepository + +-By default Spring Security stores the expected CSRF token in the `WebSession` using `WebSessionServerCsrfTokenRepository`. +-There can be cases where users will want to configure a custom `ServerCsrfTokenRepository`. +-For example, it might be desirable to persist the `CsrfToken` in a cookie to <>. ++By default, Spring Security stores the expected CSRF token in the `WebSession` by using `WebSessionServerCsrfTokenRepository`. ++Sometimes, you may need to configure a custom `ServerCsrfTokenRepository`. ++For example, you may want to persist the `CsrfToken` in a cookie to <>. + +-By default the `CookieServerCsrfTokenRepository` will write to a cookie named `XSRF-TOKEN` and read it from a header named `X-XSRF-TOKEN` or the HTTP parameter `_csrf`. ++By default, the `CookieServerCsrfTokenRepository` writes to a cookie named `XSRF-TOKEN` and read its from a header named `X-XSRF-TOKEN` or the HTTP `_csrf` parameter. + These defaults come from https://docs.angularjs.org/api/ng/service/$http#cross-site-request-forgery-xsrf-protection[AngularJS] + +-You can configure `CookieServerCsrfTokenRepository` in Java Configuration using: ++You can configure `CookieServerCsrfTokenRepository` in Java Configuration: + + .Store CSRF Token in a Cookie + ==== +@@ -63,19 +63,16 @@ fun springSecurityFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain + ----- + ==== + +-[NOTE] +-==== +-The sample explicitly sets `cookieHttpOnly=false`. +-This is necessary to allow JavaScript (i.e. AngularJS) to read it. +-If you do not need the ability to read the cookie with JavaScript directly, it is recommended to omit `cookieHttpOnly=false` (by using `new CookieServerCsrfTokenRepository()` instead) to improve security. +-==== ++NOTE: The preceding sample explicitly sets `cookieHttpOnly=false`. ++This is necessary to let JavaScript (in this case, AngularJS) to read it. ++If you do not need the ability to read the cookie with JavaScript directly, we recommend to omitting `cookieHttpOnly=false` (by using `new CookieServerCsrfTokenRepository()` instead) to improve security. + + [[webflux-csrf-configure-disable]] + ==== Disable CSRF Protection +-CSRF protection is enabled by default. +-However, it is simple to disable CSRF protection if it <>. ++By default, CSRF protection is enabled. ++However, you can disable CSRF protection if it <>. + +-The Java configuration below will disable CSRF protection. ++The following Java configuration disables CSRF protection: + + .Disable CSRF Configuration + ==== +@@ -109,15 +106,15 @@ fun springSecurityFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain + [[webflux-csrf-include]] + === Include the CSRF Token + +-In order for the <> to protect against CSRF attacks, we must include the actual CSRF token in the HTTP request. +-This must be included in a part of the request (i.e. form parameter, HTTP header, etc) that is not automatically included in the HTTP request by the browser. ++For the <> to protect against CSRF attacks, we must include the actual CSRF token in the HTTP request. ++It must be included in a part of the request (a form parameter, an HTTP header, or other option) that is not automatically included in the HTTP request by the browser. + +-Spring Security's https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/web/server/csrf/CsrfWebFilter.html[CsrfWebFilter] exposes a https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/web/csrf/CsrfToken.html[Mono] as a `ServerWebExchange` attribute named `org.springframework.security.web.server.csrf.CsrfToken`. +-This means that any view technology can access the `Mono` to expose the expected token as either a <> or <>. ++Spring Security's https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/web/server/csrf/CsrfWebFilter.html[`CsrfWebFilter`] exposes a https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/web/csrf/CsrfToken.html[`Mono`] as a `ServerWebExchange` attribute named `org.springframework.security.web.server.csrf.CsrfToken`. ++This means that any view technology can access the `Mono` to expose the expected token as either a <> or a <>. + + [[webflux-csrf-include-subscribe]] + If your view technology does not provide a simple way to subscribe to the `Mono`, a common pattern is to use Spring's `@ControllerAdvice` to expose the `CsrfToken` directly. +-For example, the following code will place the `CsrfToken` on the default attribute name (`_csrf`) used by Spring Security's <> to automatically include the CSRF token as a hidden input. ++The following example places the `CsrfToken` on the default attribute name (`_csrf`) used by Spring Security's <> to automatically include the CSRF token as a hidden input: + + .`CsrfToken` as `@ModelAttribute` + ==== +@@ -155,8 +152,8 @@ Fortunately, Thymeleaf provides <> t + + [[webflux-csrf-include-form]] + ==== Form URL Encoded +-In order to post an HTML form the CSRF token must be included in the form as a hidden input. +-For example, the rendered HTML might look like: ++To post an HTML form, the CSRF token must be included in the form as a hidden input. ++The following example shows what the rendered HTML might look like: + + .CSRF Token HTML + ==== +@@ -168,22 +165,22 @@ For example, the rendered HTML might look like: + ---- + ==== + +-Next we will discuss various ways of including the CSRF token in a form as a hidden input. ++Next, we discuss various ways of including the CSRF token in a form as a hidden input. + + [[webflux-csrf-include-form-auto]] + ===== Automatic CSRF Token Inclusion + +-Spring Security's CSRF support provides integration with Spring's https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/reactive/result/view/RequestDataValueProcessor.html[RequestDataValueProcessor] via its https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/web/reactive/result/view/CsrfRequestDataValueProcessor.html[CsrfRequestDataValueProcessor]. +-In order for `CsrfRequestDataValueProcessor` to work, the `Mono` must be subscribed to and the `CsrfToken` must be <> that matches https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/web/reactive/result/view/CsrfRequestDataValueProcessor.html#DEFAULT_CSRF_ATTR_NAME[DEFAULT_CSRF_ATTR_NAME]. ++Spring Security's CSRF support provides integration with Spring's https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/reactive/result/view/RequestDataValueProcessor.html[`RequestDataValueProcessor`] through its https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/web/reactive/result/view/CsrfRequestDataValueProcessor.html[`CsrfRequestDataValueProcessor`]. ++For `CsrfRequestDataValueProcessor` to work, the `Mono` must be subscribed to and the `CsrfToken` must be <> that matches https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/web/reactive/result/view/CsrfRequestDataValueProcessor.html#DEFAULT_CSRF_ATTR_NAME[`DEFAULT_CSRF_ATTR_NAME`]. + +-Fortunately, Thymeleaf https://www.thymeleaf.org/doc/tutorials/2.1/thymeleafspring.html#integration-with-requestdatavalueprocessor[provides support] to take care of all the boilerplate for you by integrating with `RequestDataValueProcessor` to ensure that forms that have an unsafe HTTP method (i.e. post) will automatically include the actual CSRF token. ++Fortunately, Thymeleaf https://www.thymeleaf.org/doc/tutorials/2.1/thymeleafspring.html#integration-with-requestdatavalueprocessor[takes care of all the boilerplate] for you by integrating with `RequestDataValueProcessor` to ensure that forms that have an unsafe HTTP method (POST) automatically include the actual CSRF token. + + [[webflux-csrf-include-form-attr]] + ===== CsrfToken Request Attribute + + If the <> for including the actual CSRF token in the request do not work, you can take advantage of the fact that the `Mono` <> as a `ServerWebExchange` attribute named `org.springframework.security.web.server.csrf.CsrfToken`. + +-The Thymeleaf sample below assumes that you <> the `CsrfToken` on an attribute named `_csrf`. ++The following Thymeleaf sample assumes that you <> the `CsrfToken` on an attribute named `_csrf`: + + .CSRF Token in Form with Request Attribute + ==== +@@ -202,19 +199,19 @@ The Thymeleaf sample below assumes that you <> to store the expected CSRF token in a cookie. +-By storing the expected CSRF in a cookie, JavaScript frameworks like https://docs.angularjs.org/api/ng/service/$http#cross-site-request-forgery-xsrf-protection[AngularJS] will automatically include the actual CSRF token in the HTTP request headers. ++You can <> Spring Security to store the expected CSRF token in a cookie. ++By storing the expected CSRF in a cookie, JavaScript frameworks, such as https://docs.angularjs.org/api/ng/service/$http#cross-site-request-forgery-xsrf-protection[AngularJS], automatically include the actual CSRF token in the HTTP request headers. + + [[webflux-csrf-include-ajax-meta]] +-===== Meta tags ++===== Meta Tags + + An alternative pattern to <> is to include the CSRF token within your `meta` tags. + The HTML might look something like this: +@@ -233,8 +230,8 @@ The HTML might look something like this: + ---- + ==== + +-Once the meta tags contained the CSRF token, the JavaScript code would read the meta tags and include the CSRF token as a header. +-If you were using jQuery, this could be done with the following: ++Once the meta tags contain the CSRF token, the JavaScript code can read the meta tags and include the CSRF token as a header. ++If you use jQuery, you could read the meta tags with the following code: + + .AJAX send CSRF Token + ==== +@@ -250,8 +247,8 @@ $(function () { + ---- + ==== + +-The sample below assumes that you <> the `CsrfToken` on an attribute named `_csrf`. +-An example of doing this with Thymeleaf is shown below: ++The following sample assumes that you <> the `CsrfToken` on an attribute named `_csrf`. ++The following example does this with Thymeleaf: + + .CSRF meta tag JSP + ==== +@@ -272,28 +269,28 @@ An example of doing this with Thymeleaf is shown below: + == CSRF Considerations + There are a few special considerations to consider when implementing protection against CSRF attacks. + This section discusses those considerations as it pertains to WebFlux environments. +-Refer to <> for a more general discussion. ++See <> for a more general discussion. + + + [[webflux-considerations-csrf-login]] + === Logging In + +-It is important to <> requests to protect against forging log in attempts. +-Spring Security's WebFlux support does this out of the box. ++You should <> requests to protect against forged login attempts. ++Spring Security's WebFlux support automatically does this. + + [[webflux-considerations-csrf-logout]] + === Logging Out + +-It is important to <> requests to protect against forging log out attempts. +-By default Spring Security's `LogoutWebFilter` only processes HTTP post requests. +-This ensures that log out requires a CSRF token and that a malicious user cannot forcibly log out your users. ++You should <> requests to protect against forging logout attempts. ++By default, Spring Security's `LogoutWebFilter` processes only HTTP post requests. ++This ensures that logout requires a CSRF token and that a malicious user cannot forcibly log out your users. + + The easiest approach is to use a form to log out. +-If you really want a link, you can use JavaScript to have the link perform a POST (i.e. maybe on a hidden form). +-For browsers with JavaScript that is disabled, you can optionally have the link take the user to a log out confirmation page that will perform the POST. ++If you really want a link, you can use JavaScript to have the link perform a POST (maybe on a hidden form). ++For browsers with JavaScript that is disabled, you can optionally have the link take the user to a logout confirmation page that performs the POST. + +-If you really want to use HTTP GET with logout you can do so, but remember this is generally not recommended. +-For example, the following Java Configuration will perform logout with the URL `/logout` is requested with any HTTP method: ++If you really want to use HTTP GET with logout, you can do so, but remember that doing so is generally not recommended. ++For example, the following Java Configuration logs out when the `/logout` URL is requested with any HTTP method: + + // FIXME: This should be a link to log out documentation + +@@ -330,16 +327,16 @@ fun springSecurityFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain + [[webflux-considerations-csrf-timeouts]] + === CSRF and Session Timeouts + +-By default Spring Security stores the CSRF token in the `WebSession`. +-This can lead to a situation where the session expires which means there is not an expected CSRF token to validate against. ++By default, Spring Security stores the CSRF token in the `WebSession`. ++This arrangement can lead to a situation where the session expires, which means that there is not an expected CSRF token to validate against. + +-We've already discussed <> to session timeouts. ++We have already discussed <> to session timeouts. + This section discusses the specifics of CSRF timeouts as it pertains to the WebFlux support. + +-It is simple to change storage of the expected CSRF token to be in a cookie. +-For details, refer to the <> section. ++You can change storage of the expected CSRF token to be in a cookie. ++For details, see the <> section. + +-// FIXME: We should add a custom AccessDeniedHandler section in the reference and update the links above ++// FIXME: We should add a custom AccessDeniedHandler section in the reference and update the earlier links + + // FIXME: We need a WebFlux multipart body vs action story. WebFlux always has multipart enabled. + [[webflux-csrf-considerations-multipart]] +@@ -347,17 +344,14 @@ For details, refer to the <> section. + We have <> how protecting multipart requests (file uploads) from CSRF attacks causes a https://en.wikipedia.org/wiki/Chicken_or_the_egg[chicken and the egg] problem. + This section discusses how to implement placing the CSRF token in the <> and <> within a WebFlux application. + +-[NOTE] +-==== +-More information about using multipart forms with Spring can be found within the https://docs.spring.io/spring/docs/5.2.x/spring-framework-reference/web-reactive.html#webflux-multipart[Multipart Data] section of the Spring reference. +-==== ++NOTE: For more information about using multipart forms with Spring, see the https://docs.spring.io/spring/docs/5.2.x/spring-framework-reference/web-reactive.html#webflux-multipart[Multipart Data] section of the Spring reference. + + [[webflux-csrf-considerations-multipart-body]] + ==== Place CSRF Token in the Body + + We have <> the trade-offs of placing the CSRF token in the body. + +-In a WebFlux application, this can be configured with the following configuration: ++In a WebFlux application, you can do so with the following configuration: + + .Enable obtaining CSRF token from multipart/form-data + ==== +@@ -393,7 +387,7 @@ fun springSecurityFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain + + We have <> the trade-offs of placing the CSRF token in the URL. + Since the `CsrfToken` is exposed as an `ServerHttpRequest` <>, we can use that to create an `action` with the CSRF token in it. +-An example with Thymeleaf is shown below: ++The following example uses Thymeleaf: + + .CSRF Token in Action + ==== +@@ -409,4 +403,5 @@ An example with Thymeleaf is shown below: + === HiddenHttpMethodFilter + We have <> overriding the HTTP method. + +-In a Spring WebFlux application, overriding the HTTP method is done using https://docs.spring.io/spring-framework/docs/5.2.x/javadoc-api/org/springframework/web/filter/reactive/HiddenHttpMethodFilter.html[HiddenHttpMethodFilter]. ++In a Spring WebFlux application, overriding the HTTP method is done by using https://docs.spring.io/spring-framework/docs/5.2.x/javadoc-api/org/springframework/web/filter/reactive/HiddenHttpMethodFilter.html[`HiddenHttpMethodFilter`]. ++// FIXME: Add an example. +diff --git a/docs/manual/src/docs/asciidoc/_includes/reactive/exploits/headers.adoc b/docs/manual/src/docs/asciidoc/_includes/reactive/exploits/headers.adoc +index 2ee82ad2a6..64b86ebda1 100644 +--- a/docs/manual/src/docs/asciidoc/_includes/reactive/exploits/headers.adoc ++++ b/docs/manual/src/docs/asciidoc/_includes/reactive/exploits/headers.adoc +@@ -1,19 +1,19 @@ + [[webflux-headers]] + = Security HTTP Response Headers + +-<> can be used to increase the security of web applications. +-This section is dedicated to WebFlux based support for Security HTTP Response Headers. ++You can use <> to increase the security of web applications. ++This section is dedicated to WebFlux-based support for Security HTTP Response Headers. + + [[webflux-headers-default]] + == Default Security Headers + + Spring Security provides a <> to provide secure defaults. +-While each of these headers are considered best practice, it should be noted that not all clients utilize the headers, so additional testing is encouraged. ++While each of these headers are considered best practice, it should be noted that not all clients use the headers, so additional testing is encouraged. + + You can customize specific headers. +-For example, assume that you want the defaults except you wish to specify `SAMEORIGIN` for <>. ++For example, assume that you want the defaults but you wish to specify `SAMEORIGIN` for <>. + +-You can easily do this with the following Configuration: ++You can do so with the following configuration: + + .Customize Default Security Headers + ==== +@@ -50,8 +50,7 @@ fun webFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain { + ---- + ==== + +-If you do not want the defaults to be added and want explicit control over what should be used, you can disable the defaults. +-An example is provided below: ++If you do not want the defaults to be added and want explicit control over what should be used, you can disable the defaults: + + .Disable HTTP Security Response Headers + ==== +@@ -85,13 +84,13 @@ fun webFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain { + [[webflux-headers-cache-control]] + == Cache Control + +-Spring Security includes <> headers by default. ++Spring Security includes <> headers by default. + +-However, if you actually want to cache specific responses, your application can selectively add them to the https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/http/server/reactive/ServerHttpResponse.html[ServerHttpResponse] to override the header set by Spring Security. +-This is useful to ensure things like CSS, JavaScript, and images are properly cached. ++However, if you actually want to cache specific responses, your application can selectively add them to the https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/http/server/reactive/ServerHttpResponse.html[`ServerHttpResponse`] to override the header set by Spring Security. ++This is useful to ensure that such things as CSS, JavaScript, and images are properly cached. + +-When using Spring WebFluxZz, this is typically done within your configuration. +-Details on how to do this can be found in the https://docs.spring.io/spring/docs/5.0.0.RELEASE/spring-framework-reference/web-reactive.html#webflux-config-static-resources[Static Resources] portion of the Spring Reference documentation ++When using Spring WebFlux, you typically do so within your configuration. ++You can find details on how to do so in the https://docs.spring.io/spring/docs/5.0.0.RELEASE/spring-framework-reference/web-reactive.html#webflux-config-static-resources[Static Resources] portion of the Spring Reference documentation + + If necessary, you can also disable Spring Security's cache control HTTP response headers. + +@@ -131,8 +130,8 @@ fun webFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain { + + [[webflux-headers-content-type-options]] + == Content Type Options +-Spring Security includes <> headers by default. +-However, you can disable it with: ++By default, Spring Security includes <> headers. ++However, you can disable it: + + .Content Type Options Disabled + ==== +@@ -169,9 +168,9 @@ fun webFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain { + + [[webflux-headers-hsts]] + == HTTP Strict Transport Security (HSTS) +-Spring Security provides the <> header by default. ++By default, Spring Security provides the <> header. + However, you can customize the results explicitly. +-For example, the following is an example of explicitly providing HSTS: ++For example, the following example explicitly provides HSTS: + + .Strict Transport Security + ==== +@@ -214,9 +213,9 @@ fun webFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain { + + [[webflux-headers-frame-options]] + == X-Frame-Options +-By default, Spring Security disables rendering within an iframe using <>. ++By default, Spring Security disables rendering within an iframe by using <>. + +-You can customize frame options to use the same origin using the following: ++You can customize frame options to use the same origin: + + .X-Frame-Options: SAMEORIGIN + ==== +@@ -255,8 +254,8 @@ fun webFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain { + + [[webflux-headers-xss-protection]] + == X-XSS-Protection +-By default, Spring Security instructs browsers to block reflected XSS attacks using the <. +-You can disable `X-XSS-Protection` with the following Configuration: ++By default, Spring Security instructs browsers to block reflected XSS attacks by using the <. ++You can disable `X-XSS-Protection`: + + .X-XSS-Protection Customization + ==== +@@ -293,10 +292,10 @@ fun webFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain { + + [[webflux-headers-csp]] + == Content Security Policy (CSP) +-Spring Security does not add <> by default, because a reasonable default is impossible to know without context of the application. +-The web application author must declare the security policy(s) to enforce and/or monitor for the protected resources. ++By default, Spring Security does not add <>, because a reasonable default is impossible to know without the context of the application. ++The web application author must declare the security policies to enforce and monitor the protected resources. + +-For example, given the following security policy: ++For example, consider the following security policy: + + .Content Security Policy Example + ==== +@@ -306,7 +305,7 @@ Content-Security-Policy: script-src 'self' https://trustedscripts.example.com; o + ---- + ==== + +-You can enable the CSP header as shown below: ++Given the preceding policy, you can enable the CSP header: + + .Content Security Policy + ==== +@@ -385,8 +384,8 @@ fun webFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain { + [[webflux-headers-referrer]] + == Referrer Policy + +-Spring Security does not add <> headers by default. +-You can enable the Referrer Policy header using configuration as shown below: ++By default, Spring Security does not add <> headers. ++You can enable the Referrer Policy header: + + .Referrer Policy Configuration + ==== +@@ -427,8 +426,8 @@ fun webFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain { + [[webflux-headers-feature]] + == Feature Policy + +-Spring Security does not add <> headers by default. +-The following `Feature-Policy` header: ++By default, Spring Security does not add <> headers. ++Consider the following `Feature-Policy` header: + + .Feature-Policy Example + ==== +@@ -438,7 +437,7 @@ Feature-Policy: geolocation 'self' + ---- + ==== + +-You can enable the Feature Policy header as shown below: ++You can enable the preceding Feature Policy header: + + .Feature-Policy Configuration + ==== +@@ -475,8 +474,8 @@ fun webFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain { + [[webflux-headers-permissions]] + == Permissions Policy + +-Spring Security does not add <> headers by default. +-The following `Permissions-Policy` header: ++By default, Spring Security does not add <> headers. ++Consider the following `Permissions-Policy` header: + + .Permissions-Policy Example + ==== +@@ -486,7 +485,7 @@ Permissions-Policy: geolocation=(self) + ---- + ==== + +-You can enable the Permissions Policy header as shown below: ++You can enable the preceding Permissions Policy header: + + .Permissions-Policy Configuration + ==== +@@ -527,8 +526,8 @@ fun webFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain { + [[webflux-headers-clear-site-data]] + == Clear Site Data + +-Spring Security does not add <> headers by default. +-The following Clear-Site-Data header: ++By default, Spring Security does not add <> headers. ++Consider the following `Clear-Site-Data` header: + + .Clear-Site-Data Example + ==== +@@ -537,7 +536,7 @@ Clear-Site-Data: "cache", "cookies" + ---- + ==== + +-can be sent on log out with the following configuration: ++You can send the `Clear-Site-Data` header on logout: + + .Clear-Site-Data Configuration + ==== +diff --git a/docs/manual/src/docs/asciidoc/_includes/reactive/exploits/http.adoc b/docs/manual/src/docs/asciidoc/_includes/reactive/exploits/http.adoc +index 387a05a719..3022716e87 100644 +--- a/docs/manual/src/docs/asciidoc/_includes/reactive/exploits/http.adoc ++++ b/docs/manual/src/docs/asciidoc/_includes/reactive/exploits/http.adoc +@@ -1,16 +1,16 @@ + [[webflux-http]] + = HTTP + +-All HTTP based communication should be protected <>. ++All HTTP-based communication should be protected with <>. + +-Below you can find details around WebFlux specific features that assist with HTTPS usage. ++This section covers details about using WebFlux-specific features that assist with HTTPS usage. + + [[webflux-http-redirect]] + == Redirect to HTTPS + +-If a client makes a request using HTTP rather than HTTPS, Spring Security can be configured to redirect to HTTPS. ++If a client makes a request using HTTP rather than HTTPS, you can configure Spring Security to redirect to HTTPS. + +-For example, the following Java configuration will redirect any HTTP requests to HTTPS: ++The following Java configuration redirects any HTTP requests to HTTPS: + + .Redirect to HTTPS + ==== +@@ -39,9 +39,9 @@ fun springSecurityFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain + ---- + ==== + +-The configuration can easily be wrapped around an if statement to only be turned on in production. +-Alternatively, it can be enabled by looking for a property about the request that only happens in production. +-For example, if the production environment adds a header named `X-Forwarded-Proto` the following Java Configuration could be used: ++You can wrap the configuration can be wrapped around an `if` statement to be turned on only in production. ++Alternatively, you can enable it by looking for a property about the request that happens only in production. ++For example, if the production environment adds a header named `X-Forwarded-Proto`, you should use the following Java Configuration: + + .Redirect to HTTPS when X-Forwarded + ==== +diff --git a/docs/manual/src/docs/asciidoc/_includes/reactive/method.adoc b/docs/manual/src/docs/asciidoc/_includes/reactive/method.adoc +index 08e8ba2fa7..f2f60c3caa 100644 +--- a/docs/manual/src/docs/asciidoc/_includes/reactive/method.adoc ++++ b/docs/manual/src/docs/asciidoc/_includes/reactive/method.adoc +@@ -1,14 +1,13 @@ + [[jc-erms]] + = EnableReactiveMethodSecurity + +-Spring Security supports method security using https://projectreactor.io/docs/core/release/reference/#context[Reactor's Context] which is setup using `ReactiveSecurityContextHolder`. +-For example, this demonstrates how to retrieve the currently logged in user's message. ++Spring Security supports method security by using https://projectreactor.io/docs/core/release/reference/#context[Reactor's Context], which is set up by `ReactiveSecurityContextHolder`. ++The following example shows how to retrieve the currently logged in user's message: + + [NOTE] + ==== + For this to work the return type of the method must be a `org.reactivestreams.Publisher` (i.e. `Mono`/`Flux`) or the function must be a Kotlin coroutine function. + This is necessary to integrate with Reactor's `Context`. +-==== + + ==== + .Java +@@ -27,6 +26,7 @@ StepVerifier.create(messageByUsername) + .expectNext("Hi user") + .verifyComplete(); + ---- ++==== + + .Kotlin + [source,kotlin,role="secondary"] +@@ -55,6 +55,7 @@ Mono findMessageByUsername(String username) { + return Mono.just("Hi " + username); + } + ---- ++==== + + .Kotlin + [source,kotlin,role="secondary"] +@@ -88,6 +89,7 @@ public class SecurityConfig { + } + } + ---- ++==== + + .Kotlin + [source,kotlin,role="secondary"] +@@ -125,6 +127,7 @@ public class HelloWorldMessageService { + } + } + ---- ++==== + + .Kotlin + [source,kotlin,role="secondary"] +@@ -162,7 +165,7 @@ It is important to note that any of the expressions in standard method security + However, at this time we only support return type of `Boolean` or `boolean` of the expression. + This means that the expression must not block. + +-When integrating with <>, the Reactor Context is automatically established by Spring Security according to the authenticated user. ++When integrating with <>, the Reactor Context is automatically established by Spring Security according to the authenticated user: + + ==== + .Java +@@ -198,8 +201,8 @@ public class SecurityConfig { + return new MapReactiveUserDetailsService(rob, admin); + } + } +- + ---- ++==== + + .Kotlin + [source,kotlin,role="secondary"] +diff --git a/docs/manual/src/docs/asciidoc/_includes/reactive/oauth2/access-token.adoc b/docs/manual/src/docs/asciidoc/_includes/reactive/oauth2/access-token.adoc +index ac732704a2..9c1fc38adf 100644 +--- a/docs/manual/src/docs/asciidoc/_includes/reactive/oauth2/access-token.adoc ++++ b/docs/manual/src/docs/asciidoc/_includes/reactive/oauth2/access-token.adoc +@@ -2,8 +2,9 @@ + = OAuth2 Client + + Spring Security's OAuth Support allows obtaining an access token without authenticating. +-A basic configuration with Spring Boot can be seen below: ++The following example shows basic configuration with Spring Boot: + ++==== + [source,yml] + ---- + spring: +@@ -16,10 +17,11 @@ spring: + client-secret: replace-with-client-secret + scope: read:user,public_repo + ---- ++==== + +-You will need to replace the `client-id` and `client-secret` with values registered with GitHub. ++You need to replace the `client-id` and `client-secret` with values registered with GitHub. + +-The next step is to instruct Spring Security that you wish to act as an OAuth2 Client so that you can obtain an access token. ++The next step is to instruct Spring Security that you wish to act as an OAuth2 Client so that you can obtain an access token: + + .OAuth2 Client + ==== +@@ -35,7 +37,6 @@ SecurityWebFilterChain configure(ServerHttpSecurity http) throws Exception { + } + ---- + +- + .Kotlin + [source,kotlin,role="secondary"] + ---- +@@ -49,4 +50,4 @@ fun webFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain { + ---- + ==== + +-You can now leverage Spring Security's <> or <> support to obtain and use the access token. ++You can now use Spring Security's <> or <> support to obtain and use the access token. +diff --git a/docs/manual/src/docs/asciidoc/_includes/reactive/oauth2/login.adoc b/docs/manual/src/docs/asciidoc/_includes/reactive/oauth2/login.adoc +index 5883986d8a..71c262889d 100644 +--- a/docs/manual/src/docs/asciidoc/_includes/reactive/oauth2/login.adoc ++++ b/docs/manual/src/docs/asciidoc/_includes/reactive/oauth2/login.adoc +@@ -1,9 +1,9 @@ + [[webflux-oauth2-login]] + = OAuth 2.0 Login + +-The OAuth 2.0 Login feature provides an application with the capability to have users log in to the application by using their existing account at an OAuth 2.0 Provider (e.g. ++The OAuth 2.0 Login feature provides an application with the ability to have users log in to the application by using their existing account at an OAuth 2.0 Provider (such as + GitHub) or OpenID Connect 1.0 Provider (such as Google). +-OAuth 2.0 Login implements the use cases: "Login with Google" or "Login with GitHub". ++OAuth 2.0 Login implements the "Login with Google" or "Login with GitHub" use cases. + + NOTE: OAuth 2.0 Login is implemented by using the *Authorization Code Grant*, as specified in the https://tools.ietf.org/html/rfc6749#section-4.1[OAuth 2.0 Authorization Framework] and https://openid.net/specs/openid-connect-core-1_0.html#CodeFlowAuth[OpenID Connect Core 1.0]. + +@@ -12,38 +12,38 @@ NOTE: OAuth 2.0 Login is implemented by using the *Authorization Code Grant*, as + + Spring Boot 2.0 brings full auto-configuration capabilities for OAuth 2.0 Login. + +-This section shows how to configure the {gh-samples-url}/boot/oauth2login-webflux[*OAuth 2.0 Login WebFlux sample*] using _Google_ as the _Authentication Provider_ and covers the following topics: ++This section shows how to configure the {gh-samples-url}/boot/oauth2login-webflux[*OAuth 2.0 Login WebFlux sample*] by using _Google_ as the _Authentication Provider_ and covers the following topics: + +-* <> +-* <> +-* <> +-* <> ++* <> ++* <> ++* <> ++* <> + + + [[webflux-oauth2-login-sample-setup]] +-=== Initial setup ++=== Initial Setup + + To use Google's OAuth 2.0 authentication system for login, you must set up a project in the Google API Console to obtain OAuth 2.0 credentials. + + NOTE: https://developers.google.com/identity/protocols/OpenIDConnect[Google's OAuth 2.0 implementation] for authentication conforms to the https://openid.net/connect/[OpenID Connect 1.0] specification and is https://openid.net/certification/[OpenID Certified]. + +-Follow the instructions on the https://developers.google.com/identity/protocols/OpenIDConnect[OpenID Connect] page, starting in the section, "Setting up OAuth 2.0". ++Follow the instructions on the https://developers.google.com/identity/protocols/OpenIDConnect[OpenID Connect] page, starting in the "`Setting up OAuth 2.0`" section. + +-After completing the "Obtain OAuth 2.0 credentials" instructions, you should have a new OAuth Client with credentials consisting of a Client ID and a Client Secret. ++After completing the "`Obtain OAuth 2.0 credentials`" instructions, you should have a new OAuth Client with credentials that consist of a Client ID and a Client Secret. + + [[webflux-oauth2-login-sample-redirect]] +-=== Setting the redirect URI ++=== Setting the Redirect URI + +-The redirect URI is the path in the application that the end-user's user-agent is redirected back to after they have authenticated with Google and have granted access to the OAuth Client _(<>)_ on the Consent page. ++The redirect URI is the path in the application that the end-user's user-agent is redirected back to after they have authenticated with Google and have been granted access to the OAuth Client (<>) on the consent page. + +-In the "Set a redirect URI" sub-section, ensure that the *Authorized redirect URIs* field is set to `http://localhost:8080/login/oauth2/code/google`. ++In the "`Set a redirect URI`" sub-section, ensure that the *Authorized redirect URIs* field is set to `http://localhost:8080/login/oauth2/code/google`. + + TIP: The default redirect URI template is `+{baseUrl}/login/oauth2/code/{registrationId}+`. + The *_registrationId_* is a unique identifier for the <>. + For our example, the `registrationId` is `google`. + +-IMPORTANT: If the OAuth Client is running behind a proxy server, it is recommended to check <> to ensure the application is correctly configured. +-Also, see the supported <> for `redirect-uri`. ++IMPORTANT: If the OAuth Client runs behind a proxy server, we recommend checking the <> to ensure the application is correctly configured. ++Also, see the supported <> for the `redirect-uri`. + + [[webflux-oauth2-login-sample-config]] + === Configure `application.yml` +@@ -53,6 +53,8 @@ To do so: + + . Go to `application.yml` and set the following configuration: + + ++.OAuth Client properties ++==== + [source,yaml] + ---- + spring: +@@ -65,8 +67,6 @@ spring: + client-secret: google-client-secret + ---- + + +-.OAuth Client properties +-==== + <1> `spring.security.oauth2.client.registration` is the base property prefix for OAuth Client properties. + <2> Following the base property prefix is the ID for the <>, such as google. + ==== +@@ -75,7 +75,7 @@ spring: + + + [[webflux-oauth2-login-sample-start]] +-=== Boot up the application ++=== Boot the Application + + Launch the Spring Boot 2.0 sample and go to `http://localhost:8080`. + You are then redirected to the default _auto-generated_ login page, which displays a link for Google. +@@ -92,7 +92,7 @@ At this point, the OAuth Client retrieves your email address and basic profile i + == Using OpenID Provider Configuration + + For well known providers, Spring Security provides the necessary defaults for the OAuth Authorization Provider's configuration. +-If you are working with your own Authorization Provider that supports https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfig[OpenID Provider Configuration] or https://tools.ietf.org/html/rfc8414#section-3[Authorization Server Metadata], the https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfigurationResponse[OpenID Provider Configuration Response]'s `issuer-uri` can be used to configure the application. ++If you are working with your own Authorization Provider that supports https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfig[OpenID Provider Configuration] or https://tools.ietf.org/html/rfc8414#section-3[Authorization Server Metadata], you can use the https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfigurationResponse[OpenID Provider Configuration Response]'s `issuer-uri` to configure the application. + + [source,yml] + ---- +@@ -109,10 +109,9 @@ spring: + client-secret: 6cea952f-10d0-4d00-ac79-cc865820dc2c + ---- + +-The `issuer-uri` instructs Spring Security to query in series the endpoints `https://idp.example.com/auth/realms/demo/.well-known/openid-configuration`, `https://idp.example.com/.well-known/openid-configuration/auth/realms/demo`, or `https://idp.example.com/.well-known/oauth-authorization-server/auth/realms/demo` to discover the configuration. ++The `issuer-uri` instructs Spring Security to query, in series, the following endpoints to discover the configuration: `https://idp.example.com/auth/realms/demo/.well-known/openid-configuration`, `https://idp.example.com/.well-known/openid-configuration/auth/realms/demo`, or `https://idp.example.com/.well-known/oauth-authorization-server/auth/realms/demo`. + +-[NOTE] +-Spring Security will query the endpoints one at a time, stopping at the first that gives a 200 response. ++NOTE: Spring Security queries the endpoints one at a time, stopping at the first that gives a 200 response. + + The `client-id` and `client-secret` are linked to the provider because `keycloak` is used for both the provider and the registration. + +@@ -120,7 +119,7 @@ The `client-id` and `client-secret` are linked to the provider because `keycloak + [[webflux-oauth2-login-explicit]] + == Explicit OAuth2 Login Configuration + +-A minimal OAuth2 Login configuration is shown below: ++The following listing shows a minimal OAuth2 Login configuration: + + .Minimal OAuth2 Login + ==== +@@ -168,7 +167,7 @@ fun webFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain { + ---- + ==== + +-Additional configuration options can be seen below: ++The following example shows additional configuration options: + + .Advanced OAuth2 Login + ==== +@@ -206,7 +205,7 @@ fun webFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain { + ---- + ==== + +-You may register a `GrantedAuthoritiesMapper` `@Bean` to have it automatically applied to the default configuration, as shown in the following example: ++You can register a `GrantedAuthoritiesMapper` `@Bean` to have it be automatically applied to the default configuration: + + .GrantedAuthoritiesMapper Bean + ==== +diff --git a/docs/manual/src/docs/asciidoc/_includes/reactive/oauth2/resource-server.adoc b/docs/manual/src/docs/asciidoc/_includes/reactive/oauth2/resource-server.adoc +index 1c5ff1821b..73a5ef683c 100644 +--- a/docs/manual/src/docs/asciidoc/_includes/reactive/oauth2/resource-server.adoc ++++ b/docs/manual/src/docs/asciidoc/_includes/reactive/oauth2/resource-server.adoc +@@ -1,35 +1,33 @@ + [[webflux-oauth2-resource-server]] + = OAuth 2.0 Resource Server + +-Spring Security supports protecting endpoints using two forms of OAuth 2.0 https://tools.ietf.org/html/rfc6750.html[Bearer Tokens]: ++Spring Security supports protecting endpoints by offering two forms of OAuth 2.0 https://tools.ietf.org/html/rfc6750.html[Bearer Tokens]: + + * https://tools.ietf.org/html/rfc7519[JWT] + * Opaque Tokens + + This is handy in circumstances where an application has delegated its authority management to an https://tools.ietf.org/html/rfc6749[authorization server] (for example, Okta or Ping Identity). +-This authorization server can be consulted by resource servers to authorize requests. ++Resource serves can consult this authorization server to authorize requests. + +-[NOTE] +-==== +-A complete working example for {gh-samples-url}/boot/oauth2resourceserver-webflux[*JWTs*] is available in the {gh-samples-url}[Spring Security repository]. +-==== ++NOTE: A complete working example for {gh-samples-url}/boot/oauth2resourceserver-webflux[JWT] is available in the {gh-samples-url}[Spring Security repository]. + + [[webflux-oauth2resourceserver-jwt-minimaldependencies]] + == Minimal Dependencies for JWT + + Most Resource Server support is collected into `spring-security-oauth2-resource-server`. +-However, the support for decoding and verifying JWTs is in `spring-security-oauth2-jose`, meaning that both are necessary in order to have a working resource server that supports JWT-encoded Bearer Tokens. ++However, the support for decoding and verifying JWTs is in `spring-security-oauth2-jose`, meaning that both are necessary to have a working resource server that supports JWT-encoded Bearer Tokens. + + [[webflux-oauth2resourceserver-jwt-minimalconfiguration]] + == Minimal Configuration for JWTs + + When using https://spring.io/projects/spring-boot[Spring Boot], configuring an application as a resource server consists of two basic steps. +-First, include the needed dependencies and second, indicate the location of the authorization server. ++First, include the needed dependencies. Second, indicate the location of the authorization server. + + === Specifying the Authorization Server + +-In a Spring Boot application, to specify which authorization server to use, simply do: ++In a Spring Boot application, you need to specify which authorization server to use: + ++==== + [source,yml] + ---- + spring: +@@ -39,65 +37,63 @@ spring: + jwt: + issuer-uri: https://idp.example.com/issuer + ---- ++==== + +-Where `https://idp.example.com/issuer` is the value contained in the `iss` claim for JWT tokens that the authorization server will issue. +-Resource Server will use this property to further self-configure, discover the authorization server's public keys, and subsequently validate incoming JWTs. ++Where `https://idp.example.com/issuer` is the value contained in the `iss` claim for JWT tokens that the authorization server issues. ++This resource server uses this property to further self-configure, discover the authorization server's public keys, and subsequently validate incoming JWTs. + +-[NOTE] +-To use the `issuer-uri` property, it must also be true that one of `https://idp.example.com/issuer/.well-known/openid-configuration`, `https://idp.example.com/.well-known/openid-configuration/issuer`, or `https://idp.example.com/.well-known/oauth-authorization-server/issuer` is a supported endpoint for the authorization server. ++NOTE: To use the `issuer-uri` property, it must also be true that one of `https://idp.example.com/issuer/.well-known/openid-configuration`, `https://idp.example.com/.well-known/openid-configuration/issuer`, or `https://idp.example.com/.well-known/oauth-authorization-server/issuer` is a supported endpoint for the authorization server. + This endpoint is referred to as a https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfig[Provider Configuration] endpoint or a https://tools.ietf.org/html/rfc8414#section-3[Authorization Server Metadata] endpoint. + +-And that's it! +- + === Startup Expectations + +-When this property and these dependencies are used, Resource Server will automatically configure itself to validate JWT-encoded Bearer Tokens. ++When this property and these dependencies are used, Resource Server automatically configures itself to validate JWT-encoded Bearer Tokens. + + It achieves this through a deterministic startup process: + +-1. Hit the Provider Configuration or Authorization Server Metadata endpoint, processing the response for the `jwks_url` property +-2. Configure the validation strategy to query `jwks_url` for valid public keys +-3. Configure the validation strategy to validate each JWTs `iss` claim against `https://idp.example.com`. ++. Hit the Provider Configuration or Authorization Server Metadata endpoint, processing the response for the `jwks_url` property. ++. Configure the validation strategy to query `jwks_url` for valid public keys. ++. Configure the validation strategy to validate each JWT's `iss` claim against `https://idp.example.com`. + +-A consequence of this process is that the authorization server must be up and receiving requests in order for Resource Server to successfully start up. ++A consequence of this process is that the authorization server must be receiving requests in order for Resource Server to successfully start up. + +-[NOTE] +-If the authorization server is down when Resource Server queries it (given appropriate timeouts), then startup will fail. ++NOTE: If the authorization server is down when Resource Server queries it (given appropriate timeouts), then startup fails. + + === Runtime Expectations + +-Once the application is started up, Resource Server will attempt to process any request containing an `Authorization: Bearer` header: ++Once the application is started up, Resource Server tries to process any request that contains an `Authorization: Bearer` header: + ++==== + [source,html] + ---- + GET / HTTP/1.1 + Authorization: Bearer some-token-value # Resource Server will process this + ---- ++==== + +-So long as this scheme is indicated, Resource Server will attempt to process the request according to the Bearer Token specification. ++So long as this scheme is indicated, Resource Server tries to process the request according to the Bearer Token specification. + +-Given a well-formed JWT, Resource Server will: ++Given a well-formed JWT, Resource Server: + +-1. Validate its signature against a public key obtained from the `jwks_url` endpoint during startup and matched against the JWTs header +-2. Validate the JWTs `exp` and `nbf` timestamps and the JWTs `iss` claim, and +-3. Map each scope to an authority with the prefix `SCOPE_`. ++1. Validates its signature against a public key obtained from the `jwks_url` endpoint during startup and matched against the JWTs header. ++2. Validates the JWTs `exp` and `nbf` timestamps and the JWTs `iss` claim. ++3. Maps each scope to an authority with the prefix `SCOPE_`. + +-[NOTE] +-As the authorization server makes available new keys, Spring Security will automatically rotate the keys used to validate the JWT tokens. ++NOTE: As the authorization server makes available new keys, Spring Security automatically rotates the keys used to validate the JWT tokens. + +-The resulting `Authentication#getPrincipal`, by default, is a Spring Security `Jwt` object, and `Authentication#getName` maps to the JWT's `sub` property, if one is present. ++By default, the resulting `Authentication#getPrincipal` is a Spring Security `Jwt` object, and `Authentication#getName` maps to the JWT's `sub` property, if one is present. + + From here, consider jumping to: + +-<> +- +-<> ++* <> ++* <> + + [[webflux-oauth2resourceserver-jwt-jwkseturi]] + === Specifying the Authorization Server JWK Set Uri Directly + +-If the authorization server doesn't support any configuration endpoints, or if Resource Server must be able to start up independently from the authorization server, then the `jwk-set-uri` can be supplied as well: ++If the authorization server does not support any configuration endpoints, or if Resource Server must be able to start up independently from the authorization server, you can supply `jwk-set-uri` as well: + ++==== + [source,yaml] + ---- + spring: +@@ -108,22 +104,21 @@ spring: + issuer-uri: https://idp.example.com + jwk-set-uri: https://idp.example.com/.well-known/jwks.json + ---- ++==== + +-[NOTE] +-The JWK Set uri is not standardized, but can typically be found in the authorization server's documentation ++NOTE: The JWK Set uri is not standardized, but you can typically find it in the authorization server's documentation. + +-Consequently, Resource Server will not ping the authorization server at startup. ++Consequently, Resource Server does not ping the authorization server at startup. + We still specify the `issuer-uri` so that Resource Server still validates the `iss` claim on incoming JWTs. + +-[NOTE] +-This property can also be supplied directly on the <>. ++NOTE: You can supply this property directly on the <>. + + [[webflux-oauth2resourceserver-jwt-sansboot]] + === Overriding or Replacing Boot Auto Configuration + +-There are two `@Bean` s that Spring Boot generates on Resource Server's behalf. ++Spring Boot generates two `@Bean` objects on Resource Server's behalf. + +-The first is a `SecurityWebFilterChain` that configures the app as a resource server. When including `spring-security-oauth2-jose`, this `SecurityWebFilterChain` looks like: ++The first bean is a `SecurityWebFilterChain` that configures the application as a resource server. When including `spring-security-oauth2-jose`, this `SecurityWebFilterChain` looks like: + + .Resource Server SecurityWebFilterChain + ==== +@@ -158,9 +153,9 @@ fun springSecurityFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain + ---- + ==== + +-If the application doesn't expose a `SecurityWebFilterChain` bean, then Spring Boot will expose the above default one. ++If the application does not expose a `SecurityWebFilterChain` bean, Spring Boot exposes the default one (shown in the preceding listing). + +-Replacing this is as simple as exposing the bean within the application: ++To replace it, expose the `@Bean` within the application: + + .Replacing SecurityWebFilterChain + ==== +@@ -199,9 +194,9 @@ fun springSecurityFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain + ---- + ==== + +-The above requires the scope of `message:read` for any URL that starts with `/messages/`. ++The preceding configuration requires the scope of `message:read` for any URL that starts with `/messages/`. + +-Methods on the `oauth2ResourceServer` DSL will also override or replace auto configuration. ++Methods on the `oauth2ResourceServer` DSL also override or replace auto configuration. + + For example, the second `@Bean` Spring Boot creates is a `ReactiveJwtDecoder`, which decodes `String` tokens into validated instances of `Jwt`: + +@@ -226,16 +221,15 @@ fun jwtDecoder(): ReactiveJwtDecoder { + ---- + ==== + +-[NOTE] +-Calling `{security-api-url}org/springframework/security/oauth2/jwt/ReactiveJwtDecoders.html#fromIssuerLocation-java.lang.String-[ReactiveJwtDecoders#fromIssuerLocation]` is what invokes the Provider Configuration or Authorization Server Metadata endpoint in order to derive the JWK Set Uri. +-If the application doesn't expose a `ReactiveJwtDecoder` bean, then Spring Boot will expose the above default one. ++NOTE: Calling `{security-api-url}org/springframework/security/oauth2/jwt/ReactiveJwtDecoders.html#fromIssuerLocation-java.lang.String-[ReactiveJwtDecoders#fromIssuerLocation]` invokes the Provider Configuration or Authorization Server Metadata endpoint to derive the JWK Set URI. ++If the application does not expose a `ReactiveJwtDecoder` bean, Spring Boot exposes the above default one. + +-And its configuration can be overridden using `jwkSetUri()` or replaced using `decoder()`. ++Its configuration can be overridden by using `jwkSetUri()` or replaced by using `decoder()`. + + [[webflux-oauth2resourceserver-jwt-jwkseturi-dsl]] + ==== Using `jwkSetUri()` + +-An authorization server's JWK Set Uri can be configured <> or it can be supplied in the DSL: ++You can configure an authorization server's JWK Set URI <> or supply it in the DSL: + + ==== + .Java +@@ -280,7 +274,7 @@ Using `jwkSetUri()` takes precedence over any configuration property. + [[webflux-oauth2resourceserver-jwt-decoder-dsl]] + ==== Using `decoder()` + +-More powerful than `jwkSetUri()` is `decoder()`, which will completely replace any Boot auto configuration of `JwtDecoder`: ++`decoder()` is more powerful than `jwkSetUri()`, because it completely replaces any Spring Boot auto-configuration of `JwtDecoder`: + + ==== + .Java +@@ -320,12 +314,12 @@ fun springSecurityFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain + ---- + ==== + +-This is handy when deeper configuration, like <>, is necessary. ++This is handy when you need deeper configuration, such as <>. + + [[webflux-oauth2resourceserver-decoder-bean]] + ==== Exposing a `ReactiveJwtDecoder` `@Bean` + +-Or, exposing a `ReactiveJwtDecoder` `@Bean` has the same effect as `decoder()`: ++Alternately, exposing a `ReactiveJwtDecoder` `@Bean` has the same effect as `decoder()`: + + ==== + .Java +@@ -350,15 +344,16 @@ fun jwtDecoder(): ReactiveJwtDecoder { + [[webflux-oauth2resourceserver-jwt-decoder-algorithm]] + == Configuring Trusted Algorithms + +-By default, `NimbusReactiveJwtDecoder`, and hence Resource Server, will only trust and verify tokens using `RS256`. ++By default, `NimbusReactiveJwtDecoder`, and hence Resource Server, trust and verify only tokens that use `RS256`. + +-You can customize this via <> or <>. ++You can customize this behavior with <> or by using <>. + + [[webflux-oauth2resourceserver-jwt-boot-algorithm]] +-=== Via Spring Boot ++=== Customizing Trusted Algorithms with Spring Boot + + The simplest way to set the algorithm is as a property: + ++==== + [source,yaml] + ---- + spring: +@@ -369,9 +364,10 @@ spring: + jws-algorithm: RS512 + jwk-set-uri: https://idp.example.org/.well-known/jwks.json + ---- ++==== + + [[webflux-oauth2resourceserver-jwt-decoder-builder]] +-=== Using a Builder ++=== Customizing Trusted Algorithms by Using a Builder + + For greater power, though, we can use a builder that ships with `NimbusReactiveJwtDecoder`: + +@@ -397,7 +393,7 @@ fun jwtDecoder(): ReactiveJwtDecoder { + ---- + ==== + +-Calling `jwsAlgorithm` more than once will configure `NimbusReactiveJwtDecoder` to trust more than one algorithm, like so: ++Calling `jwsAlgorithm` more than once configures `NimbusReactiveJwtDecoder` to trust more than one algorithm: + + ==== + .Java +@@ -421,7 +417,7 @@ fun jwtDecoder(): ReactiveJwtDecoder { + ---- + ==== + +-Or, you can call `jwsAlgorithms`: ++Alternately, you can call `jwsAlgorithms`: + + ==== + .Java +@@ -456,14 +452,14 @@ fun jwtDecoder(): ReactiveJwtDecoder { + === Trusting a Single Asymmetric Key + + Simpler than backing a Resource Server with a JWK Set endpoint is to hard-code an RSA public key. +-The public key can be provided via <> or by <>. ++The public key can be provided with <> or by <>. + + [[webflux-oauth2resourceserver-jwt-decoder-public-key-boot]] + ==== Via Spring Boot + +-Specifying a key via Spring Boot is quite simple. +-The key's location can be specified like so: ++You can specify a key with Spring Boot: + ++==== + [source,yaml] + ---- + spring: +@@ -473,8 +469,9 @@ spring: + jwt: + public-key-location: classpath:my-key.pub + ---- ++==== + +-Or, to allow for a more sophisticated lookup, you can post-process the `RsaKeyConversionServicePostProcessor`: ++Alternately, to allow for a more sophisticated lookup, you can post-process the `RsaKeyConversionServicePostProcessor`: + + .BeanFactoryPostProcessor + ==== +@@ -504,11 +501,14 @@ fun conversionServiceCustomizer(): BeanFactoryPostProcessor { + + Specify your key's location: + +-```yaml ++==== ++[source,yaml] ++---- + key.location: hfds://my-key.pub +-``` ++---- ++==== + +-And then autowire the value: ++Then autowire the value: + + ==== + .Java +@@ -529,7 +529,7 @@ val key: RSAPublicKey? = null + [[webflux-oauth2resourceserver-jwt-decoder-public-key-builder]] + ==== Using a Builder + +-To wire an `RSAPublicKey` directly, you can simply use the appropriate `NimbusReactiveJwtDecoder` builder, like so: ++To wire an `RSAPublicKey` directly, use the appropriate `NimbusReactiveJwtDecoder` builder: + + ==== + .Java +@@ -554,8 +554,8 @@ fun jwtDecoder(): ReactiveJwtDecoder { + [[webflux-oauth2resourceserver-jwt-decoder-secret-key]] + === Trusting a Single Symmetric Key + +-Using a single symmetric key is also simple. +-You can simply load in your `SecretKey` and use the appropriate `NimbusReactiveJwtDecoder` builder, like so: ++You can also use a single symmetric key. ++You can load in your `SecretKey` and use the appropriate `NimbusReactiveJwtDecoder` builder: + + ==== + .Java +@@ -580,13 +580,18 @@ fun jwtDecoder(): ReactiveJwtDecoder { + [[webflux-oauth2resourceserver-jwt-authorization]] + === Configuring Authorization + +-A JWT that is issued from an OAuth 2.0 Authorization Server will typically either have a `scope` or `scp` attribute, indicating the scopes (or authorities) it's been granted, for example: ++A JWT that is issued from an OAuth 2.0 Authorization Server typically has either a `scope` or an `scp` attribute, indicating the scopes (or authorities) it has been granted -- for example: + +-`{ ..., "scope" : "messages contacts"}` ++==== ++[source,json] ++---- ++{ ..., "scope" : "messages contacts"} ++---- ++==== + +-When this is the case, Resource Server will attempt to coerce these scopes into a list of granted authorities, prefixing each scope with the string "SCOPE_". ++When this is the case, Resource Server tries to coerce these scopes into a list of granted authorities, prefixing each scope with the string, `SCOPE_`. + +-This means that to protect an endpoint or method with a scope derived from a JWT, the corresponding expressions should include this prefix: ++This means that, to protect an endpoint or method with a scope derived from a JWT, the corresponding expressions should include this prefix: + + ==== + .Java +@@ -624,7 +629,7 @@ fun springSecurityFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain + ---- + ==== + +-Or similarly with method security: ++You can do something similar with method security: + + ==== + .Java +@@ -646,8 +651,8 @@ fun getMessages(): Flux { } + ==== Extracting Authorities Manually + + However, there are a number of circumstances where this default is insufficient. +-For example, some authorization servers don't use the `scope` attribute, but instead have their own custom attribute. +-Or, at other times, the resource server may need to adapt the attribute or a composition of attributes into internalized authorities. ++For example, some authorization servers do not use the `scope` attribute. Instead, they have their own custom attribute. ++At other times, the resource server may need to adapt the attribute or a composition of attributes into internalized authorities. + + To this end, the DSL exposes `jwtAuthenticationConverter()`: + +@@ -703,10 +708,10 @@ fun grantedAuthoritiesExtractor(): Converter>, indicating the authorization server's issuer uri, Resource Server will default to verifying the `iss` claim as well as the `exp` and `nbf` timestamp claims. ++Using <>, indicating the authorization server's issuer URI, Resource Server defaults to verifying the `iss` claim as well as the `exp` and `nbf` timestamp claims. + +-In circumstances where validation needs to be customized, Resource Server ships with two standard validators and also accepts custom `OAuth2TokenValidator` instances. ++In circumstances where you need to customize validation needs, Resource Server ships with two standard validators and also accepts custom `OAuth2TokenValidator` instances. + + [[webflux-oauth2resourceserver-jwt-validation-clockskew]] + ==== Customizing Timestamp Validation + +-JWT's typically have a window of validity, with the start of the window indicated in the `nbf` claim and the end indicated in the `exp` claim. ++JWT instances typically have a window of validity, with the start of the window indicated in the `nbf` claim and the end indicated in the `exp` claim. + +-However, every server can experience clock drift, which can cause tokens to appear expired to one server, but not to another. +-This can cause some implementation heartburn as the number of collaborating servers increases in a distributed system. ++However, every server can experience clock drift, which can cause tokens to appear to be expired to one server but not to another. ++This can cause some implementation heartburn, as the number of collaborating servers increases in a distributed system. + +-Resource Server uses `JwtTimestampValidator` to verify a token's validity window, and it can be configured with a `clockSkew` to alleviate the above problem: ++Resource Server uses `JwtTimestampValidator` to verify a token's validity window, and you can configure it with a `clockSkew` to alleviate the clock drift problem: + + ==== + .Java +@@ -817,13 +822,12 @@ fun jwtDecoder(): ReactiveJwtDecoder { + ---- + ==== + +-[NOTE] +-By default, Resource Server configures a clock skew of 30 seconds. ++NOTE: By default, Resource Server configures a clock skew of 30 seconds. + + [[webflux-oauth2resourceserver-validation-custom]] + ==== Configuring a Custom Validator + +-Adding a check for the `aud` claim is simple with the `OAuth2TokenValidator` API: ++You can Add a check for the `aud` claim with the `OAuth2TokenValidator` API: + + ==== + .Java +@@ -858,7 +862,7 @@ class AudienceValidator : OAuth2TokenValidator { + ---- + ==== + +-Then, to add into a resource server, it's a matter of specifying the `ReactiveJwtDecoder` instance: ++Then, to add into a resource server, you can specifying the `ReactiveJwtDecoder` instance: + + ==== + .Java +@@ -896,25 +900,28 @@ fun jwtDecoder(): ReactiveJwtDecoder { + + [[webflux-oauth2resourceserver-opaque-minimaldependencies]] + === Minimal Dependencies for Introspection +-As described in <> most of Resource Server support is collected in `spring-security-oauth2-resource-server`. +-However unless a custom <> is provided, the Resource Server will fallback to ReactiveOpaqueTokenIntrospector. +-Meaning that both `spring-security-oauth2-resource-server` and `oauth2-oidc-sdk` are necessary in order to have a working minimal Resource Server that supports opaque Bearer Tokens. +-Please refer to `spring-security-oauth2-resource-server` in order to determin the correct version for `oauth2-oidc-sdk`. ++As described in <>, most Resource Server support is collected in `spring-security-oauth2-resource-server`. ++However, unless you provide a custom <>, the Resource Server falls back to `ReactiveOpaqueTokenIntrospector`. ++This means that both `spring-security-oauth2-resource-server` and `oauth2-oidc-sdk` are necessary to have a working minimal Resource Server that supports opaque Bearer Tokens. ++See `spring-security-oauth2-resource-server` in order to determine the correct version for `oauth2-oidc-sdk`. + + [[webflux-oauth2resourceserver-opaque-minimalconfiguration]] + === Minimal Configuration for Introspection + +-Typically, an opaque token can be verified via an https://tools.ietf.org/html/rfc7662[OAuth 2.0 Introspection Endpoint], hosted by the authorization server. ++Typically, you can verify an opaque token with an https://tools.ietf.org/html/rfc7662[OAuth 2.0 Introspection Endpoint], hosted by the authorization server. + This can be handy when revocation is a requirement. + +-When using https://spring.io/projects/spring-boot[Spring Boot], configuring an application as a resource server that uses introspection consists of two basic steps. +-First, include the needed dependencies and second, indicate the introspection endpoint details. ++When using https://spring.io/projects/spring-boot[Spring Boot], configuring an application as a resource server that uses introspection consists of two steps: ++ ++. Include the needed dependencies. ++. Indicate the introspection endpoint details. + + [[webflux-oauth2resourceserver-opaque-introspectionuri]] + ==== Specifying the Authorization Server + +-To specify where the introspection endpoint is, simply do: ++You can specify where the introspection endpoint is: + ++==== + [source,yaml] + ---- + security: +@@ -925,54 +932,55 @@ security: + client-id: client + client-secret: secret + ---- ++==== + + Where `https://idp.example.com/introspect` is the introspection endpoint hosted by your authorization server and `client-id` and `client-secret` are the credentials needed to hit that endpoint. + +-Resource Server will use these properties to further self-configure and subsequently validate incoming JWTs. +- +-[NOTE] +-When using introspection, the authorization server's word is the law. +-If the authorization server responses that the token is valid, then it is. ++Resource Server uses these properties to further self-configure and subsequently validate incoming JWTs. + +-And that's it! ++NOTE: When using introspection, the authorization server's word is the law. ++If the authorization server responses that the token is valid, it is. + + ==== Startup Expectations + +-When this property and these dependencies are used, Resource Server will automatically configure itself to validate Opaque Bearer Tokens. ++When this property and these dependencies are used, Resource Server automatically configures itself to validate Opaque Bearer Tokens. + +-This startup process is quite a bit simpler than for JWTs since no endpoints need to be discovered and no additional validation rules get added. ++This startup process is quite a bit simpler than for JWTs, since no endpoints need to be discovered and no additional validation rules get added. + + ==== Runtime Expectations + +-Once the application is started up, Resource Server will attempt to process any request containing an `Authorization: Bearer` header: ++Once the application has started, Resource Server tries to process any request containing an `Authorization: Bearer` header: + +-```http ++==== ++[source,http] ++---- + GET / HTTP/1.1 + Authorization: Bearer some-token-value # Resource Server will process this +-``` ++---- ++==== + +-So long as this scheme is indicated, Resource Server will attempt to process the request according to the Bearer Token specification. ++So long as this scheme is indicated, Resource Server tries to process the request according to the Bearer Token specification. + +-Given an Opaque Token, Resource Server will ++Given an Opaque Token, Resource Server: + +-1. Query the provided introspection endpoint using the provided credentials and the token +-2. Inspect the response for an `{ 'active' : true }` attribute +-3. Map each scope to an authority with the prefix `SCOPE_` ++. Queries the provided introspection endpoint by using the provided credentials and the token. ++. Inspects the response for an `{ 'active' : true }` attribute. ++. Maps each scope to an authority with a prefix of `SCOPE_`. + +-The resulting `Authentication#getPrincipal`, by default, is a Spring Security `{security-api-url}org/springframework/security/oauth2/core/OAuth2AuthenticatedPrincipal.html[OAuth2AuthenticatedPrincipal]` object, and `Authentication#getName` maps to the token's `sub` property, if one is present. ++By default, the resulting `Authentication#getPrincipal` is a Spring Security `{security-api-url}org/springframework/security/oauth2/core/OAuth2AuthenticatedPrincipal.html[OAuth2AuthenticatedPrincipal]` object, and `Authentication#getName` maps to the token's `sub` property, if one is present. + + From here, you may want to jump to: + +-* <> +-* <> +-* <> ++* <> ++* <> ++* <> + + [[webflux-oauth2resourceserver-opaque-attributes]] +-=== Looking Up Attributes Post-Authentication ++=== Looking Up Attributes After Authentication + + Once a token is authenticated, an instance of `BearerTokenAuthentication` is set in the `SecurityContext`. + +-This means that it's available in `@Controller` methods when using `@EnableWebFlux` in your configuration: ++This means that it is available in `@Controller` methods when you use `@EnableWebFlux` in your configuration: + + ==== + .Java +@@ -994,7 +1002,7 @@ fun foo(authentication: BearerTokenAuthentication): Mono { + ---- + ==== + +-Since `BearerTokenAuthentication` holds an `OAuth2AuthenticatedPrincipal`, that also means that it's available to controller methods, too: ++Since `BearerTokenAuthentication` holds an `OAuth2AuthenticatedPrincipal`, it is also available to controller methods: + + ==== + .Java +@@ -1016,11 +1024,11 @@ fun foo(@AuthenticationPrincipal principal: OAuth2AuthenticatedPrincipal): Mono< + ---- + ==== + +-==== Looking Up Attributes Via SpEL ++==== Looking Up Attributes with SpEL + +-Of course, this also means that attributes can be accessed via SpEL. ++You can access attributes with the Spring Expression Language (SpEL). + +-For example, if using `@EnableReactiveMethodSecurity` so that you can use `@PreAuthorize` annotations, you can do: ++For example, if you use `@EnableReactiveMethodSecurity` so that you can use `@PreAuthorize` annotations, you can do: + + ==== + .Java +@@ -1045,10 +1053,10 @@ fun forFoosEyesOnly(): Mono { + [[webflux-oauth2resourceserver-opaque-sansboot]] + === Overriding or Replacing Boot Auto Configuration + +-There are two `@Bean` s that Spring Boot generates on Resource Server's behalf. ++Spring Boot generates two `@Bean` instances for Resource Server. + +-The first is a `SecurityWebFilterChain` that configures the app as a resource server. +-When use Opaque Token, this `SecurityWebFilterChain` looks like: ++The first is a `SecurityWebFilterChain` that configures the application as a resource server. ++When you use an Opaque Token, this `SecurityWebFilterChain` looks like: + + ==== + .Java +@@ -1082,9 +1090,9 @@ fun springSecurityFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain + ---- + ==== + +-If the application doesn't expose a `SecurityWebFilterChain` bean, then Spring Boot will expose the above default one. ++If the application does not expose a `SecurityWebFilterChain` bean, Spring Boot exposes the default bean (shown in the preceding listing). + +-Replacing this is as simple as exposing the bean within the application: ++You can replace it by exposing the bean within the application: + + .Replacing SecurityWebFilterChain + ==== +@@ -1130,9 +1138,9 @@ fun springSecurityFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain + ---- + ==== + +-The above requires the scope of `message:read` for any URL that starts with `/messages/`. ++The preceding example requires the scope of `message:read` for any URL that starts with `/messages/`. + +-Methods on the `oauth2ResourceServer` DSL will also override or replace auto configuration. ++Methods on the `oauth2ResourceServer` DSL also override or replace auto configuration. + + For example, the second `@Bean` Spring Boot creates is a `ReactiveOpaqueTokenIntrospector`, which decodes `String` tokens into validated instances of `OAuth2AuthenticatedPrincipal`: + +@@ -1156,14 +1164,14 @@ fun introspector(): ReactiveOpaqueTokenIntrospector { + ---- + ==== + +-If the application doesn't expose a `ReactiveOpaqueTokenIntrospector` bean, then Spring Boot will expose the above default one. ++If the application does not expose a `ReactiveOpaqueTokenIntrospector` bean, Spring Boot exposes the default one (shown in the preceding listing). + +-And its configuration can be overridden using `introspectionUri()` and `introspectionClientCredentials()` or replaced using `introspector()`. ++You can override its configuration by using `introspectionUri()` and `introspectionClientCredentials()` or replace it by using `introspector()`. + + [[webflux-oauth2resourceserver-opaque-introspectionuri-dsl]] + ==== Using `introspectionUri()` + +-An authorization server's Introspection Uri can be configured <> or it can be supplied in the DSL: ++You can configure an authorization server's Introspection URI <>, or you can supply in the DSL: + + ==== + .Java +@@ -1213,7 +1221,7 @@ Using `introspectionUri()` takes precedence over any configuration property. + [[webflux-oauth2resourceserver-opaque-introspector-dsl]] + ==== Using `introspector()` + +-More powerful than `introspectionUri()` is `introspector()`, which will completely replace any Boot auto configuration of `ReactiveOpaqueTokenIntrospector`: ++`introspector()` is more powerful than `introspectionUri()`. It completely replaces any Boot auto-configuration of `ReactiveOpaqueTokenIntrospector`: + + ==== + .Java +@@ -1256,7 +1264,7 @@ fun springSecurityFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain + ---- + ==== + +-This is handy when deeper configuration, like <>or <> is necessary. ++This is handy when deeper configuration, such as <>or <>, is necessary. + + [[webflux-oauth2resourceserver-opaque-introspector-bean]] + ==== Exposing a `ReactiveOpaqueTokenIntrospector` `@Bean` +@@ -1286,13 +1294,18 @@ fun introspector(): ReactiveOpaqueTokenIntrospector { + [[webflux-oauth2resourceserver-opaque-authorization]] + === Configuring Authorization + +-An OAuth 2.0 Introspection endpoint will typically return a `scope` attribute, indicating the scopes (or authorities) it's been granted, for example: ++An OAuth 2.0 Introspection endpoint typically returns a `scope` attribute, indicating the scopes (or authorities) it has been granted -- for example: + +-`{ ..., "scope" : "messages contacts"}` ++==== ++[source,json] ++---- ++{ ..., "scope" : "messages contacts"} ++---- ++==== + +-When this is the case, Resource Server will attempt to coerce these scopes into a list of granted authorities, prefixing each scope with the string "SCOPE_". ++When this is the case, Resource Server tries to coerce these scopes into a list of granted authorities, prefixing each scope with a string: `SCOPE_`. + +-This means that to protect an endpoint or method with a scope derived from an Opaque Token, the corresponding expressions should include this prefix: ++This means that, to protect an endpoint or method with a scope derived from an Opaque Token, the corresponding expressions should include this prefix: + + ==== + .Java +@@ -1333,7 +1346,7 @@ fun springSecurityFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain + ---- + ==== + +-Or similarly with method security: ++You can do something similar with method security: + + ==== + .Java +@@ -1354,9 +1367,9 @@ fun getMessages(): Flux { } + [[webflux-oauth2resourceserver-opaque-authorization-extraction]] + ==== Extracting Authorities Manually + +-By default, Opaque Token support will extract the scope claim from an introspection response and parse it into individual `GrantedAuthority` instances. ++By default, Opaque Token support extracts the scope claim from an introspection response and parses it into individual `GrantedAuthority` instances. + +-For example, if the introspection response were: ++Consider the following example: + + [source,json] + ---- +@@ -1366,9 +1379,9 @@ For example, if the introspection response were: + } + ---- + +-Then Resource Server would generate an `Authentication` with two authorities, one for `message:read` and the other for `message:write`. ++If the introspection response were as the preceding example shows, Resource Server would generate an `Authentication` with two authorities, one for `message:read` and the other for `message:write`. + +-This can, of course, be customized using a custom `ReactiveOpaqueTokenIntrospector` that takes a look at the attribute set and converts in its own way: ++You can customize behavior by using a custom `ReactiveOpaqueTokenIntrospector` that looks at the attribute set and converts in its own way: + + ==== + .Java +@@ -1415,7 +1428,7 @@ class CustomAuthoritiesOpaqueTokenIntrospector : ReactiveOpaqueTokenIntrospector + ---- + ==== + +-Thereafter, this custom introspector can be configured simply by exposing it as a `@Bean`: ++Thereafter, you can configure this custom introspector by exposing it as a `@Bean`: + + ==== + .Java +@@ -1441,12 +1454,13 @@ fun introspector(): ReactiveOpaqueTokenIntrospector { + === Using Introspection with JWTs + + A common question is whether or not introspection is compatible with JWTs. +-Spring Security's Opaque Token support has been designed to not care about the format of the token -- it will gladly pass any token to the introspection endpoint provided. ++Spring Security's Opaque Token support has been designed to not care about the format of the token. It gladly passes any token to the provided introspection endpoint. + +-So, let's say that you've got a requirement that requires you to check with the authorization server on each request, in case the JWT has been revoked. ++So, suppose you need to check with the authorization server on each request, in case the JWT has been revoked. + +-Even though you are using the JWT format for the token, your validation method is introspection, meaning you'd want to do: ++Even though you are using the JWT format for the token, your validation method is introspection, meaning you would want to do: + ++==== + [source,yaml] + ---- + spring: +@@ -1458,14 +1472,15 @@ spring: + client-id: client + client-secret: secret + ---- ++==== + + In this case, the resulting `Authentication` would be `BearerTokenAuthentication`. + Any attributes in the corresponding `OAuth2AuthenticatedPrincipal` would be whatever was returned by the introspection endpoint. + +-But, let's say that, oddly enough, the introspection endpoint only returns whether or not the token is active. ++However, suppose that, for whatever reason, the introspection endpoint returns only whether or not the token is active. + Now what? + +-In this case, you can create a custom `ReactiveOpaqueTokenIntrospector` that still hits the endpoint, but then updates the returned principal to have the JWTs claims as the attributes: ++In this case, you can create a custom `ReactiveOpaqueTokenIntrospector` that still hits the endpoint but then updates the returned principal to have the JWTs claims as the attributes: + + ==== + .Java +@@ -1519,7 +1534,7 @@ class JwtOpaqueTokenIntrospector : ReactiveOpaqueTokenIntrospector { + ---- + ==== + +-Thereafter, this custom introspector can be configured simply by exposing it as a `@Bean`: ++Thereafter, you can configure this custom introspector by exposing it as a `@Bean`: + + ==== + .Java +@@ -1544,16 +1559,16 @@ fun introspector(): ReactiveOpaqueTokenIntrospector { + [[webflux-oauth2resourceserver-opaque-userinfo]] + === Calling a `/userinfo` Endpoint + +-Generally speaking, a Resource Server doesn't care about the underlying user, but instead about the authorities that have been granted. ++Generally speaking, a Resource Server does not care about the underlying user but, instead, cares about the authorities that have been granted. + + That said, at times it can be valuable to tie the authorization statement back to a user. + +-If an application is also using `spring-security-oauth2-client`, having set up the appropriate `ClientRegistrationRepository`, then this is quite simple with a custom `OpaqueTokenIntrospector`. +-This implementation below does three things: ++If an application also uses `spring-security-oauth2-client`, having set up the appropriate `ClientRegistrationRepository`, you can do so with a custom `OpaqueTokenIntrospector`. ++The implementation in the next listing does three things: + +-* Delegates to the introspection endpoint, to affirm the token's validity +-* Looks up the appropriate client registration associated with the `/userinfo` endpoint +-* Invokes and returns the response from the `/userinfo` endpoint ++* Delegates to the introspection endpoint, to affirm the token's validity. ++* Looks up the appropriate client registration associated with the `/userinfo` endpoint. ++* Invokes and returns the response from the `/userinfo` endpoint. + + ==== + .Java +@@ -1610,8 +1625,8 @@ class UserInfoOpaqueTokenIntrospector : ReactiveOpaqueTokenIntrospector { + ---- + ==== + +-If you aren't using `spring-security-oauth2-client`, it's still quite simple. +-You will simply need to invoke the `/userinfo` with your own instance of `WebClient`: ++If you do not use `spring-security-oauth2-client`, you can do so ++by invoking the `/userinfo` with your own instance of `WebClient`: + + ==== + .Java +@@ -1672,17 +1687,17 @@ fun introspector(): ReactiveOpaqueTokenIntrospector { + + A resource server is considered multi-tenant when there are multiple strategies for verifying a bearer token, keyed by some tenant identifier. + +-For example, your resource server may accept bearer tokens from two different authorization servers. +-Or, your authorization server may represent a multiplicity of issuers. ++For example, your resource server can accept bearer tokens from two different authorization servers. ++Alternately, your authorization server can represent a multiplicity of issuers. + +-In each case, there are two things that need to be done and trade-offs associated with how you choose to do them: ++In each case, two things need to be done and trade-offs are associated with how you choose to do them: + +-1. Resolve the tenant +-2. Propagate the tenant ++1. Resolve the tenant. ++2. Propagate the tenant. + + === Resolving the Tenant By Claim + +-One way to differentiate tenants is by the issuer claim. Since the issuer claim accompanies signed JWTs, this can be done with the `JwtIssuerReactiveAuthenticationManagerResolver`, like so: ++One way to differentiate tenants is by the issuer claim. Since the issuer claim accompanies signed JWTs, you can do so with the `JwtIssuerReactiveAuthenticationManagerResolver`: + + ==== + .Java +@@ -1722,8 +1737,8 @@ This allows for an application startup that is independent from those authorizat + + ==== Dynamic Tenants + +-Of course, you may not want to restart the application each time a new tenant is added. +-In this case, you can configure the `JwtIssuerReactiveAuthenticationManagerResolver` with a repository of `ReactiveAuthenticationManager` instances, which you can edit at runtime, like so: ++You may not want to restart the application each time a new tenant is added. ++In this case, you can configure the `JwtIssuerReactiveAuthenticationManagerResolver` with a repository of `ReactiveAuthenticationManager` instances, which you can edit at runtime: + + ==== + .Java +@@ -1777,20 +1792,20 @@ return http { + ---- + ==== + +-In this case, you construct `JwtIssuerReactiveAuthenticationManagerResolver` with a strategy for obtaining the `ReactiveAuthenticationManager` given the issuer. +-This approach allows us to add and remove elements from the repository (shown as a `Map` in the snippet) at runtime. ++In this case, you construct `JwtIssuerReactiveAuthenticationManagerResolver` with a strategy for obtaining the `ReactiveAuthenticationManager` given to the issuer. ++This approach lets us add and remove elements from the repository (shown as a `Map` in the preceding snippet) at runtime. + + NOTE: It would be unsafe to simply take any issuer and construct an `ReactiveAuthenticationManager` from it. +-The issuer should be one that the code can verify from a trusted source like an allowed list of issuers. ++The issuer should be one that the code can verify from a trusted source, such as an allowed list of issuers. + + [[webflux-oauth2resourceserver-bearertoken-resolver]] + == Bearer Token Resolution + + By default, Resource Server looks for a bearer token in the `Authorization` header. +-This, however, can be customized. ++However, you can verify this token. + + For example, you may have a need to read the bearer token from a custom header. +-To achieve this, you can wire an instance of `ServerBearerTokenAuthenticationConverter` into the DSL, as you can see in the following example: ++To do so, you can wire an instance of `ServerBearerTokenAuthenticationConverter` into the DSL: + + .Custom Bearer Token Header + ==== +@@ -1820,8 +1835,8 @@ return http { + + == Bearer Token Propagation + +-Now that you're in possession of a bearer token, it might be handy to pass that to downstream services. +-This is quite simple with `{security-api-url}org/springframework/security/oauth2/server/resource/web/reactive/function/client/ServerBearerExchangeFilterFunction.html[ServerBearerExchangeFilterFunction]`, which you can see in the following example: ++Now that you have a bearer token, you can pass that to downstream services. ++This is possible with `{security-api-url}org/springframework/security/oauth2/server/resource/web/reactive/function/client/ServerBearerExchangeFilterFunction.html[ServerBearerExchangeFilterFunction]`: + + ==== + .Java +@@ -1847,10 +1862,8 @@ fun rest(): WebClient { + ---- + ==== + +-When the above `WebClient` is used to perform requests, Spring Security will look up the current `Authentication` and extract any `{security-api-url}org/springframework/security/oauth2/core/AbstractOAuth2Token.html[AbstractOAuth2Token]` credential. +-Then, it will propagate that token in the `Authorization` header. +- +-For example: ++When the `WebClient` shown in the preceding example performs requests, Spring Security looks up the current `Authentication` and extract any `{security-api-url}org/springframework/security/oauth2/core/AbstractOAuth2Token.html[AbstractOAuth2Token]` credential. ++Then, it propagates that token in the `Authorization` header -- for example: + + ==== + .Java +@@ -1872,9 +1885,9 @@ this.rest.get() + ---- + ==== + +-Will invoke the `https://other-service.example.com/endpoint`, adding the bearer token `Authorization` header for you. ++The prececing example invokes the `https://other-service.example.com/endpoint`, adding the bearer token `Authorization` header for you. + +-In places where you need to override this behavior, it's a simple matter of supplying the header yourself, like so: ++In places where you need to override this behavior, you can supply the header yourself: + + ==== + .Java +@@ -1898,8 +1911,7 @@ rest.get() + ---- + ==== + +-In this case, the filter will fall back and simply forward the request onto the rest of the web filter chain. ++In this case, the filter falls back and forwards the request onto the rest of the web filter chain. + +-[NOTE] +-Unlike the https://docs.spring.io/spring-security/site/docs/current-SNAPSHOT/api/org/springframework/security/oauth2/client/web/reactive/function/client/ServerOAuth2AuthorizedClientExchangeFilterFunction.html[OAuth 2.0 Client filter function], this filter function makes no attempt to renew the token, should it be expired. +-To obtain this level of support, please use the OAuth 2.0 Client filter. ++NOTE: Unlike the https://docs.spring.io/spring-security/site/docs/current-SNAPSHOT/api/org/springframework/security/oauth2/client/web/reactive/function/client/ServerOAuth2AuthorizedClientExchangeFilterFunction.html[OAuth 2.0 Client filter function], this filter function makes no attempt to renew the token, should it be expired. ++To obtain this level of support, use the OAuth 2.0 Client filter. +diff --git a/docs/manual/src/docs/asciidoc/_includes/reactive/registered-oauth2-authorized-client.adoc b/docs/manual/src/docs/asciidoc/_includes/reactive/registered-oauth2-authorized-client.adoc +index cd1e4c06cd..ce98690560 100644 +--- a/docs/manual/src/docs/asciidoc/_includes/reactive/registered-oauth2-authorized-client.adoc ++++ b/docs/manual/src/docs/asciidoc/_includes/reactive/registered-oauth2-authorized-client.adoc +@@ -1,14 +1,11 @@ + [[webflux-roac]] + = @RegisteredOAuth2AuthorizedClient + +-Spring Security allows resolving an access token using `@RegisteredOAuth2AuthorizedClient`. ++Spring Security allows resolving an access token by using `@RegisteredOAuth2AuthorizedClient`. + +-[NOTE] +-==== +-A working example can be found in {gh-samples-url}/boot/oauth2webclient-webflux[*OAuth 2.0 WebClient WebFlux sample*]. +-==== ++NOTE: You can find a working example in the {gh-samples-url}/boot/oauth2webclient-webflux[OAuth 2.0 WebClient WebFlux sample]. + +-After configuring Spring Security for <> or as an <>, an `OAuth2AuthorizedClient` can be resolved using the following: ++After configuring Spring Security for <> or as an <>, you can resolve an `OAuth2AuthorizedClient` by using the following: + + ==== + .Java +@@ -30,14 +27,14 @@ fun explicit(@RegisteredOAuth2AuthorizedClient("client-id") authorizedClient: OA + ---- + ==== + +-This integrates into Spring Security to provide the following features: ++This code integrates into Spring Security to provide the following features: + +-* Spring Security will automatically refresh expired tokens (if a refresh token is present) +-* If an access token is requested and not present, Spring Security will automatically request the access token. +-** For `authorization_code` this involves performing the redirect and then replaying the original request +-** For `client_credentials` the token is simply requested and saved ++* Spring Security automatically refreshes expired tokens (if a refresh token is present). ++* If an access token is requested and not present, Spring Security automatically requests the access token. ++** For `authorization_code`, this involves performing the redirect and then replaying the original request. ++** For `client_credentials`, the token is simply requested and saved. + +-If the user authenticated using `oauth2Login()`, then the `client-id` is optional. ++If the user authenticated by using `oauth2Login()`, the `client-id` is optional. + For example, the following would work: + + ==== +@@ -60,4 +57,4 @@ fun implicit(@RegisteredOAuth2AuthorizedClient authorizedClient: OAuth2Authorize + ---- + ==== + +-This is convenient if the user always authenticates with OAuth2 Login and an access token from the same authorization server is needed. ++This approach is convenient if the user always authenticates with OAuth2 Login and an access token from the same authorization server is needed. +diff --git a/docs/manual/src/docs/asciidoc/_includes/reactive/rsocket.adoc b/docs/manual/src/docs/asciidoc/_includes/reactive/rsocket.adoc +index 7cecae769b..822b0cd1a9 100644 +--- a/docs/manual/src/docs/asciidoc/_includes/reactive/rsocket.adoc ++++ b/docs/manual/src/docs/asciidoc/_includes/reactive/rsocket.adoc +@@ -2,9 +2,9 @@ + = RSocket Security + + Spring Security's RSocket support relies on a `SocketAcceptorInterceptor`. +-The main entry point into security is found in the `PayloadSocketAcceptorInterceptor` which adapts the RSocket APIs to allow intercepting a `PayloadExchange` with `PayloadInterceptor` implementations. ++The main entry point into security is in `PayloadSocketAcceptorInterceptor`, which adapts the RSocket APIs to allow intercepting a `PayloadExchange` with `PayloadInterceptor` implementations. + +-You can find a few sample applications that demonstrate the code below: ++You can find two sample applications that demonstrate the code: + + * Hello RSocket {gh-samples-url}/boot/hellorsocket[hellorsocket] + * https://github.com/rwinch/spring-flights/tree/security[Spring Flights] +@@ -12,8 +12,9 @@ You can find a few sample applications that demonstrate the code below: + + == Minimal RSocket Security Configuration + +-You can find a minimal RSocket Security configuration below: ++The following example shows a minimal RSocket Security configuration: + ++==== + [source,java] + ----- + @Configuration +@@ -31,15 +32,17 @@ public class HelloRSocketSecurityConfig { + } + } + ----- ++==== + + This configuration enables <> and sets up <> to require an authenticated user for any request. + + == Adding SecuritySocketAcceptorInterceptor + +-For Spring Security to work we need to apply `SecuritySocketAcceptorInterceptor` to the `ServerRSocketFactory`. +-This is what connects our `PayloadSocketAcceptorInterceptor` we created with the RSocket infrastructure. +-In a Spring Boot application this is done automatically using `RSocketSecurityAutoConfiguration` with the following code. ++For Spring Security to work, we need to apply `SecuritySocketAcceptorInterceptor` to the `ServerRSocketFactory`. ++Doing so connects our `PayloadSocketAcceptorInterceptor` with the RSocket infrastructure. ++In a Spring Boot application, you can do this automatically by using `RSocketSecurityAutoConfiguration` with the following code: + ++==== + [source,java] + ---- + @Bean +@@ -48,45 +51,44 @@ ServerRSocketFactoryProcessor springSecurityRSocketSecurity( + return builder -> builder.addSocketAcceptorPlugin(interceptor); + } + ---- ++==== + + [[rsocket-authentication]] + == RSocket Authentication + +-RSocket authentication is performed with `AuthenticationPayloadInterceptor` which acts as a controller to invoke a `ReactiveAuthenticationManager` instance. ++RSocket authentication is performed with `AuthenticationPayloadInterceptor`, which acts as a controller to invoke a `ReactiveAuthenticationManager` instance. + + [[rsocket-authentication-setup-vs-request]] +-=== Authentication at Setup vs Request Time ++=== Authentication at Setup versus Request Time + +-Generally, authentication can occur at setup time and/or request time. ++Generally, authentication can occur at setup time or at request time or both. + + Authentication at setup time makes sense in a few scenarios. +-A common scenarios is when a single user (i.e. mobile connection) is leveraging an RSocket connection. +-In this case only a single user is leveraging the connection, so authentication can be done once at connection time. ++A common scenarios is when a single user (such as a mobile connection) uses an RSocket connection. ++In this case, only a single user uses the connection, so authentication can be done once at connection time. + +-In a scenario where the RSocket connection is shared it makes sense to send credentials on each request. +-For example, a web application that connects to an RSocket server as a downstream service would make a single connection that all users leverage. +-In this case, if the RSocket server needs to perform authorization based on the web application's users credentials per request makes sense. ++In a scenario where the RSocket connection is shared, it makes sense to send credentials on each request. ++For example, a web application that connects to an RSocket server as a downstream service would make a single connection that all users use. ++In this case, if the RSocket server needs to perform authorization based on the web application's users credentials, authentication for each request makes sense. + +-In some scenarios authentication at setup and per request makes sense. +-Consider a web application as described previously. ++In some scenarios, authentication at both setup and for each request makes sense. ++Consider a web application, as described previously. + If we need to restrict the connection to the web application itself, we can provide a credential with a `SETUP` authority at connection time. +-Then each user would have different authorities but not the `SETUP` authority. ++Then each user can have different authorities but not the `SETUP` authority. + This means that individual users can make requests but not make additional connections. + + [[rsocket-authentication-simple]] + === Simple Authentication + +-Spring Security has support for https://github.com/rsocket/rsocket/blob/5920ed374d008abb712cb1fd7c9d91778b2f4a68/Extensions/Security/Simple.md[Simple Authentication Metadata Extension]. ++Spring Security has support for the https://github.com/rsocket/rsocket/blob/5920ed374d008abb712cb1fd7c9d91778b2f4a68/Extensions/Security/Simple.md[Simple Authentication Metadata Extension]. + +-[NOTE] +-==== +-Basic Authentication drafts evolved into Simple Authentication and is only supported for backward compatibility. ++NOTE: Basic Authentication evolved into Simple Authentication and is only supported for backward compatibility. + See `RSocketSecurity.basicAuthentication(Customizer)` for setting it up. +-==== + +-The RSocket receiver can decode the credentials using `AuthenticationPayloadExchangeConverter` which is automatically setup using the `simpleAuthentication` portion of the DSL. +-An explicit configuration can be found below. ++The RSocket receiver can decode the credentials by using `AuthenticationPayloadExchangeConverter`, which is automatically setup by using the `simpleAuthentication` portion of the DSL. ++The following example shows an explicit configuration: + ++==== + [source,java] + ---- + @Bean +@@ -101,17 +103,21 @@ PayloadSocketAcceptorInterceptor rsocketInterceptor(RSocketSecurity rsocket) { + return rsocket.build(); + } + ---- ++==== + +-The RSocket sender can send credentials using `SimpleAuthenticationEncoder` which can be added to Spring's `RSocketStrategies`. ++The RSocket sender can send credentials by using `SimpleAuthenticationEncoder`, which you can add to Spring's `RSocketStrategies`. + ++==== + [source,java] + ---- + RSocketStrategies.Builder strategies = ...; + strategies.encoder(new SimpleAuthenticationEncoder()); + ---- ++==== + +-It can then be used to send a username and password to the receiver in the setup: ++You can then use it to send a username and password to the receiver in the setup: + ++==== + [source,java] + ---- + MimeType authenticationMimeType = +@@ -122,9 +128,11 @@ Mono requester = RSocketRequester.builder() + .rsocketStrategies(strategies.build()) + .connectTcp(host, port); + ---- ++==== + +-Alternatively or additionally, a username and password can be sent in a request. ++Alternatively or additionally, a username and password can be sent in a request: + ++==== + [source,java] + ---- + Mono requester; +@@ -138,16 +146,18 @@ public Mono findRadar(String code) { + ); + } + ---- ++==== + + [[rsocket-authentication-jwt]] + === JWT + +-Spring Security has support for https://github.com/rsocket/rsocket/blob/5920ed374d008abb712cb1fd7c9d91778b2f4a68/Extensions/Security/Bearer.md[Bearer Token Authentication Metadata Extension]. +-The support comes in the form of authenticating a JWT (determining the JWT is valid) and then using the JWT to make authorization decisions. ++Spring Security has support for the https://github.com/rsocket/rsocket/blob/5920ed374d008abb712cb1fd7c9d91778b2f4a68/Extensions/Security/Bearer.md[Bearer Token Authentication Metadata Extension]. ++The support comes in the form of authenticating a JWT (determining that the JWT is valid) and then using the JWT to make authorization decisions. + +-The RSocket receiver can decode the credentials using `BearerPayloadExchangeConverter` which is automatically setup using the `jwt` portion of the DSL. +-An example configuration can be found below: ++The RSocket receiver can decode the credentials by using `BearerPayloadExchangeConverter`, which is automatically setup by using the `jwt` portion of the DSL. ++The following listing shows an example configuration: + ++==== + [source,java] + ---- + @Bean +@@ -162,10 +172,12 @@ PayloadSocketAcceptorInterceptor rsocketInterceptor(RSocketSecurity rsocket) { + return rsocket.build(); + } + ---- ++==== + +-The configuration above relies on the existence of a `ReactiveJwtDecoder` `@Bean` being present. +-An example of creating one from the issuer can be found below: ++The preceding configuration relies a `ReactiveJwtDecoder` `@Bean` being present. ++The following example creates one from the issuer: + ++==== + [source,java] + ---- + @Bean +@@ -174,10 +186,12 @@ ReactiveJwtDecoder jwtDecoder() { + .fromIssuerLocation("https://example.com/auth/realms/demo"); + } + ---- ++==== + +-The RSocket sender does not need to do anything special to send the token because the value is just a simple String. +-For example, the token can be sent at setup time: ++The RSocket sender does not need to do anything special to send the token, because the value is a simple `String`. ++The following example sends the token at setup time: + ++==== + [source,java] + ---- + MimeType authenticationMimeType = +@@ -187,9 +201,11 @@ Mono requester = RSocketRequester.builder() + .setupMetadata(token, authenticationMimeType) + .connectTcp(host, port); + ---- ++==== + +-Alternatively or additionally, the token can be sent in a request. ++Alternatively or additionally, you can send the token in a request: + ++==== + [source,java] + ---- + MimeType authenticationMimeType = +@@ -205,14 +221,16 @@ public Mono findRadar(String code) { + ); + } + ---- ++==== + + [[rsocket-authorization]] + == RSocket Authorization + +-RSocket authorization is performed with `AuthorizationPayloadInterceptor` which acts as a controller to invoke a `ReactiveAuthorizationManager` instance. +-The DSL can be used to setup authorization rules based upon the `PayloadExchange`. +-An example configuration can be found below: ++RSocket authorization is performed with `AuthorizationPayloadInterceptor`, which acts as a controller to invoke a `ReactiveAuthorizationManager` instance. ++You can use the DSL to set up authorization rules based upon the `PayloadExchange`. ++The following listing shows an example configuration: + ++==== + [[source,java]] + ---- + rsocket +@@ -228,17 +246,18 @@ rsocket + .anyExchange().permitAll() // <6> + ) + ---- +-<1> Setting up a connection requires the authority `ROLE_SETUP` +-<2> If the route is `fetch.profile.me` authorization only requires the user be authenticated +-<3> In this rule we setup a custom matcher where authorization requires the user to have the authority `ROLE_CUSTOM` +-<4> This rule leverages custom authorization. +-The matcher expresses a variable with the name `username` that is made available in the `context`. ++<1> Setting up a connection requires the `ROLE_SETUP` authority. ++<2> If the route is `fetch.profile.me`, authorization only requires the user to be authenticated. ++<3> In this rule, we set up a custom matcher, where authorization requires the user to have the `ROLE_CUSTOM` authority. ++<4> This rule uses custom authorization. ++The matcher expresses a variable with a name of `username` that is made available in the `context`. + A custom authorization rule is exposed in the `checkFriends` method. +-<5> This rule ensures that request that does not already have a rule will require the user to be authenticated. ++<5> This rule ensures that a request that does not already have a rule requires the user to be authenticated. + A request is where the metadata is included. + It would not include additional payloads. + <6> This rule ensures that any exchange that does not already have a rule is allowed for anyone. +-In this example, it means that payloads that have no metadata have no authorization rules. ++In this example, it means that payloads that have no metadata also have no authorization rules. ++==== + +-It is important to understand that authorization rules are performed in order. +-Only the first authorization rule that matches will be invoked. ++Note that authorization rules are performed in order. ++Only the first authorization rule that matches is invoked. +diff --git a/docs/manual/src/docs/asciidoc/_includes/reactive/test.adoc b/docs/manual/src/docs/asciidoc/_includes/reactive/test.adoc +index 4a9e3a9e39..247dc15a4c 100644 +--- a/docs/manual/src/docs/asciidoc/_includes/reactive/test.adoc ++++ b/docs/manual/src/docs/asciidoc/_includes/reactive/test.adoc +@@ -1,12 +1,15 @@ + [[test-webflux]] + = Reactive Test Support + ++This section describes how to test reactive applications that use Spring Security. ++ + [[test-erms]] + == Testing Reactive Method Security + +-For example, we can test our example from <> using the same setup and annotations we did in <>. +-Here is a minimal sample of what we can do: ++For example, we can test our example from <> by using the same setup and annotations that we used in <>. ++The following minimal sample shows what we can do: + ++==== + [source,java] + ---- + @RunWith(SpringRunner.class) +@@ -39,6 +42,7 @@ public class HelloWorldMessageServiceTests { + } + } + ---- ++==== + + [[test-webtestclient]] + == WebTestClientSupport +@@ -46,6 +50,7 @@ public class HelloWorldMessageServiceTests { + Spring Security provides integration with `WebTestClient`. + The basic setup looks like this: + ++==== + [source,java] + ---- + @RunWith(SpringRunner.class) +@@ -69,12 +74,13 @@ public class HelloWebfluxMethodApplicationTests { + // ... + } + ---- ++==== + + === Authentication + +-After applying the Spring Security support to `WebTestClient` we can use either annotations or `mutateWith` support. +-For example: ++After applying the Spring Security support to `WebTestClient`, we can use either annotations or `mutateWith` support -- for example: + ++==== + [source,java] + ---- + @Test +@@ -132,13 +138,14 @@ public void messageWhenMutateWithMockAdminThenOk() throws Exception { + .expectBody(String.class).isEqualTo("Hello World!"); + } + ---- ++==== + + + === CSRF Support + +-Spring Security also provides support for CSRF testing with `WebTestClient`. +-For example: ++Spring Security also provides support for CSRF testing with `WebTestClient` -- for example: + ++==== + [source,java] + ---- + this.rest +@@ -148,14 +155,16 @@ this.rest + .uri("/login") + ... + ---- ++==== + + [[webflux-testing-oauth2]] + === 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`. + +-For example, for a controller that looks like this: ++Consider the following example of a controller: + ++==== + [source,java] + ---- + @GetMapping("/endpoint") +@@ -163,11 +172,13 @@ public Mono foo(Principal user) { + return Mono.just(user.getName()); + } + ---- ++==== + +-There's nothing OAuth2-specific about it, so you will likely be able to simply <> and be fine. ++Nothing about it is OAuth2-specific, so you can <> and be fine. + +-But, in cases where your controllers are bound to some aspect of Spring Security's OAuth 2.0 support, like the following: ++However, consider a case where your controller is bound to some aspect of Spring Security's OAuth 2.0 support: + ++==== + [source,java] + ---- + @GetMapping("/endpoint") +@@ -175,50 +186,59 @@ public Mono foo(@AuthenticationPrincipal OidcUser user) { + return Mono.just(user.getIdToken().getSubject()); + } + ---- ++==== + +-then Spring Security's test support can come in handy. ++In that case, Spring Security's test support is handy. + + [[webflux-testing-oidc-login]] + === Testing OIDC Login + +-Testing the method above with `WebTestClient` 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. ++Testing the method shown in the <> with `WebTestClient` requires simulating some kind of grant flow with an authorization server. ++This is a daunting task, which is why Spring Security ships with support for removing this boilerplate. + +-For example, we can tell Spring Security to include a default `OidcUser` using the `SecurityMockServerConfigurers#oidcLogin` method, like so: ++For example, we can tell Spring Security to include a default `OidcUser` by using the `SecurityMockServerConfigurers#oidcLogin` method: + ++==== + [source,java] + ---- + client + .mutateWith(mockOidcLogin()).get().uri("/endpoint").exchange(); + ---- ++==== + +-What this will do is configure the associated `MockServerRequest` with an `OidcUser` that includes a simple `OidcIdToken`, `OidcUserInfo`, and `Collection` of granted authorities. ++That line configures the associated `MockServerRequest` with an `OidcUser` that includes a simple `OidcIdToken`, an `OidcUserInfo`, and a `Collection` of granted authorities. + +-Specifically, it will include an `OidcIdToken` with a `sub` claim set to `user`: ++Specifically, it includes an `OidcIdToken` with a `sub` claim set to `user`: + ++==== + [source,json] + ---- + assertThat(user.getIdToken().getClaim("sub")).isEqualTo("user"); + ---- ++==== + +-an `OidcUserInfo` with no claims set: ++It also includes an `OidcUserInfo` with no claims set: + ++==== + [source,json] + ---- + assertThat(user.getUserInfo().getClaims()).isEmpty(); + ---- ++==== + +-and a `Collection` of authorities with just one authority, `SCOPE_read`: ++It also includes a `Collection` of authorities with just one authority, `SCOPE_read`: + ++==== + [source,json] + ---- + assertThat(user.getAuthorities()).hasSize(1); + assertThat(user.getAuthorities()).containsExactly(new SimpleGrantedAuthority("SCOPE_read")); + ---- ++==== + +-Spring Security does the necessary work to make sure that the `OidcUser` instance is available for <>. ++Spring Security makes sure that the `OidcUser` instance is available for <>. + +-Further, it also links that `OidcUser` to a simple instance of `OAuth2AuthorizedClient` that it deposits into a mock `ServerOAuth2AuthorizedClientRepository`. ++Further, it also links the `OidcUser` to a simple instance of `OAuth2AuthorizedClient` that it deposits into a mock `ServerOAuth2AuthorizedClientRepository`. + This can be handy if your tests <>.. + + [[webflux-testing-oidc-login-authorities]] +@@ -226,8 +246,9 @@ This can be handy if your tests < foo(@AuthenticationPrincipal OidcUser oidcUser) { + // ... + } + ---- ++==== + +-In that case, you'd want to specify that claim with the `idToken()` method: ++In that case, you can specify that claim with the `idToken()` method: + ++==== + [source,java] + ---- + client +@@ -264,25 +289,27 @@ client + ) + .get().uri("/endpoint").exchange(); + ---- ++==== + +-since `OidcUser` collects its claims from `OidcIdToken`. ++That works because `OidcUser` collects its claims from `OidcIdToken`. + + [[webflux-testing-oidc-login-user]] + ==== Additional Configurations + +-There are additional methods, too, for further configuring the authentication; it simply depends on what data your controller expects: ++There are additional methods, too, for further configuring the authentication, depending on what data your controller expects: + +-* `userInfo(OidcUserInfo.Builder)` - For configuring the `OidcUserInfo` instance +-* `clientRegistration(ClientRegistration)` - For configuring the associated `OAuth2AuthorizedClient` with a given `ClientRegistration` +-* `oidcUser(OidcUser)` - For configuring the complete `OidcUser` instance ++* `userInfo(OidcUserInfo.Builder)`: Configures the `OidcUserInfo` instance ++* `clientRegistration(ClientRegistration)`: Configures the associated `OAuth2AuthorizedClient` with a given `ClientRegistration` ++* `oidcUser(OidcUser)`: Configures the complete `OidcUser` instance + + That last one is handy if you: +-1. Have your own implementation of `OidcUser`, or +-2. Need to change the name attribute ++* Have your own implementation of `OidcUser` or ++* Need to change the name attribute + +-For example, let's say that your authorization server sends the principal name in the `user_name` claim instead of the `sub` claim. ++For example, suppose that your authorization server sends the principal name in the `user_name` claim instead of the `sub` claim. + In that case, you can configure an `OidcUser` by hand: + ++==== + [source,java] + ---- + OidcUser oidcUser = new DefaultOidcUser( +@@ -294,15 +321,17 @@ client + .mutateWith(mockOidcLogin().oidcUser(oidcUser)) + .get().uri("/endpoint").exchange(); + ---- ++==== + + [[webflux-testing-oauth2-login]] + === Testing OAuth 2.0 Login + +-As with <>, 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. ++As with <>, testing OAuth 2.0 Login presents a similar challenge: mocking a grant flow. ++Because of that, Spring Security also has test support for non-OIDC use cases. + +-Let's say that we've got a controller that gets the logged-in user as an `OAuth2User`: ++Suppose that we have a controller that gets the logged-in user as an `OAuth2User`: + ++==== + [source,java] + ---- + @GetMapping("/endpoint") +@@ -310,32 +339,39 @@ public Mono foo(@AuthenticationPrincipal OAuth2User oauth2User) { + return Mono.just(oauth2User.getAttribute("sub")); + } + ---- ++==== + +-In that case, we can tell Spring Security to include a default `OAuth2User` using the `SecurityMockServerConfigurers#oauth2User` method, like so: ++In that case, we can tell Spring Security to include a default `OAuth2User` by using the `SecurityMockServerConfigurers#oauth2User` method: + ++==== + [source,java] + ---- + client + .mutateWith(mockOAuth2Login()) + .get().uri("/endpoint").exchange(); + ---- ++==== + +-What this will do is configure the associated `MockServerRequest` with an `OAuth2User` that includes a simple `Map` of attributes and `Collection` of granted authorities. ++The preceding example configures the associated `MockServerRequest` with an `OAuth2User` that includes a simple `Map` of attributes and a `Collection` of granted authorities. + +-Specifically, it will include a `Map` with a key/value pair of `sub`/`user`: ++Specifically, it includes a `Map` with a key/value pair of `sub`/`user`: + ++==== + [source,json] + ---- + assertThat((String) user.getAttribute("sub")).isEqualTo("user"); + ---- ++==== + +-and a `Collection` of authorities with just one authority, `SCOPE_read`: ++It also includes a `Collection` of authorities with just one authority, `SCOPE_read`: + ++==== + [source,json] + ---- + assertThat(user.getAuthorities()).hasSize(1); + assertThat(user.getAuthorities()).containsExactly(new SimpleGrantedAuthority("SCOPE_read")); + ---- ++==== + + Spring Security does the necessary work to make sure that the `OAuth2User` instance is available for <>. + +@@ -347,8 +383,9 @@ This can be handy if your tests < foo(@AuthenticationPrincipal OAuth2User oauth2User) { + // ... + } + ---- ++==== + +-In that case, you'd want to specify that attribute with the `attributes()` method: ++In that case, you can specify that attribute with the `attributes()` method: + ++==== + [source,java] + ---- + client +@@ -385,22 +426,24 @@ client + ) + .get().uri("/endpoint").exchange(); + ---- ++==== + + [[webflux-testing-oauth2-login-user]] + ==== Additional Configurations + +-There are additional methods, too, for further configuring the authentication; it simply depends on what data your controller expects: ++There are additional methods, too, for further configuring the authentication, depending on what data your controller expects: + +-* `clientRegistration(ClientRegistration)` - For configuring the associated `OAuth2AuthorizedClient` with a given `ClientRegistration` +-* `oauth2User(OAuth2User)` - For configuring the complete `OAuth2User` instance ++* `clientRegistration(ClientRegistration)`: Configures the associated `OAuth2AuthorizedClient` with a given `ClientRegistration` ++* `oauth2User(OAuth2User)`: Configures the complete `OAuth2User` instance + + That last one is handy if you: +-1. Have your own implementation of `OAuth2User`, or +-2. Need to change the name attribute ++* Have your own implementation of `OAuth2User` or ++* Need to change the name attribute + +-For example, let's say that your authorization server sends the principal name in the `user_name` claim instead of the `sub` claim. ++For example, suppose that your authorization server sends the principal name in the `user_name` claim instead of the `sub` claim. + In that case, you can configure an `OAuth2User` by hand: + ++==== + [source,java] + ---- + OAuth2User oauth2User = new DefaultOAuth2User( +@@ -412,14 +455,16 @@ client + .mutateWith(mockOAuth2Login().oauth2User(oauth2User)) + .get().uri("/endpoint").exchange(); + ---- ++==== + + [[webflux-testing-oauth2-client]] + === 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: ++For example, your controller may rely on the client credentials grant to get a token that is not associated with the user at all: + +-[source,json] ++==== ++[source,java] + ---- + @GetMapping("/endpoint") + public Mono foo(@RegisteredOAuth2AuthorizedClient("my-app") OAuth2AuthorizedClient authorizedClient) { +@@ -429,51 +474,61 @@ public Mono foo(@RegisteredOAuth2AuthorizedClient("my-app") OAuth2Author + .bodyToMono(String.class); + } + ---- ++==== + +-Simulating this handshake with the authorization server could be cumbersome. +-Instead, you can use `SecurityMockServerConfigurers#oauth2Client` to add a `OAuth2AuthorizedClient` into a mock `ServerOAuth2AuthorizedClientRepository`: ++Simulating this handshake with the authorization server can be cumbersome. ++Instead, you can use `SecurityMockServerConfigurers#oauth2Client` to add a `OAuth2AuthorizedClient` to a mock `ServerOAuth2AuthorizedClientRepository`: + ++==== + [source,java] + ---- + client + .mutateWith(mockOAuth2Client("my-app")) + .get().uri("/endpoint").exchange(); + ---- ++==== + +-What this will do is create an `OAuth2AuthorizedClient` that has a simple `ClientRegistration`, `OAuth2AccessToken`, and resource owner name. ++This creates an `OAuth2AuthorizedClient` that has a simple `ClientRegistration`, a `OAuth2AccessToken`, and a resource owner name. + +-Specifically, it will include a `ClientRegistration` with a client id of "test-client" and client secret of "test-secret": ++Specifically, it includes a `ClientRegistration` with a client ID of `test-client` and a client secret of `test-secret`: + ++==== + [source,json] + ---- + assertThat(authorizedClient.getClientRegistration().getClientId()).isEqualTo("test-client"); + assertThat(authorizedClient.getClientRegistration().getClientSecret()).isEqualTo("test-secret"); + ---- ++==== + +-a resource owner name of "user": ++It also includes a resource owner name of `user`: + ++==== + [source,json] + ---- + assertThat(authorizedClient.getPrincipalName()).isEqualTo("user"); + ---- ++==== + +-and an `OAuth2AccessToken` with just one scope, `read`: ++It also includes an `OAuth2AccessToken` with one scope, `read`: + ++==== + [source,json] + ---- + assertThat(authorizedClient.getAccessToken().getScopes()).hasSize(1); + assertThat(authorizedClient.getAccessToken().getScopes()).containsExactly("read"); + ---- ++==== + +-The client can then be retrieved as normal using `@RegisteredOAuth2AuthorizedClient` in a controller method. ++You can then retrieve the client as usual by using `@RegisteredOAuth2AuthorizedClient` in a controller method. + + [[webflux-testing-oauth2-client-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: ++Consider the following example of how a controller can inspect the scopes: + +-[source,json] ++==== ++[source,java] + ---- + @GetMapping("/endpoint") + public Mono foo(@RegisteredOAuth2AuthorizedClient("my-app") OAuth2AuthorizedClient authorizedClient) { +@@ -487,9 +542,11 @@ public Mono foo(@RegisteredOAuth2AuthorizedClient("my-app") OAuth2Author + // ... + } + ---- ++==== + +-then you can configure the scope using the `accessToken()` method: ++Given a controller that inspects scopes, you can configure the scope by using the `accessToken()` method: + ++==== + [source,java] + ---- + client +@@ -498,22 +555,24 @@ client + ) + .get().uri("/endpoint").exchange(); + ---- ++==== + + [[webflux-testing-oauth2-client-registration]] + ==== Additional Configurations + +-There are additional methods, too, for further configuring the authentication; it simply depends on what data your controller expects: ++You can also use additional methods to further configure the authentication depending on what data your controller expects: + +-* `principalName(String)` - For configuring the resource owner name +-* `clientRegistration(Consumer)` - For configuring the associated `ClientRegistration` +-* `clientRegistration(ClientRegistration)` - For configuring the complete `ClientRegistration` ++* `principalName(String)`; Configures the resource owner name ++* `clientRegistration(Consumer)`: Configures the associated `ClientRegistration` ++* `clientRegistration(ClientRegistration)`: Configures the complete `ClientRegistration` + + That last one is handy if you want to use a real `ClientRegistration` + +-For example, let's say that you are wanting to use one of your app's `ClientRegistration` definitions, as specified in your `application.yml`. ++For example, suppose that you want to use one of your application's `ClientRegistration` definitions, as specified in your `application.yml`. + + In that case, your test can autowire the `ReactiveClientRegistrationRepository` and look up the one your test needs: + ++==== + [source,java] + ---- + @Autowired +@@ -527,32 +586,36 @@ client + ) + .get().uri("/exchange").exchange(); + ---- ++==== + + [[webflux-testing-jwt]] + === Testing JWT Authentication + +-In order to make an authorized request on a resource server, you need a bearer token. +-If your resource server is configured for JWTs, then this would mean that the bearer token needs to be signed and then encoded according to the JWT specification. +-All of this can be quite daunting, especially when this isn't the focus of your test. ++To make an authorized request on a resource server, you need a bearer token. ++If your resource server is configured for JWTs, the bearer token needs to be signed and then encoded according to the JWT specification. ++All of this can be quite daunting, especially when this is not the focus of your test. + +-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: ++Fortunately, there are a number of simple ways in which you can overcome this difficulty and let your tests focus on authorization and not on representing bearer tokens. ++We look at two of them in the next two subsections. + + ==== `mockJwt() WebTestClientConfigurer` + +-The first way is via a `WebTestClientConfigurer`. ++The first way is with a `WebTestClientConfigurer`. + The simplest of these would look something like this: + ++==== + [source,java] + ---- + client + .mutateWith(mockJwt()).get().uri("/endpoint").exchange(); + ---- ++==== + +-What this will do is create a mock `Jwt`, passing it correctly through any authentication APIs so that it's available for your authorization mechanisms to verify. ++This example creates a mock `Jwt` and passes it through any authentication APIs so that it is available for your authorization mechanisms to verify. + + By default, the `JWT` that it creates has the following characteristics: + ++==== + [source,json] + ---- + { +@@ -563,9 +626,11 @@ By default, the `JWT` that it creates has the following characteristics: + } + } + ---- ++==== + +-And the resulting `Jwt`, were it tested, would pass in the following way: ++The resulting `Jwt`, were it tested, would pass in the following way: + ++==== + [source,java] + ---- + assertThat(jwt.getTokenValue()).isEqualTo("token"); +@@ -574,11 +639,13 @@ assertThat(jwt.getSubject()).isEqualTo("sub"); + GrantedAuthority authority = jwt.getAuthorities().iterator().next(); + assertThat(authority.getAuthority()).isEqualTo("read"); + ---- ++==== + +-These values can, of course be configured. ++Note that you configure these values. + +-Any headers or claims can be configured with their corresponding methods: ++You can also configure any headers or claims with their corresponding methods: + ++==== + [source,java] + ---- + client +@@ -593,28 +660,34 @@ client + .mutateWith(mockJwt().jwt(jwt -> jwt.claims(claims -> claims.remove("scope")))) + .get().uri("/endpoint").exchange(); + ---- ++==== + + The `scope` and `scp` claims are processed the same way here as they are in a normal bearer token request. + However, this can be overridden simply by providing the list of `GrantedAuthority` instances that you need for your test: + ++==== + [source,java] + ---- + client + .mutateWith(jwt().authorities(new SimpleGrantedAuthority("SCOPE_messages"))) + .get().uri("/endpoint").exchange(); + ---- ++==== + +-Or, if you have a custom `Jwt` to `Collection` converter, you can also use that to derive the authorities: ++Alternatively, if you have a custom `Jwt` to `Collection` converter, you can also use that to derive the authorities: + ++==== + [source,java] + ---- + client + .mutateWith(jwt().authorities(new MyConverter())) + .get().uri("/endpoint").exchange(); + ---- ++==== + +-You can also specify a complete `Jwt`, for which `{security-api-url}org/springframework/security/oauth2/jwt/Jwt.Builder.html[Jwt.Builder]` comes quite handy: ++You can also specify a complete `Jwt`, for which `{security-api-url}org/springframework/security/oauth2/jwt/Jwt.Builder.html[Jwt.Builder]` is quite handy: + ++==== + [source,java] + ---- + Jwt jwt = Jwt.withTokenValue("token") +@@ -626,12 +699,14 @@ client + .mutateWith(mockJwt().jwt(jwt)) + .get().uri("/endpoint").exchange(); + ---- ++==== + +-==== `authentication()` `WebTestClientConfigurer` ++==== `authentication()` and `WebTestClientConfigurer` + + The second way is by using the `authentication()` `Mutator`. +-Essentially, you can instantiate your own `JwtAuthenticationToken` and provide it in your test, like so: ++You can instantiate your own `JwtAuthenticationToken` and provide it in your test: + ++==== + [source,java] + ---- + Jwt jwt = Jwt.withTokenValue("token") +@@ -645,8 +720,9 @@ client + .mutateWith(authentication(token)) + .get().uri("/endpoint").exchange(); + ---- ++==== + +-Note that as an alternative to these, you can also mock the `ReactiveJwtDecoder` bean itself with a `@MockBean` annotation. ++Note that, as an alternative to these, you can also mock the `ReactiveJwtDecoder` bean itself with a `@MockBean` annotation. + + [[webflux-testing-opaque-token]] + === Testing Opaque Token Authentication +@@ -654,8 +730,9 @@ Note that as an alternative to these, you can also mock the `ReactiveJwtDecoder` + Similar to <>, 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. + +-Let's say that we've got a controller that retrieves the authentication as a `BearerTokenAuthentication`: ++Suppose you have a controller that retrieves the authentication as a `BearerTokenAuthentication`: + ++==== + [source,java] + ---- + @GetMapping("/endpoint") +@@ -663,42 +740,50 @@ public Mono foo(BearerTokenAuthentication authentication) { + return Mono.just((String) authentication.getTokenAttributes("sub")); + } + ---- ++==== + +-In that case, we can tell Spring Security to include a default `BearerTokenAuthentication` using the `SecurityMockServerConfigurers#opaqueToken` method, like so: ++In that case, you can tell Spring Security to include a default `BearerTokenAuthentication` by using the `SecurityMockServerConfigurers#opaqueToken` method: + ++==== + [source,java] + ---- + client + .mutateWith(mockOpaqueToken()) + .get().uri("/endpoint").exchange(); + ---- ++==== + +-What this will do is configure the associated `MockHttpServletRequest` with a `BearerTokenAuthentication` that includes a simple `OAuth2AuthenticatedPrincipal`, `Map` of attributes, and `Collection` of granted authorities. ++This example configures the associated `MockHttpServletRequest` with a `BearerTokenAuthentication` that includes a simple `OAuth2AuthenticatedPrincipal`, a `Map` of attributes, and a `Collection` of granted authorities. + +-Specifically, it will include a `Map` with a key/value pair of `sub`/`user`: ++Specifically, it includes a `Map` with a key/value pair of `sub`/`user`: + ++==== + [source,json] + ---- + assertThat((String) token.getTokenAttributes().get("sub")).isEqualTo("user"); + ---- ++==== + +-and a `Collection` of authorities with just one authority, `SCOPE_read`: ++It also includes a `Collection` of authorities with just one authority, `SCOPE_read`: + ++==== + [source,json] + ---- + assertThat(token.getAuthorities()).hasSize(1); + assertThat(token.getAuthorities()).containsExactly(new SimpleGrantedAuthority("SCOPE_read")); + ---- ++==== + +-Spring Security does the necessary work to make sure that the `BearerTokenAuthentication` instance is available for your controller methods. ++Spring Security makes sure that the `BearerTokenAuthentication` instance is available for your controller methods. + + [[webflux-testing-opaque-token-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. + +-In this case, you can supply what granted authorities you need using the `authorities()` method: ++In those cases, you can supply the granted authorities you need by using the `authorities()` method: + ++==== + [source,java] + ---- + client +@@ -707,15 +792,17 @@ client + ) + .get().uri("/endpoint").exchange(); + ---- ++==== + + [[webflux-testing-opaque-token-attributes]] + ==== 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. ++While granted authorities are quite common across all of Spring Security, we also have attributes in the case of OAuth 2.0. + +-Let's say, for example, that you've got a `user_id` attribute that indicates the user's id in your system. +-You might access it like so in a controller: ++Suppose, for example, that you have a `user_id` attribute that indicates the user's ID in your system. ++You might access it as follows in a controller: + ++==== + [source,java] + ---- + @GetMapping("/endpoint") +@@ -724,9 +811,11 @@ public Mono foo(BearerTokenAuthentication authentication) { + // ... + } + ---- ++==== + +-In that case, you'd want to specify that attribute with the `attributes()` method: ++In that case, you can specify that attribute with the `attributes()` method: + ++==== + [source,java] + ---- + client +@@ -735,21 +824,23 @@ client + ) + .get().uri("/endpoint").exchange(); + ---- ++==== + + [[webflux-testing-opaque-token-principal]] + ==== Additional Configurations + +-There are additional methods, too, for further configuring the authentication; it simply depends on what data your controller expects. ++You can also use additional methods to further configure the authentication, depending on what data your controller expects. + +-One such is `principal(OAuth2AuthenticatedPrincipal)`, which you can use to configure the complete `OAuth2AuthenticatedPrincipal` instance that underlies the `BearerTokenAuthentication` ++One such method is `principal(OAuth2AuthenticatedPrincipal)`, which you can use to configure the complete `OAuth2AuthenticatedPrincipal` instance that underlies the `BearerTokenAuthentication`. + +-It's handy if you: +-1. Have your own implementation of `OAuth2AuthenticatedPrincipal`, or +-2. Want to specify a different principal name ++It is handy if you: ++* Have your own implementation of `OAuth2AuthenticatedPrincipal` or ++* Want to specify a different principal name + +-For example, let's say that your authorization server sends the principal name in the `user_name` attribute instead of the `sub` attribute. ++For example, suppose that your authorization server sends the principal name in the `user_name` attribute instead of the `sub` attribute. + In that case, you can configure an `OAuth2AuthenticatedPrincipal` by hand: + ++==== + [source,java] + ---- + Map attributes = Collections.singletonMap("user_name", "foo_user"); +@@ -762,5 +853,6 @@ client + .mutateWith(mockOpaqueToken().principal(principal)) + .get().uri("/endpoint").exchange(); + ---- ++==== + +-Note that as an alternative to using `mockOpaqueToken()` test support, you can also mock the `OpaqueTokenIntrospector` bean itself with a `@MockBean` annotation. ++Note that, as an alternative to using `mockOpaqueToken()` test support, you can also mock the `OpaqueTokenIntrospector` bean itself with a `@MockBean` annotation. +diff --git a/docs/manual/src/docs/asciidoc/_includes/reactive/webclient.adoc b/docs/manual/src/docs/asciidoc/_includes/reactive/webclient.adoc +index 181ac58b2c..5de656a0e8 100644 +--- a/docs/manual/src/docs/asciidoc/_includes/reactive/webclient.adoc ++++ b/docs/manual/src/docs/asciidoc/_includes/reactive/webclient.adoc +@@ -1,13 +1,9 @@ + = WebClient + +-[NOTE] +-==== +-The following documentation is for use within Reactive environments. +-For Servlet environments, refer to <> environments. +-==== +- ++NOTE: The documentation in this section is for use within Reactive environments. ++For Servlet environments, see <>. + +-Spring Framework has built in support for setting a Bearer token. ++Spring Framework has built-in support for setting a Bearer token: + + ==== + .Java +@@ -29,17 +25,17 @@ webClient.get() + + Spring Security builds on this support to provide additional benefits: + +-* Spring Security will automatically refresh expired tokens (if a refresh token is present) +-* If an access token is requested and not present, Spring Security will automatically request the access token. +-** For authorization_code this involves performing the redirect and then replaying the original request +-** For client_credentials the token is simply requested and saved ++* Spring Security automatically refreshes expired tokens (if a refresh token is present). ++* If an access token is requested and not present, Spring Security automatically requests the access token. ++** For `authorization_code`, this involves performing the redirect and then replaying the original request. ++** For `client_credentials`, the token is requested and saved. + * Support for the ability to transparently include the current OAuth token or explicitly select which token should be used. + + [[webclient-setup]] + == WebClient OAuth2 Setup + +-The first step is ensuring to setup the `WebClient` correctly. +-An example of setting up `WebClient` in a fully reactive environment can be found below: ++The first step is ensuring that the `WebClient` is set up correctly. ++The following example shows how to set up `WebClient` in a fully reactive environment: + + ==== + .Java +@@ -81,8 +77,8 @@ fun webClient(clientRegistrations: ReactiveClientRegistrationRepository, + [[webclient-implicit]] + == Implicit OAuth2AuthorizedClient + +-If we set `defaultOAuth2AuthorizedClient` to `true` in our setup and the user authenticated with oauth2Login (i.e. OIDC), then the current authentication is used to automatically provide the access token. +-Alternatively, if we set `defaultClientRegistrationId` to a valid `ClientRegistration` id, that registration is used to provide the access token. ++If we set `defaultOAuth2AuthorizedClient` to `true` in our setup and the user authenticated with `oauth2Login` (OIDC), the current authentication is used to automatically provide the access token. ++Alternatively, if we set `defaultClientRegistrationId` to a valid `ClientRegistration` ID, that registration is used to provide the access token. + This is convenient, but in environments where not all endpoints should get the access token, it is dangerous (you might provide the wrong access token to an endpoint). + + ==== +@@ -110,8 +106,8 @@ val body: Mono = webClient + [[webclient-explicit]] + == Explicit OAuth2AuthorizedClient + +-The `OAuth2AuthorizedClient` can be explicitly provided by setting it on the requests attributes. +-In the example below we resolve the `OAuth2AuthorizedClient` using Spring WebFlux or Spring MVC argument resolver support. ++You can explicitly provide the `OAuth2AuthorizedClient` by setting it on the request attributes. ++In the next example, we resolve the `OAuth2AuthorizedClient` by using Spring WebFlux or the Spring MVC argument resolver support. + However, it does not matter how the `OAuth2AuthorizedClient` is resolved. + + ==== +@@ -147,8 +143,8 @@ fun explicit(@RegisteredOAuth2AuthorizedClient("client-id") authorizedClient: OA + [[webclient-clientregistrationid]] + == clientRegistrationId + +-Alternatively, it is possible to specify the `clientRegistrationId` on the request attributes and the `WebClient` will attempt to lookup the `OAuth2AuthorizedClient`. +-If it is not found, one will automatically be acquired. ++Alternatively, you can specify the `clientRegistrationId` on the request attributes, and the `WebClient` tries to look up the `OAuth2AuthorizedClient`. ++If it is not found, one is automatically acquired. + + ==== + .Java +diff --git a/docs/manual/src/docs/asciidoc/_includes/reactive/webflux.adoc b/docs/manual/src/docs/asciidoc/_includes/reactive/webflux.adoc +index d6a5263a35..d181b8c100 100644 +--- a/docs/manual/src/docs/asciidoc/_includes/reactive/webflux.adoc ++++ b/docs/manual/src/docs/asciidoc/_includes/reactive/webflux.adoc +@@ -2,7 +2,7 @@ + = WebFlux Security + + Spring Security's WebFlux support relies on a `WebFilter` and works the same for Spring WebFlux and Spring WebFlux.Fn. +-You can find a few sample applications that demonstrate the code below: ++A few sample applications demonstrate the code: + + * Hello WebFlux {gh-samples-url}/boot/hellowebflux[hellowebflux] + * Hello WebFlux.Fn {gh-samples-url}/boot/hellowebfluxfn[hellowebfluxfn] +@@ -11,7 +11,7 @@ You can find a few sample applications that demonstrate the code below: + + == Minimal WebFlux Security Configuration + +-You can find a minimal WebFlux Security configuration below: ++The following listing shows a minimal WebFlux Security configuration: + + .Minimal WebFlux Security Configuration + ==== +@@ -53,11 +53,11 @@ class HelloWebfluxSecurityConfig { + ----- + ==== + +-This configuration provides form and http basic authentication, sets up authorization to require an authenticated user for accessing any page, sets up a default log in page and a default log out page, sets up security related HTTP headers, CSRF protection, and more. ++This configuration provides form and HTTP basic authentication, sets up authorization to require an authenticated user for accessing any page, sets up a default login page and a default logout page, sets up security related HTTP headers, adds CSRF protection, and more. + + == Explicit WebFlux Security Configuration + +-You can find an explicit version of the minimal WebFlux Security configuration below: ++The following page shows an explicit version of the minimal WebFlux Security configuration: + + .Explicit WebFlux Security Configuration + ==== +@@ -123,17 +123,18 @@ class HelloWebfluxSecurityConfig { + ==== + + This configuration explicitly sets up all the same things as our minimal configuration. +-From here you can easily make the changes to the defaults. ++From here, you can more easily make changes to the defaults. + +-You can find more examples of explicit configuration in unit tests, by searching https://github.com/spring-projects/spring-security/search?q=path%3Aconfig%2Fsrc%2Ftest%2F+EnableWebFluxSecurity[EnableWebFluxSecurity in the `config/src/test/` directory]. ++You can find more examples of explicit configuration in unit tests, by searching for https://github.com/spring-projects/spring-security/search?q=path%3Aconfig%2Fsrc%2Ftest%2F+EnableWebFluxSecurity[`EnableWebFluxSecurity` in the `config/src/test/` directory]. + + [[jc-webflux-multiple-filter-chains]] + === Multiple Chains Support + +-You can configure multiple `SecurityWebFilterChain` instances to separate configuration by `RequestMatcher` s. ++You can configure multiple `SecurityWebFilterChain` instances to separate configuration by `RequestMatcher` instances. + +-For example, you can isolate configuration for URLs that start with `/api`, like so: ++For example, you can isolate configuration for URLs that start with `/api`: + ++==== + [source,java] + ---- + @Configuration +@@ -171,15 +172,15 @@ static class MultiSecurityHttpConfig { + } + ---- + +-<1> Configure a `SecurityWebFilterChain` with an `@Order` to specify which `SecurityWebFilterChain` Spring Security should consider first +-<2> Use `PathPatternParserServerWebExchangeMatcher` to state that this `SecurityWebFilterChain` will only apply to URL paths that start with `/api/` +-<3> Specify the authentication mechanisms that will be used for `/api/**` endpoints +-<4> Create another instance of `SecurityWebFilterChain` with lower precedence to match all other URLs +-<5> Specify the authentication mechanisms that will be used for the rest of the application +- +-Spring Security will select one `SecurityWebFilterChain` `@Bean` for each request. +-It will match the requests in order by the `securityMatcher` definition. ++<1> Configure a `SecurityWebFilterChain` with an `@Order` to specify which `SecurityWebFilterChain` Spring Security should consider first. ++<2> Use `PathPatternParserServerWebExchangeMatcher` to state that this `SecurityWebFilterChain` applies only to URL paths that start with `/api/`. ++<3> Specify the authentication mechanisms that is used for `/api/**` endpoints. ++<4> Create another instance of `SecurityWebFilterChain` with lower precedence to match all other URLs. ++<5> Specify the authentication mechanisms that is used for the rest of the application. ++==== + +-In this case, that means that if the URL path starts with `/api`, then Spring Security will use `apiHttpSecurity`. +-If the URL does not start with `/api` then Spring Security will default to `webHttpSecurity`, which has an implied `securityMatcher` that matches any request. ++Spring Security selects one `SecurityWebFilterChain` `@Bean` for each request. ++It matches the requests in order by the `securityMatcher` definition. + ++In this case, that means that, if the URL path starts with `/api`, Spring Security uses `apiHttpSecurity`. ++If the URL does not start with `/api`, Spring Security defaults to `webHttpSecurity`, which has an implied `securityMatcher` that matches any request. +diff --git a/docs/manual/src/docs/asciidoc/_includes/reactive/x509.adoc b/docs/manual/src/docs/asciidoc/_includes/reactive/x509.adoc +index 694b905093..515ae7533e 100644 +--- a/docs/manual/src/docs/asciidoc/_includes/reactive/x509.adoc ++++ b/docs/manual/src/docs/asciidoc/_includes/reactive/x509.adoc +@@ -1,9 +1,11 @@ + [[reactive-x509]] + = Reactive X.509 Authentication + +-Similar to <>, reactive x509 authentication filter allows extracting an authentication token from a certificate provided by a client. ++Similar to <>, the reactive x509 authentication filter allows extracting an authentication token from a certificate provided by a client. + +-Below is an example of a reactive x509 security configuration: ++The folloiwng example shows a reactive x509 security configuration: ++ ++==== + [source,java] + ---- + @Bean +@@ -16,11 +18,13 @@ public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) { + return http.build(); + } + ---- ++==== + +-In the configuration above, when neither `principalExtractor` nor `authenticationManager` is provided defaults will be used. The default principal extractor is `SubjectDnX509PrincipalExtractor` which extracts the CN (common name) field from a certificate provided by a client. The default authentication manager is `ReactivePreAuthenticatedAuthenticationManager` which performs user account validation, checking that user account with a name extracted by `principalExtractor` exists and it is not locked, disabled, or expired. ++In the preceding configuration, when neither `principalExtractor` nor `authenticationManager` is provided, defaults are used. The default principal extractor is `SubjectDnX509PrincipalExtractor`, which extracts the CN (common name) field from a certificate provided by a client. The default authentication manager is `ReactivePreAuthenticatedAuthenticationManager`, which performs user account validation, checking that a user account with a name extracted by `principalExtractor` exists and that it is not locked, disabled, or expired. + +-The next example demonstrates how these defaults can be overridden. ++The following example demonstrates how these defaults can be overridden: + ++==== + [source,java] + ---- + @Bean +@@ -46,7 +50,8 @@ public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) { + return http.build(); + } + ---- ++==== + +-In this example, a username is extracted from the OU field of a client certificate instead of CN, and account lookup using `ReactiveUserDetailsService` is not performed at all. Instead, if the provided certificate issued to an OU named "Trusted Org Unit", a request will be authenticated. ++In the previous example, a username is extracted from the OU field of a client certificate instead of CN, and account lookup using `ReactiveUserDetailsService` is not performed at all. Instead, if the provided certificate issued to an OU named "`Trusted Org Unit`", a request is authenticated. + + For an example of configuring Netty and `WebClient` or `curl` command-line tool to use mutual TLS and enable X.509 authentication, please refer to https://github.com/spring-projects/spring-security-samples/tree/main/servlet/java-configuration/authentication/x509. +diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/appendix/database-schema.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/appendix/database-schema.adoc +index ab840e131f..8998047ec2 100644 +--- a/docs/manual/src/docs/asciidoc/_includes/servlet/appendix/database-schema.adoc ++++ b/docs/manual/src/docs/asciidoc/_includes/servlet/appendix/database-schema.adoc +@@ -1,19 +1,19 @@ + [[appendix-schema]] + = Security Database Schema +-There are various database schema used by the framework and this appendix provides a single reference point to them all. +-You only need to provide the tables for the areas of functionality you require. ++The framework uses various database schema. This appendix provides a single reference point to them all. ++You need only provide the tables for the areas of functionality you require. + + DDL statements are given for the HSQLDB database. +-You can use these as a guideline for defining the schema for the database you are using. ++You can use these as a guideline for defining the schema for the database you use. + + + == User Schema +-The standard JDBC implementation of the `UserDetailsService` (`JdbcDaoImpl`) requires tables to load the password, account status (enabled or disabled) and a list of authorities (roles) for the user. +-You will need to adjust this schema to match the database dialect you are using. ++The standard JDBC implementation of the `UserDetailsService` (`JdbcDaoImpl`) requires tables to load the password, account status (enabled or disabled), and a list of authorities (roles) for the user. ++You need to adjust this schema to match the database dialect you use: + ++==== + [source] + ---- +- + create table users( + username varchar_ignorecase(50) not null primary key, + password varchar_ignorecase(50) not null, +@@ -27,8 +27,13 @@ create table authorities ( + ); + create unique index ix_auth_username on authorities (username,authority); + ---- ++==== + + === For Oracle database ++ ++The following listing shows the Oracle variant of the schema creation commands: ++ ++==== + [source] + ---- + CREATE TABLE USERS ( +@@ -45,15 +50,15 @@ CREATE TABLE AUTHORITIES ( + ALTER TABLE AUTHORITIES ADD CONSTRAINT AUTHORITIES_UNIQUE UNIQUE (USERNAME, AUTHORITY); + ALTER TABLE AUTHORITIES ADD CONSTRAINT AUTHORITIES_FK1 FOREIGN KEY (USERNAME) REFERENCES USERS (USERNAME) ENABLE; + ---- ++==== + + === Group Authorities + Spring Security 2.0 introduced support for group authorities in `JdbcDaoImpl`. +-The table structure if groups are enabled is as follows. +-You will need to adjust this schema to match the database dialect you are using. ++You need to adjust the following schema to match the database dialect you use: + ++==== + [source] + ---- +- + create table groups ( + id bigint generated by default as identity(start with 0) primary key, + group_name varchar_ignorecase(50) not null +@@ -72,16 +77,18 @@ create table group_members ( + constraint fk_group_members_group foreign key(group_id) references groups(id) + ); + ---- ++==== + +-Remember that these tables are only required if you are using the provided JDBC `UserDetailsService` implementation. +-If you write your own or choose to implement `AuthenticationProvider` without a `UserDetailsService`, then you have complete freedom over how you store the data, as long as the interface contract is satisfied. ++Remember that these tables are required only if you us the provided JDBC `UserDetailsService` implementation. ++If you write your own or choose to implement `AuthenticationProvider` without a `UserDetailsService`, you have complete freedom over how you store the data, as long as the interface contract is satisfied. + + + == Persistent Login (Remember-Me) Schema +-This table is used to store data used by the more secure <> remember-me implementation. +-If you are using `JdbcTokenRepositoryImpl` either directly or through the namespace, then you will need this table. +-Remember to adjust this schema to match the database dialect you are using. ++This table is used to store the data used by the more secure <> remember-me implementation. ++If you use `JdbcTokenRepositoryImpl` either directly or through the namespace, you need this table. ++Remember to adjust this schema to match the database dialect you use: + ++==== + [source] + ---- + +@@ -93,21 +100,22 @@ create table persistent_logins ( + ); + + ---- ++==== + + [[dbschema-acl]] + == ACL Schema +-There are four tables used by the Spring Security <> implementation. ++The Spring Security <> implementation uses four tables. + +-. `acl_sid` stores the security identities recognised by the ACL system. +-These can be unique principals or authorities which may apply to multiple principals. +-. `acl_class` defines the domain object types to which ACLs apply. ++* `acl_sid` stores the security identities recognised by the ACL system. ++These can be unique principals or authorities, which may apply to multiple principals. ++* `acl_class` defines the domain object types to which ACLs apply. + The `class` column stores the Java class name of the object. +-. `acl_object_identity` stores the object identity definitions of specific domain objects. +-. `acl_entry` stores the ACL permissions which apply to a specific object identity and security identity. ++* `acl_object_identity` stores the object identity definitions of specific domain objects. ++* `acl_entry` stores the ACL permissions, each of which applies to a specific object identity and security identity. + +-It is assumed that the database will auto-generate the primary keys for each of the identities. ++We assume that the database auto-generates the primary keys for each of the identities. + The `JdbcMutableAclService` has to be able to retrieve these when it has created a new row in the `acl_sid` or `acl_class` tables. +-It has two properties which define the SQL needed to retrieve these values `classIdentityQuery` and `sidIdentityQuery`. ++It has two properties that define the SQL needed to retrieve these values `classIdentityQuery` and `sidIdentityQuery`. + Both of these default to `call identity()` + + The ACL artifact JAR contains files for creating the ACL schema in HyperSQL (HSQLDB), PostgreSQL, MySQL/MariaDB, Microsoft SQL Server, and Oracle Database. +@@ -116,9 +124,9 @@ These schemas are also demonstrated in the following sections. + === HyperSQL + The default schema works with the embedded HSQLDB database that is used in unit tests within the framework. + ++==== + [source,ddl] + ---- +- + create table acl_sid( + id bigint generated by default as identity(start with 100) not null primary key, + principal boolean not null, +@@ -159,8 +167,16 @@ create table acl_entry( + constraint foreign_fk_5 foreign key(sid) references acl_sid(id) + ); + ---- ++==== + + === PostgreSQL ++ ++For PostgreSQL, you have to set the `classIdentityQuery` and `sidIdentityQuery` properties of `JdbcMutableAclService` to the following values, respectively: ++ ++* `select currval(pg_get_serial_sequence('acl_class', 'id'))` ++* `select currval(pg_get_serial_sequence('acl_sid', 'id'))` ++ ++==== + [source,ddl] + ---- + create table acl_sid( +@@ -203,13 +219,11 @@ create table acl_entry( + constraint foreign_fk_5 foreign key(sid) references acl_sid(id) + ); + ---- +- +-You will have to set the `classIdentityQuery` and `sidIdentityQuery` properties of `JdbcMutableAclService` to the following values, respectively: +- +-* `select currval(pg_get_serial_sequence('acl_class', 'id'))` +-* `select currval(pg_get_serial_sequence('acl_sid', 'id'))` ++==== + + === MySQL and MariaDB ++ ++==== + [source,ddl] + ---- + CREATE TABLE acl_sid ( +@@ -252,8 +266,11 @@ CREATE TABLE acl_entry ( + CONSTRAINT fk_acl_entry_acl FOREIGN KEY (sid) REFERENCES acl_sid (id) + ) ENGINE=InnoDB; + ---- ++==== + + === Microsoft SQL Server ++ ++==== + [source,ddl] + ---- + CREATE TABLE acl_sid ( +@@ -296,8 +313,10 @@ CREATE TABLE acl_entry ( + CONSTRAINT fk_acl_entry_acl FOREIGN KEY (sid) REFERENCES acl_sid (id) + ); + ---- +- ++==== + === Oracle Database ++ ++==== + [source,ddl] + ---- + CREATE TABLE ACL_SID ( +@@ -363,13 +382,14 @@ BEGIN + SELECT ACL_ENTRY_SQ.NEXTVAL INTO :NEW.ID FROM DUAL; + END; + ---- +- ++==== + + [[dbschema-oauth2-client]] + == OAuth 2.0 Client Schema +-The JDBC implementation of <> (`JdbcOAuth2AuthorizedClientService`) requires a table for persisting `OAuth2AuthorizedClient`(s). +-You will need to adjust this schema to match the database dialect you are using. ++The JDBC implementation of <> (`JdbcOAuth2AuthorizedClientService`) requires a table for persisting `OAuth2AuthorizedClient` instances. ++You need to adjust this schema to match the database dialect you use. + ++==== + [source,ddl] + ---- + CREATE TABLE oauth2_authorized_client ( +@@ -386,3 +406,4 @@ CREATE TABLE oauth2_authorized_client ( + PRIMARY KEY (client_registration_id, principal_name) + ); + ---- ++==== +diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/appendix/faq.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/appendix/faq.adoc +index 196c3992fe..e3481e3ab0 100644 +--- a/docs/manual/src/docs/asciidoc/_includes/servlet/appendix/faq.adoc ++++ b/docs/manual/src/docs/asciidoc/_includes/servlet/appendix/faq.adoc +@@ -1,6 +1,8 @@ + [[appendix-faq]] + == Spring Security FAQ + ++This FAQ has the following sections: ++ + * <> + * <> + * <> +@@ -9,57 +11,59 @@ + [[appendix-faq-general-questions]] + === General Questions + +-. <> +-. <> +-. <> +-. <> ++This FAQ answers the following general questions: ++ ++* <> ++* <> ++* <> ++* <> + + + [[appendix-faq-other-concerns]] +-==== Will Spring Security take care of all my application security requirements? ++==== Can 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. +-Check out the https://www.owasp.org/[OWASP web site] for information on the major issues facing web application developers and the countermeasures you can use against them. ++Spring Security provides you with a 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 with which you should be familiar, preferably before you start development so that you can design and code with them in mind from the beginning. ++Check out the https://www.owasp.org/[OWASP web site] for information on the major issues that face web application developers and the countermeasures you can use against them. + + + [[appendix-faq-web-xml]] +-==== Why not just use web.xml security? ++==== Why Not 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: ++Suppose you are developing an enterprise application based on Spring. ++You typically need to address four security concerns : authentication, web request security, service layer security (your methods that implement business logic), and domain object instance security (different domain objects can have different permissions). With these typical requirements in mind, we have the following considerations: + +-. __Authentication__: The servlet specification provides an approach to authentication. +-However, you will need to configure the container to perform authentication which typically requires editing of container-specific "realm" settings. +-This makes a non-portable configuration, and if you need to write an actual Java class to implement the container's authentication interface, it becomes even more non-portable. +-With Spring Security you achieve complete portability - right down to the WAR level. ++* _Authentication_: The servlet specification provides an approach to authentication. ++However, you need to configure the container to perform authentication, which typically requires editing of container-specific "`realm`" settings. ++This makes a non-portable configuration. Also, if you need to write an actual Java class to implement the container's authentication interface, it becomes even more non-portable. ++With Spring Security, you achieve complete portability -- right down to the WAR level. + Also, Spring Security offers a choice of production-proven authentication providers and mechanisms, meaning you can switch your authentication approaches at deployment time. + This is particularly valuable for software vendors writing products that need to work in an unknown target environment. + +-. __Web request security:__ The servlet specification provides an approach to secure your request URIs. +-However, these URIs can only be expressed in the servlet specification's own limited URI path format. ++* _Web request security:_ The servlet specification provides an approach to secure your request URIs. ++However, these URIs can be expressed only in the servlet specification's own limited URI path format. + Spring Security provides a far more comprehensive approach. +-For instance, you can use Ant paths or regular expressions, you can consider parts of the URI other than simply the requested page (e.g. +-you can consider HTTP GET parameters) and you can implement your own runtime source of configuration data. +-This means your web request security can be dynamically changed during the actual execution of your webapp. ++For instance, you can use Ant paths or regular expressions, you can consider parts of the URI other than simply the requested page (for example, ++you can consider HTTP GET parameters), and you can implement your own runtime source of configuration data. ++This means that you can dynamically change your web request security during the actual execution of your web application. + +-. __Service layer and domain object security:__ The absence of support in the servlet specification for services layer security or domain object instance security represent serious limitations for multi-tiered applications. +-Typically developers either ignore these requirements, or implement security logic within their MVC controller code (or even worse, inside the views). There are serious disadvantages with this approach: ++* _Service layer and domain object security:_ The absence of support in the servlet specification for services layer security or domain object instance security represents serious limitations for multi-tiered applications. ++Typically, developers either ignore these requirements or implement security logic within their MVC controller code (or, even worse, inside the views). There are serious disadvantages with this approach: + +-.. __Separation of concerns:__ Authorization is a crosscutting concern and should be implemented as such. +-MVC controllers or views implementing authorization code makes it more difficult to test both the controller and authorization logic, more difficult to debug, and will often lead to code duplication. ++** _Separation of concerns:_ Authorization is a crosscutting concern and should be implemented as such. ++MVC controllers or views that implement authorization code makes it more difficult to test both the controller and the authorization logic, is more difficult to debug, and often leads to code duplication. + +-.. __Support for rich clients and web services:__ If an additional client type must ultimately be supported, any authorization code embedded within the web layer is non-reusable. +-It should be considered that Spring remoting exporters only export service layer beans (not MVC controllers). As such authorization logic needs to be located in the services layer to support a multitude of client types. ++** _Support for rich clients and web services:_ If an additional client type must ultimately be supported, any authorization code embedded within the web layer is non-reusable. ++It should be considered that Spring remoting exporters export only service layer beans (not MVC controllers). As a result, authorization logic needs to be located in the services layer to support a multitude of client types. + +-.. __Layering issues:__ An MVC controller or view is simply the incorrect architectural layer to implement authorization decisions concerning services layer methods or domain object instances. +-Whilst the Principal may be passed to the services layer to enable it to make the authorization decision, doing so would introduce an additional argument on every services layer method. +-A more elegant approach is to use a ThreadLocal to hold the Principal, although this would likely increase development time to a point where it would become more economical (on a cost-benefit basis) to simply use a dedicated security framework. ++** _Layering issues:_ An MVC controller or view is the incorrect architectural layer in which to implement authorization decisions concerning services layer methods or domain object instances. ++While the principal may be passed to the services layer to enable it to make the authorization decision, doing so would introduce an additional argument on every services layer method. ++A more elegant approach is to use a `ThreadLocal` to hold the principal, although this would likely increase development time to a point where it would become more economical (on a cost-benefit basis) to use a dedicated security framework. + +-.. __Authorisation code quality:__ It is often said of web frameworks that they "make it easier to do the right things, and harder to do the wrong things". Security frameworks are the same, because they are designed in an abstract manner for a wide range of purposes. +-Writing your own authorization code from scratch does not provide the "design check" a framework would offer, and in-house authorization code will typically lack the improvements that emerge from widespread deployment, peer review and new versions. ++** _Authorisation code quality:_ It is often said of web frameworks that they "`make it easier to do the right things, and harder to do the wrong things`". Security frameworks are the same, because they are designed in an abstract manner for a wide range of purposes. ++Writing your own authorization code from scratch does not provide the "`design check`" a framework would offer, and in-house authorization code typically lacks the improvements that emerge from widespread deployment, peer review, and new versions. + +-For simple applications, servlet specification security may just be enough. ++For simple applications, servlet specification security may be enough. + Although when considered within the context of web container portability, configuration requirements, limited web request security flexibility, and non-existent services layer and domain object instance security, it becomes clear why developers often look to alternative solutions. + + +@@ -67,138 +71,141 @@ Although when considered within the context of web container portability, config + ==== 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. ++Ideally, you should use the latest release versions to avoid problems. + + Spring Security 2.0.x requires a minimum JDK version of 1.4 and is built against Spring 2.0.x. +-It should also be compatible with applications using Spring 2.5.x. ++It should also be compatible with applications that use 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. +-What could be wrong? ++==== I have a complex scenario. What could be wrong? ++ ++(This answer address complex scenarios in general by dealing with a particular scenario.) + +-Or substitute an alternative complex scenario... ++Suppose you are new to Spring Security and 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). You have copied some configuration files but have found that it does not work. What could be wrong? + +-Realistically, you need an understanding of the technologies you are intending to use before you can successfully build applications with them. ++You need an understanding of the technologies you intend to use before you can successfully build applications with them. + Security is complicated. +-Setting up a simple configuration using a login form and some hard-coded users using Spring Security's namespace is reasonably straightforward. ++Setting up a simple configuration by using a login form and some hard-coded users with Spring Security's namespace is reasonably straightforward. + Moving to using a backed JDBC database is also easy enough. +-But if you try and jump straight to a complicated deployment scenario like this you will almost certainly be frustrated. +-There is a big jump in the learning curve required to set up systems like CAS, configure LDAP servers and install SSL certificates properly. ++However, if you try to jump straight to a complicated deployment scenario like this scenario, you are almost certain to be frustrated. ++There is a big jump in the learning curve required to set up systems such as CAS, configure LDAP servers, and install SSL certificates properly. + So you need to take things one step at a time. + +-From a Spring Security perspective, the first thing you should do is follow the "Getting Started" guide on the web site. ++From a Spring Security perspective, the first thing you should do is follow the "`Getting Started`" guide on the web site. + This will take you through a series of steps to get up and running and get some idea of how the framework operates. +-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. ++If you use other technologies with which you are not familiar, 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 + +-. Authentication +-.. <> +-.. <> +-.. <> +-.. <> +-.. <> +-.. <> +-. Session Management +-.. <> +-.. <> +-.. <> +-.. <> +-.. <> +-. Miscellaneous +-.. <> +-.. <> +-.. <> +-.. <> +-.. <> ++This section addresses the most common problems that people encounter when using Spring Security: ++ ++* Authentication ++** <> ++** <> ++** <> ++** <> ++** <> ++** <> ++* Session Management ++** <> ++** <> ++** <> ++** <> ++** <> ++* Miscellaneous ++** <> ++** <> ++** <> ++** <> ++** <> + + [[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 is 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. ++It does not say why, as it is good practice to avoid giving details that might help an attacker guess account names or passwords. + +-This also means that if you ask this question in the forum, you will not get an answer unless you provide additional information. +-As with any issue you should check the output from the debug log, note any exception stacktraces and related messages. +-Step through the code in a debugger to see where the authentication fails and why. +-Write a test case which exercises your authentication configuration outside of the application. ++This also means that, if you ask this question online, you should not expect an answer unless you provide additional information. ++As with any issue, you should check the output from the debug log and note any exception stacktraces and related messages. ++You should step through the code in a debugger to see where the authentication fails and why. ++You should also write a test case which exercises your authentication configuration outside of the application. + More often than not, the failure is due to a difference in the password data stored in a database and that entered by the user. +-If you are using hashed passwords, make sure the value stored in your database is __exactly__ the same as the value produced by the `PasswordEncoder` configured in your application. ++If you use hashed passwords, make sure the value stored in your database is _exactly_ the same as the value produced by the `PasswordEncoder` configured in your application. + + + [[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 is 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. ++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`. + +-If your AccessDecisionManager includes an AuthenticatedVoter, you can use the attribute "IS_AUTHENTICATED_ANONYMOUSLY". This is automatically available if you are using the standard namespace configuration setup. ++If your `AccessDecisionManager` includes an `AuthenticatedVoter`, you can use the `IS_AUTHENTICATED_ANONYMOUSLY` attribute. This is automatically available if you use the standard namespace configuration setup. + +-From Spring Security 2.0.1 onwards, when you are using namespace-based configuration, a check will be made on loading the application context and a warning message logged if your login page appears to be protected. ++From Spring Security 2.0.1 onwards, when you use namespace-based configuration, a check is made on loading the application context and a warning message logged if your login page appears to be protected. + + + [[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 a message of "Access is denied (user is anonymous);". What is wrong? + +-This is a debug level message which occurs the first time an anonymous user attempts to access a protected resource. ++The following listing shows a debug level message that occurs the first time an anonymous user attempts to access a protected resource: + ++==== + [source] + ---- +- + DEBUG [ExceptionTranslationFilter] - Access is denied (user is anonymous); redirecting to authentication entry point + org.springframework.security.AccessDeniedException: Access is denied + at org.springframework.security.vote.AffirmativeBased.decide(AffirmativeBased.java:68) + at org.springframework.security.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:262) +- + ---- ++==== + +-It is normal and shouldn't be anything to worry about. ++It is normal and is not something 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 have 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. ++The most common reason for this is that your browser has cached the page and you are seeing a copy that is being retrieved from the browsers cache. ++Verify this by checking whether the browser is actually sending the request (check your server access logs and 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. + 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 a message of "An Authentication object was not found in the SecurityContext". What is 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. ++The following listing shows another debug-level message that occurs the first time an anonymous user attempts to access a protected resource. However, this listing shows what happens when you do not have an `AnonymousAuthenticationFilter` in your filter chain configuration: + ++==== + [source] + ---- +- + DEBUG [ExceptionTranslationFilter] - Authentication exception occurred; redirecting to authentication entry point + org.springframework.security.AuthenticationCredentialsNotFoundException: + An Authentication object was not found in the SecurityContext + at org.springframework.security.intercept.AbstractSecurityInterceptor.credentialsNotFound(AbstractSecurityInterceptor.java:342) + at org.springframework.security.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:254) + ---- ++==== + +-It is normal and shouldn't be anything to worry about. ++It is normal and is not something to worry about. + + + [[appendix-faq-ldap-authentication]] +-==== I can't get LDAP authentication to work. +-What's wrong with my configuration? ++==== I cannot get LDAP authentication to work. What is wrong with my configuration? + +-Note that the permissions for an LDAP directory often do not allow you to read the password for a user. +-Hence it is often not possible to use the <> where Spring Security compares the stored password with the one submitted by the user. +-The most common approach is to use LDAP "bind", which is one of the operations supported by https://en.wikipedia.org/wiki/Lightweight_Directory_Access_Protocol[the LDAP protocol]. With this approach, Spring Security validates the password by attempting to authenticate to the directory as the user. ++Note that the permissions for an LDAP directory often do not let you read the password for a user. ++Hence, it is often not possible to use the <> where Spring Security compares the stored password with the one submitted by the user. ++The most common approach is to use LDAP "`bind`", which is one of the operations supported by https://en.wikipedia.org/wiki/Lightweight_Directory_Access_Protocol[the LDAP protocol]. With this approach, Spring Security validates the password by trying to authenticate to the directory as the user. + + The most common problem with LDAP authentication is a lack of knowledge of the directory server tree structure and configuration. +-This will be different in different companies, so you have to find it out yourself. +-Before adding a Spring Security LDAP configuration to an application, it's a good idea to write a simple test using standard Java LDAP code (without Spring Security involved), and make sure you can get that to work first. ++This differs from one company to another, so you have to find it out yourself. ++Before adding a Spring Security LDAP configuration to an application, you should write a simple test by using standard Java LDAP code (without Spring Security involved) and make sure you can get that to work first. + For example, to authenticate a user, you could use the following code: + ++==== + [source,java] + ---- +- + @Test + public void ldapAuthenticationIsSuccessful() throws Exception { + Hashtable env = new Hashtable(); +@@ -211,125 +218,126 @@ public void ldapAuthenticationIsSuccessful() throws Exception { + InitialLdapContext ctx = new InitialLdapContext(env, null); + + } +- + ---- ++==== + + ==== Session Management + +-Session management issues are a common source of forum questions. ++Session management issues are a common source of 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. +-You should also understand the difference between secure and non-secure cookies and the implications of using HTTP/HTTPS and switching between the two. ++You should also understand the difference between secure and non-secure cookies and the implications of using HTTP and HTTPS and switching between the two. + Spring Security has nothing to do with maintaining the session or providing session identifiers. + 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. +-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? ++==== I am using Spring Security's concurrent session control to prevent users from logging in more than once at the same time. When I open another browser window after logging in, it does not stop me from logging in again. Why can I log in more than once? + + Browsers generally maintain a single session per browser instance. + You cannot have two separate sessions at once. +-So if you log in again in another window or tab you are just reauthenticating in the same session. +-The server doesn't know anything about tabs, windows or browser instances. +-All it sees are HTTP requests and it ties those to a particular session according to the value of the JSESSIONID cookie that they contain. +-When a user authenticates during a session, Spring Security's concurrent session control checks the number of __other authenticated sessions__ that they have. +-If they are already authenticated with the same session, then re-authenticating will have no effect. ++So, if you log in again in another window or tab, you are reauthenticating in the same session. ++The server does not know anything about tabs, windows, or browser instances. ++All it sees are HTTP requests, and it ties those to a particular session according to the value of the `JSESSIONID` cookie that they contain. ++When a user authenticates during a session, Spring Security's concurrent session control checks the number of _other authenticated sessions_ that they have. ++If they are already authenticated with the same session, re-authenticating has no effect. + + + [[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. +-If you're using an older container, Spring Security invalidates the existing session, creates a new session, and transfers the session data to the new session. +-Changing the session identifier in this manner prevents"session-fixation" attacks. ++If you us a Servlet 3.1 or newer container, the session ID is simply changed. ++If you use an older container, Spring Security invalidates the existing session, creates a new session, and transfers the session data to the new session. ++Changing the session identifier in this manner prevents "`session-fixation`" attacks. + 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. +-It doesn't work - I just end up back at the login page after authenticating. ++==== I use Tomcat (or some other servlet container) and have enabled HTTPS for my login page, switching back to HTTP afterwards. It does not work. I 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. ++This happens because sessions created under HTTPS, for which the session cookie is marked as "`secure`", cannot subsequently be used under HTTP. The browser does not send the cookie back to the server, and any session state (including the security context information) is lost. Starting a session in HTTP first should work, as the session cookie is not marked as secure. + However, Spring Security's https://docs.spring.io/spring-security/site/docs/3.1.x/reference/springsecurity-single.html#ns-session-fixation[Session Fixation Protection] can interfere with this because it results in a new session ID cookie being sent back to the user's browser, usually with the secure flag. +-To get around this, you can disable session fixation protection, but in newer Servlet containers you can also configure session cookies to never use the secure flag. +-Note that switching between HTTP and HTTPS is not a good idea in general, as any application which uses HTTP at all is vulnerable to man-in-the-middle attacks. ++To get around this, you can disable session fixation protection. However, in newer Servlet containers, you can also configure session cookies to never use the secure flag. ++ ++IMPORTANT: Switching between HTTP and HTTPS is not a good idea in general, as any application that uses HTTP at all is vulnerable to man-in-the-middle attacks. + To be truly secure, the user should begin accessing your site in HTTPS and continue using it until they log out. + Even clicking on an HTTPS link from a page accessed over HTTP is potentially risky. +-If you need more convincing, check out a tool like https://www.thoughtcrime.org/software/sslstrip/[sslstrip]. ++If you need more convincing, check out a tool such as https://www.thoughtcrime.org/software/sslstrip/[sslstrip]. + + +-==== I'm not switching between HTTP and HTTPS but my session is still getting lost ++==== I am not switching between HTTP and HTTPS, but my session is still lost. What happened? + +-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. ++Sessions are maintained either by exchanging a session cookie or by adding a `jsessionid` parameter to URLs (this happens automatically if you use 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`, the session is 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 am trying to use the concurrent session-control support, but it does not let me log back in, even if I am sure I have logged out and have not exceeded the allowed sessions. What is wrong? + +-Make sure you have added the listener to your web.xml file. ++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. +-Without it, the session information will not be removed from the registry. +- ++Without it, the session information is not removed from the registry. ++The following example adds a listener in a `web.xml` file: + ++==== + [source,xml] + ---- + + org.springframework.security.web.session.HttpSessionEventPublisher + + ---- ++==== + + [[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 creates a session somewhere, even though I have configured it not to, by setting the create-session attribute to never. What is wrong? + +-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. +-To prevent a JSP from creating a session, add the directive `<%@ page session="false" %>` to the top of the page. ++This usually means that the user's application is creating a session somewhere but that they are not aware of it. ++The most common culprit is a JSP. Many people are not aware that JSPs create sessions by default. ++To prevent a JSP from creating a session, add the `<%@ page session="false" %>` directive to the top of the page. + +-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. ++If you have 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 is to add a `javax.servlet.http.HttpSessionListener`, which calls `Thread.dumpStack()` in the `sessionCreated` method, to your application. + + [[appendix-faq-forbidden-csrf]] +-==== I get a 403 Forbidden when performing a POST ++==== I get a 403 Forbidden when performing a POST. What is wrong? + +-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). ++If an HTTP 403 Forbidden error is returned for HTTP POST but it works for HTTP GET, 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 (the latter is 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 am forwarding a request to another URL by using the RequestDispatcher, but my security constraints are not 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 element, a child element of . ++By default, filters are not applied to forwards or includes. ++If you really want the security filters to be applied to forwards or includes, you have to configure these explicitly in your `web.xml` file by using the `` element, which is a child element of the `` element. + + + [[appendix-faq-method-security-in-web-context]] +-==== I have added Spring Security's 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 element to my application context, but, if I add security annotations to my Spring MVC controller beans (Struts actions etc.), they do not seem to have an effect. Why not? + +-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. +-The beans in these "child" contexts are not visible to the rest of the application. +-The"parent" application context is loaded by the `ContextLoaderListener` you define in your `web.xml` and is visible to all the child contexts. +-This parent context is usually where you define your security configuration, including the `` element). As a result any security constraints applied to methods in these web beans will not be enforced, since the beans cannot be seen from the `DispatcherServlet` context. +-You need to either move the `` declaration to the web context or moved the beans you want secured into the main application context. ++In a Spring web application, the application context that 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 the `web.xml` file. An application can have multiple `DispatcherServlet` instances, each with its own isolated application context. ++The beans in these "`child`" contexts are not visible to the rest of the application. ++The "`parent`" application context is loaded by the `ContextLoaderListener` you define in your `web.xml` file and is visible to all the child contexts. ++This parent context is usually where you define your security configuration, including the `` element. As a result, any security constraints applied to methods in these web beans are not enforced, since the beans cannot be seen from the `DispatcherServlet` context. ++You need to either move the `` declaration to the web context or move the beans you want secured into the main application context. + +-Generally we would recommend applying method security at the service layer rather than on individual web controllers. ++Generally, we recommend applying method security at the service layer rather than on individual web controllers. + + + [[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. +-Why can't I see the user information? ++==== 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 I not see the user information? + +-If you have excluded the request from the security filter chain using the attribute `filters='none'` in the `` element that matches the URL pattern, then the `SecurityContextHolder` will not be populated for that request. ++If you have excluded the request from the security filter chain by using the `filters='none'` attribute in the `` element that matches the URL pattern, the `SecurityContextHolder` is not populated for that request. + Check the debug log to see whether the request is passing through the filter chain. +-(You are reading the debug log, right?). ++(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 does not respect my method security annotations when using the URL attribute. Why not? + +-Method security will not hide links when using the `url` attribute in `` 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. ++Method security does not hide links when using the `url` attribute in ``, because we cannot readily reverse engineer what URL is mapped to what controller endpoint. We are limited because controllers can rely on headers, the current user, and other details to determine what method to invoke. + + [[appendix-faq-architecture]] + === Spring Security Architecture Questions + ++This section addresses common Spring Security architecture questions: ++ + . <> + . <> + . <> +@@ -342,56 +350,56 @@ Method security will not hide links when using the `url` attribute in `> that lists the first-level dependencies for each Spring Security module, with some information on whether they are optional and when they are required. + +-If you are building your project with maven, then adding the appropriate Spring Security modules as dependencies to your pom.xml will automatically pull in the core jars that the framework requires. +-Any which are marked as "optional" in the Spring Security POM files will have to be added to your own pom.xml file if you need them. ++If you build your project with Maven, adding the appropriate Spring Security modules as dependencies to your `pom.xml` file automatically pulls in the core jars that the framework requires. ++Any that are marked as "`optional`" in the Spring Security `pom.xml` files have to be added to your own `pom.xml` file if you need them. + + + [[appendix-faq-apacheds-deps]] + ==== 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: ++If you use Maven, you need to add the following to your `pom.xml` file dependencies: + ++==== + [source] + ---- +- + + org.apache.directory.server + apacheds-core +@@ -404,8 +412,8 @@ If you are using Maven, you need to add the following to your pom dependencies: + 1.5.5 + runtime + +- + ---- ++==== + + The other required jars should be pulled in transitively. + +@@ -413,16 +421,18 @@ The other required jars should be pulled in transitively. + ==== 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. ++It has no function other than to load that data for use by other components within the framework. + It is not responsible for authenticating the user. +-Authenticating a user with a username/password combination is most commonly performed by the `DaoAuthenticationProvider`, which is injected with a `UserDetailsService` to allow it to load the password (and other data) for a user in order to compare it with the submitted value. +-Note that if you are using LDAP, <>. ++Authenticating a user with a username and password combination is most commonly performed by the `DaoAuthenticationProvider`, which is injected with a `UserDetailsService` to let it to load the password (and other data) for a user, to compare it with the submitted value. ++Note that, if you use LDAP, <>. + +-If you want to customize the authentication process then you should implement `AuthenticationProvider` yourself. +-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. ++If you want to customize the authentication process, you should implement `AuthenticationProvider` yourself. ++See this https://spring.io/blog/2010/08/02/spring-security-in-google-app-engine/[ blog article] for an example that integrate Spring Security authentication with Google App Engine. + + [[appendix-faq-howto]] +-=== Common "Howto" Requests ++=== Common "How to" Questions ++ ++This section addresses the most common "How to" (or "How do I") questions about Spring Security: + + . <> + . <> +@@ -435,72 +445,70 @@ 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. +-How do I add support for extra login fields (e.g. +-a company name)? ++==== I need to login in with more information than just the username. How do I add support for extra login fields (such as a company name)? + +-This question comes up repeatedly in the Spring Security forum so you will find more information there by searching the archives (or through google). ++This question comes up repeatedly, so you can find more information by searching online. + +-The submitted login information is processed by an instance of `UsernamePasswordAuthenticationFilter`. You will need to customize this class to handle the extra data field(s). One option is to use your own customized authentication token class (rather than the standard `UsernamePasswordAuthenticationToken`), another is simply to concatenate the extra fields with the username (for example, using a ":" as the separator) and pass them in the username property of `UsernamePasswordAuthenticationToken`. ++The submitted login information is processed by an instance of `UsernamePasswordAuthenticationFilter`. You need to customize this class to handle the extra data fields. One option is to use your own customized authentication token class (rather than the standard `UsernamePasswordAuthenticationToken`). Another option is to concatenate the extra fields with the username (for example, by using a `:` character as the separator) and pass them in the username property of `UsernamePasswordAuthenticationToken`. + +-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. ++You also need to customize the actual authentication process. ++If you use a custom authentication token class, for example, you will have to write an `AuthenticationProvider` (or extend the standard `DaoAuthenticationProvider`) to handle it. If you have concatenated the fields, you can implement your own `UserDetailsService` to split them up and load 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 (such as /thing1#thing2 and /thing1#thing3? + +-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. ++You cannot do this, since the fragment is not transmitted from the browser to the server. ++From the server's perspective, the URLs are identical. + 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? + +-Obviously you can't (without resorting to something like thread-local variables) since the only information supplied to the interface is the username. ++You cannot (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. + +-In a standard web setup, the `getDetails()` method on the `Authentication` object will return an instance of `WebAuthenticationDetails`. If you need additional information, you can inject a custom `AuthenticationDetailsSource` into the authentication filter you are using. +-If you are using the namespace, for example with the `` element, then you should remove this element and replace it with a `` declaration pointing to an explicitly configured `UsernamePasswordAuthenticationFilter`. ++In a standard web setup, the `getDetails()` method on the `Authentication` object returns an instance of `WebAuthenticationDetails`. If you need additional information, you can inject a custom `AuthenticationDetailsSource` into the authentication filter you are using. ++If you use the namespace, for example with the `` element, you should remove this element and replace it with a `` declaration that points to an explicitly configured `UsernamePasswordAuthenticationFilter`. + + + [[appendix-faq-access-session-from-user-service]] + ==== 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. ++You cannot, since the `UserDetailsService` has no awareness of the servlet API. If you want to store custom user data, you should customize the `UserDetails` object that is returned. ++This can then be accessed at any point, through the thread-local `SecurityContextHolder`. A call to `SecurityContextHolder.getContext().getAuthentication().getPrincipal()` returns this custom object. + +-If you really need to access the session, then it must be done by customizing the web tier. ++If you really need to access the session, you must do so by by customizing the web tier. + + + [[appendix-faq-password-in-user-service]] + ==== How do I access the user's password in a UserDetailsService? + +-You can't (and shouldn't). You are probably misunderstanding its purpose. +-See "<>" above. ++You cannot (and should not, even if you find a way to do so). You are probably misunderstanding its purpose. ++See "<>", earlier in the FAQ. + + + [[appendix-faq-dynamic-url-metadata]] +-==== How do I define the secured URLs within an application dynamically? ++==== How do I dynamically define the secured URLs within an application? + +-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. ++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. + + The first thing you should ask yourself is if you really need to do this. +-If an application requires securing, then it also requires that the security be tested thoroughly based on a defined policy. ++If an application needs to be secure, it also requires that the security be tested thoroughly based on a defined policy. + It may require auditing and acceptance testing before being rolled out into a production environment. +-A security-conscious organization should be aware that the benefits of their diligent testing process could be wiped out instantly by allowing the security settings to be modified at runtime by changing a row or two in a configuration database. +-If you have taken this into account (perhaps using multiple layers of security within your application) then Spring Security allows you to fully customize the source of security metadata. ++A security-conscious organization should be aware that the benefits of their diligent testing process could be wiped out instantly by letting the security settings be modified at runtime by changing a row or two in a configuration database. ++If you have taken this into account (perhaps by using multiple layers of security within your application), Spring Security lets you fully customize the source of security metadata. + You can make it fully dynamic if you choose. + +-Both method and web security are protected by subclasses of `AbstractSecurityInterceptor` which is configured with a `SecurityMetadataSource` from which it obtains the metadata for a particular method or filter invocation. +-For web security, the interceptor class is `FilterSecurityInterceptor` and it uses the marker interface `FilterInvocationSecurityMetadataSource`. The "secured object" type it operates on is a `FilterInvocation`. The default implementation which is used (both in the namespace `` and when configuring the interceptor explicitly, stores the list of URL patterns and their corresponding list of "configuration attributes" (instances of `ConfigAttribute`) in an in-memory map. ++Both method and web security are protected by subclasses of `AbstractSecurityInterceptor`, which is configured with a `SecurityMetadataSource` from which it obtains the metadata for a particular method or filter invocation. ++For web security, the interceptor class is `FilterSecurityInterceptor`, and it uses the `FilterInvocationSecurityMetadataSource` marker interface. The "`secured object`" type it operates on is a `FilterInvocation`. The default implementation (which is used both in the namespace `` and when configuring the interceptor explicitly) stores the list of URL patterns and their corresponding list of "`configuration attributes`" (instances of `ConfigAttribute`) in an in-memory map. + +-To load the data from an alternative source, you must be using an explicitly declared security filter chain (typically Spring Security's `FilterChainProxy`) in order to customize the `FilterSecurityInterceptor` bean. +-You can't use the namespace. +-You would then implement `FilterInvocationSecurityMetadataSource` to load the data as you please for a particular `FilterInvocation` footnote:[The `FilterInvocation` object contains the `HttpServletRequest`, so you can obtain the URL or any other relevant information on which to base your decision on what the list of returned attributes will contain.]. A very basic outline would look something like this: ++To load the data from an alternative source, you must use an explicitly declared security filter chain (typically Spring Security's `FilterChainProxy`) to customize the `FilterSecurityInterceptor` bean. ++You cannot use the namespace. ++You would then implement `FilterInvocationSecurityMetadataSource` to load the data as you please for a particular `FilterInvocation`. The `FilterInvocation` object contains the `HttpServletRequest`, so you can obtain the URL or any other relevant information on which to base your decision, based on what the list of returned attributes contains. A basic outline would look something like the following example: + ++==== + [source,java] + ---- +- + public class MyFilterSecurityMetadataSource implements FilterInvocationSecurityMetadataSource { + + public List getAttributes(Object object) { +@@ -523,8 +531,8 @@ You would then implement `FilterInvocationSecurityMetadataSource` to load the da + return FilterInvocation.class.isAssignableFrom(clazz); + } + } +- + ---- ++==== + + For more information, look at the code for `DefaultFilterInvocationSecurityMetadataSource`. + +@@ -532,54 +540,53 @@ 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? + +-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. ++The `LdapAuthenticationProvider` bean (which handles normal LDAP authentication in Spring Security) is configured with two separate strategy interfaces, one that performs the authentication and one that 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 let you specify how these should be retrieved. + +-To use JDBC instead, you can implement the interface yourself, using whatever SQL is appropriate for your schema: ++To use JDBC instead, you can implement the interface yourself, by using whatever SQL is appropriate for your schema: + ++==== + [source,java] + ---- +- +- public class MyAuthoritiesPopulator implements LdapAuthoritiesPopulator { +- @Autowired +- JdbcTemplate template; +- +- List getGrantedAuthorities(DirContextOperations userData, String username) { +- List = template.query("select role from roles where username = ?", +- new String[] {username}, +- new RowMapper() { +- /** +- * We're assuming here that you're using the standard convention of using the role +- * prefix "ROLE_" to mark attributes which are supported by Spring Security's RoleVoter. +- */ +- public GrantedAuthority mapRow(ResultSet rs, int rowNum) throws SQLException { +- return new SimpleGrantedAuthority("ROLE_" + rs.getString(1); +- } +- } +- } +- } +- ++public class MyAuthoritiesPopulator implements LdapAuthoritiesPopulator { ++ @Autowired ++ JdbcTemplate template; ++ ++ List getGrantedAuthorities(DirContextOperations userData, String username) { ++ List = template.query("select role from roles where username = ?", ++ new String[] {username}, ++ new RowMapper() { ++ /** ++ * We assume here that you use the standard convention of using the role ++ * prefix (`ROLE_`) to mark attributes that are supported by Spring Security's RoleVoter. ++ */ ++ public GrantedAuthority mapRow(ResultSet rs, int rowNum) throws SQLException { ++ return new SimpleGrantedAuthority("ROLE_" + rs.getString(1); ++ } ++ }); ++ } ++} + ---- ++==== + +-You would then add a bean of this type to your application context and inject it into the `LdapAuthenticationProvider`. This is covered in the section on configuring LDAP using explicit Spring beans in the LDAP chapter of the reference manual. +-Note that you can't use the namespace for configuration in this case. +-You should also consult the Javadoc for the relevant classes and interfaces. ++You would then add a bean of this type to your application context and inject it into the `LdapAuthenticationProvider`. This is covered in the section on configuring LDAP by using explicit Spring beans in the LDAP chapter of the reference manual. ++Note that you cannot use the namespace for configuration in this case. ++You should also consult the security-api-url[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. +-What can I do short of abandoning namespace use? ++==== 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. +-If you want to do something simple, like modify a bean, or inject a different dependency, you can do this by adding a `BeanPostProcessor` to your configuration. +-More information can be found in the https://docs.spring.io/spring/docs/3.0.x/spring-framework-reference/htmlsingle/spring-framework-reference.html#beans-factory-extension-bpp[Spring Reference Manual]. In order to do this, you need to know a bit about which beans are created, so you should also read the blog article in the above question on <>. ++The namespace functionality is intentionally limited, so it does not cover everything that you can do with plain beans. ++If you want to do something simple, such as modifying a bean or injecting a different dependency, you can do so by adding a `BeanPostProcessor` to your configuration. ++You can find more information in the https://docs.spring.io/spring/docs/3.0.x/spring-framework-reference/htmlsingle/spring-framework-reference.html#beans-factory-extension-bpp[Spring Reference Manual]. To do so, you need to know a bit about which beans are created, so you should also read the blog article mentioned in the earlier question on <>. + +-Normally, you would add the functionality you require to the `postProcessBeforeInitialization` method of `BeanPostProcessor`. Let's say that you want to customize the `AuthenticationDetailsSource` used by the `UsernamePasswordAuthenticationFilter`, (created by the `form-login` element). You want to extract a particular header called `CUSTOM_HEADER` from the request and make use of it while authenticating the user. +-The processor class would look like this: ++Normally, you would add the functionality you require to the `postProcessBeforeInitialization` method of `BeanPostProcessor`. Suppose that you want to customize the `AuthenticationDetailsSource` used by the `UsernamePasswordAuthenticationFilter` (created by the `form-login` element). You want to extract a particular header called `CUSTOM_HEADER` from the request and use it while authenticating the user. ++The processor class would look like the following listing: + ++==== + [source,java] + ---- +- + public class BeanPostProcessor implements BeanPostProcessor { + + public Object postProcessAfterInitialization(Object bean, String name) { +@@ -599,8 +606,8 @@ public class BeanPostProcessor implements BeanPostProcessor { + return bean; + } + } +- + ---- ++==== + + You would then register this bean in your application context. +-Spring will automatically invoke it on the beans defined in the application context. ++Spring automatically invoke it on the beans defined in the application context. +diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/appendix/index.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/appendix/index.adoc +index 5f01cc38d0..682e833a16 100644 +--- a/docs/manual/src/docs/asciidoc/_includes/servlet/appendix/index.adoc ++++ b/docs/manual/src/docs/asciidoc/_includes/servlet/appendix/index.adoc +@@ -1,6 +1,8 @@ + + = Appendix + ++This appendix contains additional information that may help you understand topics within the Spring Security Reference Guide. ++ + include::database-schema.adoc[leveloffset=+1] + + include::namespace.adoc[] +diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/appendix/namespace.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/appendix/namespace.adoc +index 87d802ca8e..9630a228c0 100644 +--- a/docs/manual/src/docs/asciidoc/_includes/servlet/appendix/namespace.adoc ++++ b/docs/manual/src/docs/asciidoc/_includes/servlet/appendix/namespace.adoc +@@ -9,27 +9,29 @@ If you are familiar with this format, you may wish to examine the https://raw.gi + [[nsa-web]] + === Web Application Security + ++This section deals with the XML namespace elements and attributes that deal with the security of web applications. ++ + [[nsa-debug]] + ==== + Enables Spring Security debugging infrastructure. +-This will provide human-readable (multi-line) debugging information to monitor requests coming into the security filters. +-This may include sensitive information, such as request parameters or headers, and should only be used in a development environment. ++This element provides human-readable (multi-line) debugging information to monitor requests that come to the security filters. ++This may include sensitive information (such as request parameters or headers) and should only be used in a development environment. + + [[nsa-http]] + ==== +-If you use an `` element within your application, a `FilterChainProxy` bean named "springSecurityFilterChain" is created and the configuration within the element is used to build a filter chain within ++If you use an `` element within your application, a `FilterChainProxy` bean named `springSecurityFilterChain` is created, and the configuration within the element is used to build a filter chain within + `FilterChainProxy`. +-As of Spring Security 3.1, additional `http` elements can be used to add extra filter chains footnote:[See the pass:specialcharacters,macros[<>] for how to set up the mapping from your `web.xml` ]. +-Some core filters are always created in a filter chain and others will be added to the stack depending on the attributes and child elements which are present. ++As of Spring Security 3.1, you can use additional `http` elements to add extra filter chains. See the <> for how to set up the mapping from your `web.xml`. ++Some core filters are always created in a filter chain and others are added to the stack depending on the attributes and child elements that are present. + The positions of the standard filters are fixed (see + <> in the namespace introduction), removing a common source of errors with previous versions of the framework when users had to configure the filter chain explicitly in the + `FilterChainProxy` bean. +-You can, of course, still do this if you need full control of the configuration. ++You can still controle the order of the filters if you need full control of the configuration. + + +-All filters which require a reference to the <> will be automatically injected with the internal instance created by the namespace configuration. ++All filters that require a reference to the <> are automatically injected with the internal instance created by the namespace configuration. + +-Each `` namespace block always creates an `SecurityContextPersistenceFilter`, an `ExceptionTranslationFilter` and a `FilterSecurityInterceptor`. ++Each `` namespace block always creates an `SecurityContextPersistenceFilter`, an `ExceptionTranslationFilter`, and a `FilterSecurityInterceptor`. + These are fixed and cannot be replaced with alternatives. + + +@@ -39,119 +41,126 @@ The attributes on the `` element control some of the properties on the cor + + + [[nsa-http-access-decision-manager-ref]] +-* **access-decision-manager-ref** +-Optional attribute specifying the ID of the `AccessDecisionManager` implementation which should be used for authorizing HTTP requests. +-By default an `AffirmativeBased` implementation is used for with a `RoleVoter` and an `AuthenticatedVoter`. ++`access-decision-manager-ref`:: ++Optional attribute specifying the ID of the `AccessDecisionManager` implementation that should be used for authorizing HTTP requests. ++By default, an `AffirmativeBased` implementation is used for with a `RoleVoter` and an `AuthenticatedVoter`. + + + [[nsa-http-authentication-manager-ref]] +-* **authentication-manager-ref** ++`authentication-manager-ref`:: + A reference to the `AuthenticationManager` used for the `FilterChain` created by this http element. + + + [[nsa-http-auto-config]] +-* **auto-config** +-Automatically registers a login form, BASIC authentication, logout services. +-If set to "true", all of these capabilities are added (although you can still customize the configuration of each by providing the respective element). +-If unspecified, defaults to "false". ++`auto-config`:: ++Automatically registers a login form, BASIC authentication, and logout services. ++If set to `true`, all of these capabilities are added. (You can still customize the configuration of each by providing the respective element). ++If unspecified, it defaults to `false`. + Use of this attribute is not recommended. +-Use explicit configuration elements instead to avoid confusion. ++Instead, you should use explicit configuration elements to avoid confusion. + + + [[nsa-http-create-session]] +-* **create-session** ++`create-session`:: + Controls the eagerness with which an HTTP session is created by Spring Security classes. + Options include: + +-** `always` - Spring Security will proactively create a session if one does not exist. +-** `ifRequired` - Spring Security will only create a session only if one is required (default value). +-** `never` - Spring Security will never create a session, but will make use of one if the application does. +-** `stateless` - Spring Security will not create a session and ignore the session for obtaining a Spring `Authentication`. ++* `always`: Spring Security proactively creates a session if one does not exist. ++* `ifRequired` (default): Spring Security creates a session only if one is required. ++* `never`: Spring Security never creates a session, but it will make use of one if the application creates one. ++* `stateless`: Spring Security does not create a session and ignores the session for obtaining a Spring `Authentication`. + + [[nsa-http-disable-url-rewriting]] +-* **disable-url-rewriting** ++`disable-url-rewriting`:: + Prevents session IDs from being appended to URLs in the application. + Clients must use cookies if this attribute is set to `true`. + The default is `true`. + + + [[nsa-http-entry-point-ref]] +-* **entry-point-ref** +-Normally the `AuthenticationEntryPoint` used will be set depending on which authentication mechanisms have been configured. +-This attribute allows this behaviour to be overridden by defining a customized `AuthenticationEntryPoint` bean which will start the authentication process. ++`entry-point-ref`:: ++Normally, which `AuthenticationEntryPoint` is used depends on which authentication mechanisms have been configured. ++This attribute lets this behavior be overridden by defining a customized `AuthenticationEntryPoint` bean, which starts the authentication process. + + + [[nsa-http-jaas-api-provision]] +-* **jaas-api-provision** +-If available, runs the request as the `Subject` acquired from the `JaasAuthenticationToken` which is implemented by adding a `JaasApiIntegrationFilter` bean to the stack. ++`jaas-api-provision`:: ++If available, runs the request as the `Subject` acquired from the `JaasAuthenticationToken`, which is implemented by adding a `JaasApiIntegrationFilter` bean to the stack. + Defaults to `false`. + + + [[nsa-http-name]] +-* **name** +-A bean identifier, used for referring to the bean elsewhere in the context. ++`name`:: ++A bean identifier used for referring to the bean elsewhere in the context. + + + [[nsa-http-once-per-request]] +-* **once-per-request** ++`once-per-request`:: + Corresponds to the `observeOncePerRequest` property of `FilterSecurityInterceptor`. + Defaults to `true`. + + + [[nsa-http-pattern]] +-* **pattern** +-Defining a pattern for the <> element controls the requests which will be filtered through the list of filters which it defines. ++`pattern`:: ++Defines a pattern for the <> element controls the requests which are filtered through the list of filters that it defines. + The interpretation is dependent on the configured <>. +-If no pattern is defined, all requests will be matched, so the most specific patterns should be declared first. ++If no pattern is defined, all requests are matched, so the most specific patterns should be declared first. + + + [[nsa-http-realm]] +-* **realm** ++`realm`:: + Sets the realm name used for basic authentication (if enabled). + Corresponds to the `realmName` property on `BasicAuthenticationEntryPoint`. + + + [[nsa-http-request-matcher]] +-* **request-matcher** ++`request-matcher`:: + Defines the `RequestMatcher` strategy used in the `FilterChainProxy` and the beans created by the `intercept-url` to match incoming requests. +-Options are currently `mvc`, `ant`, `regex` and `ciRegex`, for Spring MVC, ant, regular-expression and case-insensitive regular-expression respectively. +-A separate instance is created for each <> element using its <>, <> and <> attributes. +-Ant paths are matched using an `AntPathRequestMatcher`, regular expressions are matched using a `RegexRequestMatcher` and for Spring MVC path matching the `MvcRequestMatcher` is used. ++The current options are ++ ++* `mvc`: Spring MVC ++* `ant` (default): Ant ++* `regex`: Regular expression ++* `ciRegex`: Case-insensitive regular-expression respectively. ++A separate instance is created for each <> element, by using its <>, <>, and <> attributes. ++Ant paths are matched by using an `AntPathRequestMatcher`. Regular expressions are matched by using a `RegexRequestMatcher`. For Spring MVC path matching, the `MvcRequestMatcher` is used. + See the Javadoc for these classes for more details on exactly how the matching is performed. +-Ant paths are the default strategy. + + + [[nsa-http-request-matcher-ref]] +-* **request-matcher-ref** +-A reference to a bean that implements `RequestMatcher` that will determine if this `FilterChain` should be used. +-This is a more powerful alternative to <>. ++`request-matcher-ref`:: ++A reference to a bean that implements `RequestMatcher`, which determines whenter this `FilterChain` should be used. ++This is a more powerful alternative to <>. + + + [[nsa-http-security]] +-* **security** +-A request pattern can be mapped to an empty filter chain, by setting this attribute to `none`. +-No security will be applied and none of Spring Security's features will be available. ++`security`:: ++A request pattern can be mapped to an empty filter chain by setting this attribute to `none`. ++In that case, no security is applied and none of Spring Security's features are available. + + + [[nsa-http-security-context-repository-ref]] +-* **security-context-repository-ref** ++`security-context-repository-ref`:: + Allows injection of a custom `SecurityContextRepository` into the `SecurityContextPersistenceFilter`. + + + [[nsa-http-servlet-api-provision]] +-* **servlet-api-provision** +-Provides versions of `HttpServletRequest` security methods such as `isUserInRole()` and `getPrincipal()` which are implemented by adding a `SecurityContextHolderAwareRequestFilter` bean to the stack. +-Defaults to `true`. ++`servlet-api-provision`:: ++Provides versions of `HttpServletRequest` security methods, such as `isUserInRole()` and `getPrincipal()`, which are implemented by adding a `SecurityContextHolderAwareRequestFilter` bean to the stack. ++Default: `true`. + + + [[nsa-http-use-expressions]] +-* **use-expressions** ++`use-expressions`:: + Enables EL-expressions in the `access` attribute, as described in the chapter on <>. +-The default value is true. ++Default: `true`. + + + [[nsa-http-children]] + ===== Child Elements of ++ ++The `` element has the following child elements, which we describe later in this appendix: ++ + * <> + * <> + * <> +@@ -177,26 +186,26 @@ The default value is true. + + [[nsa-access-denied-handler]] + ==== +-This element allows you to set the `errorPage` property for the default `AccessDeniedHandler` used by the `ExceptionTranslationFilter`, using the <> attribute, or to supply your own implementation using the<> attribute. +-This is discussed in more detail in the section on the <>. ++This element lets you set the `errorPage` property for the default `AccessDeniedHandler` used by the `ExceptionTranslationFilter` (by using the <> attribute) or to supply your own implementation by using the<> attribute. ++This is discussed in more detail in the section on the <>. + + + [[nsa-access-denied-handler-parents]] + ===== Parent Elements of + +-* <> ++The parent element of the `` element is <>. + + [[nsa-access-denied-handler-attributes]] + ===== Attributes + + + [[nsa-access-denied-handler-error-page]] +-* **error-page** +-The access denied page that an authenticated user will be redirected to if they request a page which they don't have the authority to access. ++`error-page`:: ++The access denied page to which an authenticated user is redirected if they request a page to which they do not have access. + + + [[nsa-access-denied-handler-ref]] +-* **ref** ++`ref`:: + Defines a reference to a Spring bean of type `AccessDeniedHandler`. + + +@@ -207,26 +216,26 @@ If no `CorsFilter` or `CorsConfigurationSource` is specified and Spring MVC is o + + [[nsa-cors-attributes]] + ===== Attributes +-The attributes on the `` element control the headers element. ++The attributes on the `` element control the headers element are: + + [[nsa-cors-ref]] +-* **ref** ++`ref`:: + Optional attribute that specifies the bean name of a `CorsFilter`. + + [[nsa-cors-configuration-source-ref]] +-* **cors-configuration-source-ref** ++cors-configuration-source-ref:: + Optional attribute that specifies the bean name of a `CorsConfigurationSource` to be injected into a `CorsFilter` created by the XML namespace. + + [[nsa-cors-parents]] + ===== Parent Elements of + +-* <> ++The parent element of the `` element is <>. + + [[nsa-headers]] + ==== +-This element allows for configuring additional (security) headers to be send with the response. +-It enables easy configuration for several headers and also allows for setting custom headers through the <> element. +-Additional information, can be found in the <> section of the reference. ++This element allows for configuring additional (security) headers to be sent with the response. ++It enables configuration for several headers and also allows for setting custom headers through the <> element. ++You can find additional information in the <> section of the reference. + + ** `Cache-Control`, `Pragma`, and `Expires` - Can be set using the <> element. + This ensures that the browser does not cache your secured pages. +@@ -248,30 +257,30 @@ https://www.w3.org/TR/CSP2/[Content Security Policy (CSP)] is a mechanism that w + + [[nsa-headers-attributes]] + ===== Attributes +-The attributes on the `` element control the headers element. ++The attributes on the `` element control the `` element in the HTML output. + + + [[nsa-headers-defaults-disabled]] +-* **defaults-disabled** +-Optional attribute that specifies to disable the default Spring Security's HTTP response headers. +-The default is false (the default headers are included). ++`defaults-disabled`:: ++Optional attribute that specifies whether to disable the default Spring Security's HTTP response headers. ++The default is `false` (the default headers are included). + + [[nsa-headers-disabled]] +-* **disabled** +-Optional attribute that specifies to disable Spring Security's HTTP response headers. ++`disabled`:: ++Optional attribute that specifies whether to disable Spring Security's HTTP response headers. + The default is false (the headers are enabled). + + + [[nsa-headers-parents]] + ===== Parent Elements of + +-* <> +- ++The parent element of the `` element is the <`>> element. + + + [[nsa-headers-children]] + ===== Child Elements of + ++The `` element has the following possible children: + + * <> + * <> +@@ -285,318 +294,329 @@ The default is false (the headers are enabled). + * <> + + +- + [[nsa-cache-control]] + ==== +-Adds `Cache-Control`, `Pragma`, and `Expires` headers to ensure that the browser does not cache your secured pages. ++The `` element adds the `Cache-Control`, `Pragma`, and `Expires` headers to ensure that the browser does not cache your secured pages. + + + [[nsa-cache-control-attributes]] + ===== Attributes + ++The `` element can have the following attribute: ++ + [[nsa-cache-control-disabled]] +-* **disabled** +-Specifies if Cache Control should be disabled. +-Default false. ++`disabled`:: ++Specifies whether cache control should be disabled. ++Default: `false`. + + + [[nsa-cache-control-parents]] + ===== Parent Elements of + +- +-* <> +- ++The parent of the `` element is the <`>> element. + + + [[nsa-hsts]] + ==== +-When enabled adds the https://tools.ietf.org/html/rfc6797[Strict-Transport-Security] header to the response for any secure request. +-This allows the server to instruct browsers to automatically use HTTPS for future requests. ++When enabled, the `` element adds the https://tools.ietf.org/html/rfc6797[Strict-Transport-Security] header to the response for any secure request. ++This lets the server instruct browsers to automatically use HTTPS for future requests. + + + [[nsa-hsts-attributes]] + ===== Attributes + ++The `` element has the following available attributes: ++ + [[nsa-hsts-disabled]] +-* **disabled** +-Specifies if Strict-Transport-Security should be disabled. +-Default false. ++`disabled`:: ++Specifies whether Strict-Transport-Security should be disabled. ++Default: `false`. + + [[nsa-hsts-include-subdomains]] +-* **include-sub-domains** +-Specifies if subdomains should be included. +-Default true. ++`include-sub-domains`:: ++Specifies whether subdomains should be included. ++Default: true. + + + [[nsa-hsts-max-age-seconds]] +-* **max-age-seconds** ++`max-age-seconds`:: + Specifies the maximum amount of time the host should be considered a Known HSTS Host. + Default one year. + + + [[nsa-hsts-request-matcher-ref]] +-* **request-matcher-ref** +-The RequestMatcher instance to be used to determine if the header should be set. +-Default is if HttpServletRequest.isSecure() is true. ++`request-matcher-ref`:: ++The `RequestMatcher` instance to be used to determine if the header should be set. ++The default is to see whether `HttpServletRequest.isSecure()` is `true`. + + [[nsa-hsts-preload]] +-* **preload** +-Specifies if preload should be included. +-Default false. ++preload:: ++Specifies whether preload should be included. ++Default: `false`. + + [[nsa-hsts-parents]] + ===== Parent Elements of + +-* <> +- ++The parent element of the `` element is the <`>> element. + + + [[nsa-hpkp]] + ==== +-When enabled adds the https://tools.ietf.org/html/rfc7469[Public Key Pinning Extension for HTTP] header to the response for any secure request. +-This allows HTTPS websites to resist impersonation by attackers using mis-issued or otherwise fraudulent certificates. ++When enabled, the `` element adds the https://tools.ietf.org/html/rfc7469[Public Key Pinning Extension for HTTP] header to the response for any secure request. ++This lets HTTPS websites resist impersonation by attackers that use mis-issued or otherwise fraudulent certificates. + + + [[nsa-hpkp-attributes]] + ===== Attributes + ++The `` element can have the following elements: ++ + [[nsa-hpkp-disabled]] +-* **disabled** ++`disabled`:: + Specifies if HTTP Public Key Pinning (HPKP) should be disabled. +-Default true. ++Default: `true`. + + [[nsa-hpkp-include-subdomains]] +-* **include-sub-domains** +-Specifies if subdomains should be included. +-Default false. ++`include-sub-domains`:: ++Specifies whether subdomains should be included. ++Default: `false`. + + + [[nsa-hpkp-max-age-seconds]] +-* **max-age-seconds** +-Sets the value for the max-age directive of the Public-Key-Pins header. +-Default 60 days. ++max-age-seconds:: ++Sets the value for the `max-age` directive of the `Public-Key-Pins` header. ++Default: 60 days (5,184,000 seconds) + + + [[nsa-hpkp-report-only]] +-* **report-only** +-Specifies if the browser should only report pin validation failures. +-Default true. ++`report-only`:: ++Specifies whether the browser should report only pin validation failures. ++Default: `true`. + + + [[nsa-hpkp-report-uri]] +-* **report-uri** ++`report-uri`: + Specifies the URI to which the browser should report pin validation failures. + + + [[nsa-hpkp-parents]] + ===== Parent Elements of + +-* <> ++The parent element of the element is the <`>> element. + + + [[nsa-pins]] + ==== +-The list of pins ++This section describes the attributes and child elements of the `` element. + + + [[nsa-pins-children]] + ===== Child Elements of + +-* <> ++The element has a single child element: <`>>. There can be multiple elements. + + + [[nsa-pin]] + ==== +-A pin is specified using the base64-encoded SPKI fingerprint as value and the cryptographic hash algorithm as attribute ++A element is specified by using the base64-encoded SPKI fingerprint as the value and the cryptographic hash algorithm as the attribute. + + [[nsa-pin-attributes]] + ===== Attributes + + [[nsa-pin-algorithm]] +-* **algorithm** ++`algorithm`:: + The cryptographic hash algorithm. +-Default is SHA256. ++Default: SHA256. + + + [[nsa-pin-parents]] + ===== Parent Elements of + +-* <> ++The parent element of the element is the <`>> element. + + + + [[nsa-content-security-policy]] + ==== +-When enabled adds the https://www.w3.org/TR/CSP2/[Content Security Policy (CSP)] header to the response. +-CSP is a mechanism that web applications can leverage to mitigate content injection vulnerabilities, such as cross-site scripting (XSS). ++When enabled, the `` element adds the https://www.w3.org/TR/CSP2/[Content Security Policy (CSP)] header to the response. ++CSP is a mechanism that web applications can use to mitigate content injection vulnerabilities, such as cross-site scripting (XSS). + + [[nsa-content-security-policy-attributes]] + ===== Attributes + ++The element has the following attributes: ++ + [[nsa-content-security-policy-policy-directives]] +-* **policy-directives** +-The security policy directive(s) for the Content-Security-Policy header or if report-only is set to true, then the Content-Security-Policy-Report-Only header is used. ++`policy-directives`:: ++The security policy directive(s) for the Content-Security-Policy header. If report-only is set to `true`, the Content-Security-Policy-Report-Only header is used. + + [[nsa-content-security-policy-report-only]] +-* **report-only** +-Set to true, to enable the Content-Security-Policy-Report-Only header for reporting policy violations only. +-Defaults to false. ++`report-only`:: ++Whether to enable the Content-Security-Policy-Report-Only header for reporting policy violations only. ++Default: `false`. + + [[nsa-content-security-policy-parents]] + ===== Parent Elements of + +-* <> ++The parent element of the element is <`>>. + + + + [[nsa-referrer-policy]] + ==== +-When enabled adds the https://www.w3.org/TR/referrer-policy/[Referrer Policy] header to the response. ++When enabled, the `` element adds the https://www.w3.org/TR/referrer-policy/[Referrer Policy] header to the response. + + [[nsa-referrer-policy-attributes]] + ===== Attributes + ++The `` element has the following attribute: ++ + [[nsa-referrer-policy-policy]] +-* **policy** +-The policy for the Referrer-Policy header. +-Default "no-referrer". ++policy:: ++The policy for the `Referrer-Policy` header. ++Default: `no-referrer`. + + [[nsa-referrer-policy-parents]] + ===== Parent Elements of + +-* <> ++The parent element of the `` element is the <`>> element. + + + + [[nsa-feature-policy]] + ==== +-When enabled adds the https://wicg.github.io/feature-policy/[Feature Policy] header to the response. ++When enabled, the `` element adds the https://wicg.github.io/feature-policy/[Feature Policy] header to the response. + + [[nsa-feature-policy-attributes]] + ===== Attributes + ++The `` element has the following attribute: ++ + [[nsa-feature-policy-policy-directives]] +-* **policy-directives** ++`policy-directives`:: + The security policy directive(s) for the Feature-Policy header. + + [[nsa-feature-policy-parents]] + ===== Parent Elements of + +-* <> ++The parent element of the element is the <`>> element. + + + + [[nsa-frame-options]] + ==== +-When enabled adds the https://tools.ietf.org/html/draft-ietf-websec-x-frame-options[X-Frame-Options header] to the response, this allows newer browsers to do some security checks and prevent https://en.wikipedia.org/wiki/Clickjacking[clickjacking] attacks. ++When enabled, the `` element adds the https://tools.ietf.org/html/draft-ietf-websec-x-frame-options[X-Frame-Options header] to the response. Doing so lets newer browsers do some security checks and prevent https://en.wikipedia.org/wiki/Clickjacking[clickjacking] attacks. + + + [[nsa-frame-options-attributes]] + ===== Attributes + ++The `` element has the following attributes: ++ + [[nsa-frame-options-disabled]] +-* **disabled** +-If disabled, the X-Frame-Options header will not be included. +-Default false. ++`disabled`:: ++If disabled, the X-Frame-Options header is not included. ++Default: `false`. + + [[nsa-frame-options-policy]] +-* **policy** +-** `DENY` The page cannot be displayed in a frame, regardless of the site attempting to do so. ++`policy`:: ++* `DENY` (default): The page cannot be displayed in a frame, regardless of the site attempting to do so. + This is the default when frame-options-policy is specified. +-** `SAMEORIGIN` The page can only be displayed in a frame on the same origin as the page itself ++* `SAMEORIGIN`: The page can be displayed in a frame only on the same origin as the page itself. + +-+ +- +-In other words, if you specify DENY, not only will attempts to load the page in a frame fail when loaded from other sites, attempts to do so will fail when loaded from the same site. +-On the other hand, if you specify SAMEORIGIN, you can still use the page in a frame as long as the site including it in a frame it is the same as the one serving the page. ++In other words, if you specify `DENY`, not only do attempts to load the page in a frame fail when loaded from other sites, attempts to do so fail when loaded from the same site. ++On the other hand, if you specify `SAMEORIGIN`, you can still use the page in a frame as long as the site including it in a frame is the same site as the one serving the page. + + + + [[nsa-frame-options-parents]] + ===== Parent Elements of + +-* <> ++The parent element of the `` element is the <`>> element. + + + + [[nsa-xss-protection]] + ==== +-Adds the https://blogs.msdn.com/b/ie/archive/2008/07/02/ie8-security-part-iv-the-xss-filter.aspx[X-XSS-Protection header] to the response to assist in protecting against https://en.wikipedia.org/wiki/Cross-site_scripting#Non-Persistent[reflected / Type-1 Cross-Site Scripting (XSS)] attacks. +-This is in no-way a full protection to XSS attacks! ++The `` adds the https://blogs.msdn.com/b/ie/archive/2008/07/02/ie8-security-part-iv-the-xss-filter.aspx[X-XSS-Protection header] to the response, to assist in protecting against https://en.wikipedia.org/wiki/Cross-site_scripting#Non-Persistent[reflected / Type-1 Cross-Site Scripting (XSS)] attacks. ++NOTE: Full protection against XSS attacks is not possible. + + + [[nsa-xss-protection-attributes]] + ===== Attributes + ++The `` element has the following attributes: + + [[nsa-xss-protection-disabled]] +-* **xss-protection-disabled** +-Do not include the header for https://en.wikipedia.org/wiki/Cross-site_scripting#Non-Persistent[reflected / Type-1 Cross-Site Scripting (XSS)] protection. ++`xss-protection-disabled`:: ++If set to `true`, do not include the header for https://en.wikipedia.org/wiki/Cross-site_scripting#Non-Persistent[reflected / Type-1 Cross-Site Scripting (XSS)] protection. + + + [[nsa-xss-protection-enabled]] + * **xss-protection-enabled** +-Explicitly enable or disable https://en.wikipedia.org/wiki/Cross-site_scripting#Non-Persistent[reflected / Type-1 Cross-Site Scripting (XSS)] protection. ++Whether to explicitly enable or disable https://en.wikipedia.org/wiki/Cross-site_scripting#Non-Persistent[reflected / Type-1 Cross-Site Scripting (XSS)] protection. + + + [[nsa-xss-protection-block]] + * **xss-protection-block** +-When true and xss-protection-enabled is true, adds mode=block to the header. ++When `true` and `xss-protection-enabled` is `true`, adds `mode=block` to the header. + This indicates to the browser that the page should not be loaded at all. +-When false and xss-protection-enabled is true, the page will still be rendered when an reflected attack is detected but the response will be modified to protect against the attack. +-Note that there are sometimes ways of bypassing this mode which can often times make blocking the page more desirable. ++When `false` and `xss-protection-enabled` is `true`, the page is still rendered when a reflected attack is detected, but the response is modified to protect against the attack. ++Note that there are sometimes ways of bypassing this mode, which can often times make blocking the page more desirable. + + + [[nsa-xss-protection-parents]] + ===== Parent Elements of + +-* <> ++The parent element of the `` is the <`>> element. + + + + [[nsa-content-type-options]] + ==== +-Add the X-Content-Type-Options header with the value of nosniff to the response. ++The `` element adds the `X-Content-Type-Options` header with a value of `nosniff` to the response. + This https://blogs.msdn.com/b/ie/archive/2008/09/02/ie8-security-part-vi-beta-2-update.aspx[disables MIME-sniffing] for IE8+ and Chrome extensions. + + + [[nsa-content-type-options-attributes]] + ===== Attributes + ++The `` element has the following attribute: ++ + [[nsa-content-type-options-disabled]] +-* **disabled** +-Specifies if Content Type Options should be disabled. +-Default false. ++`disabled`:: ++Specifies whether Content Type Options should be disabled. ++Default: `false`. + + [[nsa-content-type-options-parents]] + ===== Parent Elements of + +- +-* <> ++The parent element of the `` element is the <`>> element. + + + + [[nsa-header]] + ====
+-Add additional headers to the response, both the name and value need to be specified. ++The `
` element adds additional headers to the response. Both the name and value of each added header need to be specified in a `` element (a child of the `
` element). To add multiple headers, add multiple `` elements. + + + [[nsa-header-attributes]] + ===== Attributes + ++The `` element has the following attributes: + + [[nsa-header-name]] +-* **header-name** +-The `name` of the header. ++`header-name`:: ++The `name` of the header to add. + + + [[nsa-header-value]] +-* **value** ++value:: + The `value` of the header to add. + + + [[nsa-header-ref]] +-* **ref** ++`ref`:: + Reference to a custom implementation of the `HeaderWriter` interface. + + +@@ -604,335 +624,341 @@ Reference to a custom implementation of the `HeaderWriter` interface. + ===== Parent Elements of
+ + +-* <> ++The parent element of the `
` is the <`>> element. + + + + [[nsa-anonymous]] + ==== +-Adds an `AnonymousAuthenticationFilter` to the stack and an `AnonymousAuthenticationProvider`. +-Required if you are using the `IS_AUTHENTICATED_ANONYMOUSLY` attribute. ++The `` element adds an `AnonymousAuthenticationFilter` to the stack and adds an `AnonymousAuthenticationProvider`. ++This element is required if you use the `IS_AUTHENTICATED_ANONYMOUSLY` attribute. + + + [[nsa-anonymous-parents]] + ===== Parent Elements of + +- +-* <> ++The parent element of the `` element is the <`>> element. + + + + [[nsa-anonymous-attributes]] + ===== Attributes + ++The `` element has the following attributes: + + [[nsa-anonymous-enabled]] +-* **enabled** +-With the default namespace setup, the anonymous "authentication" facility is automatically enabled. +-You can disable it using this property. ++`enabled`:: ++With the default namespace setup, the anonymous "`authentication`" facility is automatically enabled. ++You can disable it by setting this property. + + + [[nsa-anonymous-granted-authority]] +-* **granted-authority** ++`granted-authority`:: + The granted authority that should be assigned to the anonymous request. +-Commonly this is used to assign the anonymous request particular roles, which can subsequently be used in authorization decisions. +-If unset, defaults to `ROLE_ANONYMOUS`. ++Commonly, this attribute is used to assign the anonymous request particular roles, which can subsequently be used in authorization decisions. ++If unset, it defaults to `ROLE_ANONYMOUS`. + + + [[nsa-anonymous-key]] +-* **key** +-The key shared between the provider and filter. ++`key`:: ++The key shared between the provider and the filter. + This generally does not need to be set. +-If unset, it will default to a secure randomly generated value. +-This means setting this value can improve startup time when using the anonymous functionality since secure random values can take a while to be generated. ++If unset, it defaults to a secure randomly generated value. ++This means that setting this value can improve startup time when using the anonymous functionality, since secure random values can take a while to be generated. + + + [[nsa-anonymous-username]] +-* **username** ++username:: + The username that should be assigned to the anonymous request. +-This allows the principal to be identified, which may be important for logging and auditing. +-if unset, defaults to `anonymousUser`. ++This lets the principal be identified, which may be important for logging and auditing. ++Defaults: `anonymousUser` + + + [[nsa-csrf]] + ==== +-This element will add https://en.wikipedia.org/wiki/Cross-site_request_forgery[Cross Site Request Forger (CSRF)] protection to the application. +-It also updates the default RequestCache to only replay "GET" requests upon successful authentication. +-Additional information can be found in the <> section of the reference. ++The `> section of the reference. + + + [[nsa-csrf-parents]] +-===== Parent Elements of ++===== Parent Element of + +- +-* <> ++The parent element of the `` element is the <> element. + + + + [[nsa-csrf-attributes]] + ===== Attributes + ++The `` element has the following attributes: ++ + [[nsa-csrf-disabled]] +-* **disabled** +-Optional attribute that specifies to disable Spring Security's CSRF protection. +-The default is false (CSRF protection is enabled). +-It is highly recommended to leave CSRF protection enabled. ++`disabled`:: ++Optional attribute that specifies whether to disable Spring Security's CSRF protection. ++Default: `false` (CSRF protection is enabled) ++We highly recommended leaving CSRF protection enabled. + + [[nsa-csrf-token-repository-ref]] +-* **token-repository-ref** +-The CsrfTokenRepository to use. +-The default is `HttpSessionCsrfTokenRepository`. ++`token-repository-ref`:: ++The `CsrfTokenRepository` to use. ++Default: `HttpSessionCsrfTokenRepository` + + + [[nsa-csrf-request-matcher-ref]] +-* **request-matcher-ref** +-The RequestMatcher instance to be used to determine if CSRF should be applied. +-Default is any HTTP method except "GET", "TRACE", "HEAD", "OPTIONS". ++request-matcher-ref:: ++The `RequestMatcher` instance to be used to determine whether CSRF should be applied. ++The default is any HTTP method except `GET`, `TRACE`, `HEAD`, `OPTIONS`. + + + [[nsa-custom-filter]] + ==== +-This element is used to add a filter to the filter chain. +-It doesn't create any additional beans but is used to select a bean of type `javax.servlet.Filter` which is already defined in the application context and add that at a particular position in the filter chain maintained by Spring Security. ++The `` element adds a filter to the filter chain. ++It does not create any additional beans but is used to select a bean of type `javax.servlet.Filter` which is already defined in the application context and add that at a particular position in the filter chain maintained by Spring Security. + Full details can be found in the <>. + + + [[nsa-custom-filter-parents]] + ===== Parent Elements of + +- +-* <> ++The parent element of the `` is the <`>> element. + + + + [[nsa-custom-filter-attributes]] + ===== Attributes + ++The `` element has the following attributes: + + [[nsa-custom-filter-after]] +-* **after** +-The filter immediately after which the custom-filter should be placed in the chain. +-This feature will only be needed by advanced users who wish to mix their own filters into the security filter chain and have some knowledge of the standard Spring Security filters. ++`after`:: ++The filter immediately after which the custom filter should be placed in the chain. ++This feature is needed only by advanced users who wish to mix their own filters into the security filter chain and have some knowledge of the standard Spring Security filters. + The filter names map to specific Spring Security implementation filters. + + + [[nsa-custom-filter-before]] +-* **before** +-The filter immediately before which the custom-filter should be placed in the chain ++`before`:: ++The filter immediately before which the custom filter should be placed in the chain. + + + [[nsa-custom-filter-position]] +-* **position** +-The explicit position at which the custom-filter should be placed in the chain. +-Use if you are replacing a standard filter. ++`position`:: ++The explicit position at which the custom filter should be placed in the chain. ++Use this attribute to replace a standard filter. + + + [[nsa-custom-filter-ref]] +-* **ref** ++ref:: + Defines a reference to a Spring bean that implements `Filter`. + + + [[nsa-expression-handler]] + ==== +-Defines the `SecurityExpressionHandler` instance which will be used if expression-based access-control is enabled. +-A default implementation (with no ACL support) will be used if not supplied. ++Defines the `SecurityExpressionHandler` instance to be used if expression-based access control is enabled. ++A default implementation (with no ACL support) is used if none is supplied. + + + [[nsa-expression-handler-parents]] + ===== Parent Elements of + ++The `` has the following parent elements: + +-* <> +-* <> +-* <> ++* <> ++* <> ++* <> + + + + [[nsa-expression-handler-attributes]] + ===== Attributes + ++The `` element has the following attribute: + + [[nsa-expression-handler-ref]] +-* **ref** ++`ref`:: + Defines a reference to a Spring bean that implements `SecurityExpressionHandler`. + + + [[nsa-form-login]] + ==== +-Used to add an `UsernamePasswordAuthenticationFilter` to the filter stack and an `LoginUrlAuthenticationEntryPoint` to the application context to provide authentication on demand. +-This will always take precedence over other namespace-created entry points. +-If no attributes are supplied, a login page will be generated automatically at the URL "/login" footnote:[ +-This feature is really just provided for convenience and is not intended for production (where a view technology will have been chosen and can be used to render a customized login page). +-The class `DefaultLoginPageGeneratingFilter` is responsible for rendering the login page and will provide login forms for both normal form login and/or OpenID if required. +-] The behaviour can be customized using the <` Attributes>>. ++Used to add an `UsernamePasswordAuthenticationFilter` to the filter stack and a `LoginUrlAuthenticationEntryPoint` to the application context, to provide authentication on demand. ++This always takes precedence over other namespace-created entry points. ++If no attributes are supplied, a login page is generated automatically at the `/login` URL. ++You can customize this behavior by setting the <` Attributes>>. ++ ++NOTE: This feature is provided for convenience and is not intended for production (where a view technology should have been chosen and can be used to render a customized login page). ++The class `DefaultLoginPageGeneratingFilter` class is responsible for rendering the login page and provide login forms for both normal form login and OpenID if required. + + + [[nsa-form-login-parents]] + ===== Parent Elements of + + +-* <> ++The parent element of the `` element is the <`>> element. + + + + [[nsa-form-login-attributes]] + ===== Attributes ++The `form-login` element has the following attributes: + + + [[nsa-form-login-always-use-default-target]] +-* **always-use-default-target** +-If set to `true`, the user will always start at the value given by <>, regardless of how they arrived at the login page. ++`always-use-default-target` ++If set to `true`, the user always starts at the value given by <>, regardless of how they arrived at the login page. + Maps to the `alwaysUseDefaultTargetUrl` property of `UsernamePasswordAuthenticationFilter`. +-Default value is `false`. ++Default: `false`. + + + [[nsa-form-login-authentication-details-source-ref]] +-* **authentication-details-source-ref** +-Reference to an `AuthenticationDetailsSource` which will be used by the authentication filter ++`authentication-details-source-ref`:: ++Reference to an `AuthenticationDetailsSource`, which is used by the authentication filter. + + + [[nsa-form-login-authentication-failure-handler-ref]] +-* **authentication-failure-handler-ref** +-Can be used as an alternative to <>, giving you full control over the navigation flow after an authentication failure. ++`authentication-failure-handler-ref`:: ++Can be used as an alternative to <>, giving you full control over the navigation flow after an authentication failure. + The value should be the name of an `AuthenticationFailureHandler` bean in the application context. + + + [[nsa-form-login-authentication-failure-url]] + * **authentication-failure-url** + Maps to the `authenticationFailureUrl` property of `UsernamePasswordAuthenticationFilter`. +-Defines the URL the browser will be redirected to on login failure. +-Defaults to `/login?error`, which will be automatically handled by the automatic login page generator, re-rendering the login page with an error message. ++Defines the URL to which the browser is redirected on login failure. ++Defaults to `/login?error`, which is automatically handled by the automatic login page generator, re-rendering the login page with an error message. + + + [[nsa-form-login-authentication-success-handler-ref]] +-* **authentication-success-handler-ref** +-This can be used as an alternative to <> and <>, giving you full control over the navigation flow after a successful authentication. ++`authentication-success-handler-ref`:: ++You an use this as an alternative to <> and <>, giving you full control over the navigation flow after a successful authentication. + The value should be the name of an `AuthenticationSuccessHandler` bean in the application context. +-By default, an implementation of `SavedRequestAwareAuthenticationSuccessHandler` is used and injected with the <>. ++By default, an implementation of `SavedRequestAwareAuthenticationSuccessHandler` is used and injected with the <>. + + + [[nsa-form-login-default-target-url]] +-* **default-target-url** ++default-target-url:: + Maps to the `defaultTargetUrl` property of `UsernamePasswordAuthenticationFilter`. +-If not set, the default value is "/" (the application root). +-A user will be taken to this URL after logging in, provided they were not asked to login while attempting to access a secured resource, when they will be taken to the originally requested URL. ++If not set, the default value is `/` (the application root). ++A user is taken to this URL after logging in, provided they were not asked to login while attempting to access a secured resource, when they will be taken to the originally requested URL. + + + [[nsa-form-login-login-page]] +-* **login-page** ++`login-page`:: + The URL that should be used to render the login page. + Maps to the `loginFormUrl` property of the `LoginUrlAuthenticationEntryPoint`. +-Defaults to "/login". ++Default: `/login`. + + + [[nsa-form-login-login-processing-url]] +-* **login-processing-url** ++`login-processing-url`:: + Maps to the `filterProcessesUrl` property of `UsernamePasswordAuthenticationFilter`. +-The default value is "/login". ++Default: `/login`. + + + [[nsa-form-login-password-parameter]] + * **password-parameter** +-The name of the request parameter which contains the password. +-Defaults to "password". ++The name of the request parameter that contains the password. ++Default: `password`. + + + [[nsa-form-login-username-parameter]] +-* **username-parameter** +-The name of the request parameter which contains the username. +-Defaults to "username". ++username-parameter:: ++The name of the request parameter that contains the username. ++Default: `username`. + + [[nsa-form-login-authentication-success-forward-url]] +-* **authentication-success-forward-url** +-Maps a `ForwardAuthenticationSuccessHandler` to `authenticationSuccessHandler` property of `UsernamePasswordAuthenticationFilter`. ++`authentication-success-forward-url`:: ++Maps a `ForwardAuthenticationSuccessHandler` to the `authenticationSuccessHandler` property of `UsernamePasswordAuthenticationFilter`. + + + [[nsa-form-login-authentication-failure-forward-url]] +-* **authentication-failure-forward-url** +-Maps a `ForwardAuthenticationFailureHandler` to `authenticationFailureHandler` property of `UsernamePasswordAuthenticationFilter`. ++`authentication-failure-forward-url`:: ++Maps a `ForwardAuthenticationFailureHandler` to the `authenticationFailureHandler` property of `UsernamePasswordAuthenticationFilter`. + + + [[nsa-oauth2-login]] + ==== +-The <> feature configures authentication support using an OAuth 2.0 and/or OpenID Connect 1.0 Provider. ++The <> feature configures authentication support by using an OAuth 2.0 or OpenID Connect 1.0 Provider. + + + [[nsa-oauth2-login-parents]] + ===== Parent Elements of + +-* <> ++The parent element of the `` element is the <`>> element. + + [[nsa-oauth2-login-attributes]] + ===== Attributes + ++The `` has the following attributes: + + [[nsa-oauth2-login-client-registration-repository-ref]] +-* **client-registration-repository-ref** ++`client-registration-repository-ref`:: + Reference to the `ClientRegistrationRepository`. + + + [[nsa-oauth2-login-authorized-client-repository-ref]] +-* **authorized-client-repository-ref** ++`authorized-client-repository-ref`:: + Reference to the `OAuth2AuthorizedClientRepository`. + + + [[nsa-oauth2-login-authorized-client-service-ref]] +-* **authorized-client-service-ref** ++`authorized-client-service-ref`:: + Reference to the `OAuth2AuthorizedClientService`. + + + [[nsa-oauth2-login-authorization-request-repository-ref]] +-* **authorization-request-repository-ref** ++`authorization-request-repository-ref`:: + Reference to the `AuthorizationRequestRepository`. + + + [[nsa-oauth2-login-authorization-request-resolver-ref]] +-* **authorization-request-resolver-ref** ++`authorization-request-resolver-ref`:: + Reference to the `OAuth2AuthorizationRequestResolver`. + + + [[nsa-oauth2-login-access-token-response-client-ref]] +-* **access-token-response-client-ref** ++`access-token-response-client-ref`:: + Reference to the `OAuth2AccessTokenResponseClient`. + + + [[nsa-oauth2-login-user-authorities-mapper-ref]] +-* **user-authorities-mapper-ref** ++`user-authorities-mapper-ref`:: + Reference to the `GrantedAuthoritiesMapper`. + + + [[nsa-oauth2-login-user-service-ref]] +-* **user-service-ref** ++`user-service-ref`:: + Reference to the `OAuth2UserService`. + + + [[nsa-oauth2-login-oidc-user-service-ref]] +-* **oidc-user-service-ref** ++`oidc-user-service-ref`:: + Reference to the OpenID Connect `OAuth2UserService`. + + + [[nsa-oauth2-login-login-processing-url]] +-* **login-processing-url** ++`login-processing-url`:: + The URI where the filter processes authentication requests. + + + [[nsa-oauth2-login-login-page]] +-* **login-page** +-The URI to send users to login. ++`login-page`:: ++The URI to which to send users to login. + + + [[nsa-oauth2-login-authentication-success-handler-ref]] +-* **authentication-success-handler-ref** ++`authentication-success-handler-ref`:: + Reference to the `AuthenticationSuccessHandler`. + + + [[nsa-oauth2-login-authentication-failure-handler-ref]] +-* **authentication-failure-handler-ref** ++`authentication-failure-handler-ref`:: + Reference to the `AuthenticationFailureHandler`. + + + [[nsa-oauth2-login-jwt-decoder-factory-ref]] +-* **jwt-decoder-factory-ref** ++`jwt-decoder-factory-ref`:: + Reference to the `JwtDecoderFactory` used by `OidcAuthorizationCodeAuthenticationProvider`. + + +@@ -944,31 +970,32 @@ Configures <> support. + [[nsa-oauth2-client-parents]] + ===== Parent Elements of + +-* <> ++The parent of the `` is the <`>> element. + + [[nsa-oauth2-client-attributes]] + ===== Attributes + ++The `` element has the following attributes: + + [[nsa-oauth2-client-client-registration-repository-ref]] +-* **client-registration-repository-ref** ++`client-registration-repository-ref`:: + Reference to the `ClientRegistrationRepository`. + + + [[nsa-oauth2-client-authorized-client-repository-ref]] +-* **authorized-client-repository-ref** ++`authorized-client-repository-ref`:: + Reference to the `OAuth2AuthorizedClientRepository`. + + + [[nsa-oauth2-client-authorized-client-service-ref]] +-* **authorized-client-service-ref** ++`authorized-client-service-ref`:: + Reference to the `OAuth2AuthorizedClientService`. + + + [[nsa-oauth2-client-children]] + ===== Child Elements of + +-* <> ++The `` has one child element: <`>>. + + + [[nsa-authorization-code-grant]] +@@ -979,49 +1006,52 @@ Configures < + [[nsa-authorization-code-grant-parents]] + ===== Parent Elements of + +-* <> ++The parent element of the `` element is the <> element. + + + [[nsa-authorization-code-grant-attributes]] + ===== Attributes + ++The `` element has the following attributes: + + [[nsa-authorization-code-grant-authorization-request-repository-ref]] +-* **authorization-request-repository-ref** ++`authorization-request-repository-ref`:: + Reference to the `AuthorizationRequestRepository`. + + + [[nsa-authorization-code-grant-authorization-request-resolver-ref]] +-* **authorization-request-resolver-ref** ++`authorization-request-resolver-ref`:: + Reference to the `OAuth2AuthorizationRequestResolver`. + + + [[nsa-authorization-code-grant-access-token-response-client-ref]] +-* **access-token-response-client-ref** ++`access-token-response-client-ref`:: + Reference to the `OAuth2AccessTokenResponseClient`. + + + [[nsa-client-registrations]] + ==== +-A container element for client(s) registered (<>) with an OAuth 2.0 or OpenID Connect 1.0 Provider. ++The `` is a container element for client(s) registered (<>) with an OAuth 2.0 or OpenID Connect 1.0 Provider. + + + [[nsa-client-registrations-children]] + ===== Child Elements of + ++The `` element has the following child elements: ++ + * <> + * <> + + + [[nsa-client-registration]] + ==== +-Represents a client registered with an OAuth 2.0 or OpenID Connect 1.0 Provider. ++The `` represents a client registered with an OAuth 2.0 or OpenID Connect 1.0 Provider. You can have multiple `` elements. + + + [[nsa-client-registration-parents]] + ===== Parent Elements of + +-* <> ++The parent element of the `` is the <>. + + + [[nsa-client-registration-attributes]] +@@ -1029,966 +1059,960 @@ Represents a client registered with an OAuth 2.0 or OpenID Connect 1.0 Provider. + + + [[nsa-client-registration-registration-id]] +-* **registration-id** ++registration-`id`:: + The ID that uniquely identifies the `ClientRegistration`. + + + [[nsa-client-registration-client-id]] +-* **client-id** ++`client-id`:: + The client identifier. + + + [[nsa-client-registration-client-secret]] +-* **client-secret** ++`client-secret`:: + The client secret. + + + [[nsa-client-registration-client-authentication-method]] +-* **client-authentication-method** +-The method used to authenticate the Client with the Provider. +-The supported values are *client_secret_basic*, *client_secret_post* and *none* https://tools.ietf.org/html/rfc6749#section-2.1[(public clients)]. ++`client-authentication-method`:: ++The method used to authenticate the client with the provider. ++The supported values are `client_secret_basic`, `client_secret_post`, and `none` (https://tools.ietf.org/html/rfc6749#section-2.1[public clients]). + + + [[nsa-client-registration-authorization-grant-type]] +-* **authorization-grant-type** ++`authorization-grant-type`:: + The OAuth 2.0 Authorization Framework defines four https://tools.ietf.org/html/rfc6749#section-1.3[Authorization Grant] types. +-The supported values are `authorization_code`, `client_credentials` and `password`. ++The supported values are `authorization_code`, `client_credentials`, and `password`. + + + [[nsa-client-registration-redirect-uri]] +-* **redirect-uri** +-The client's registered redirect URI that the _Authorization Server_ redirects the end-user's user-agent to after the end-user has authenticated and authorized access to the client. ++`redirect-uri`:: ++The client's registered redirect URI to which the _Authorization Server_ redirects the end-user's user-agent after the end-user has authenticated and authorized access to the client. + + + [[nsa-client-registration-scope]] +-* **scope** +-The scope(s) requested by the client during the Authorization Request flow, such as openid, email, or profile. ++`scope`:: ++The scope(s) requested by the client during the Authorization Request flow, such as `openid`, `email`, or `profile`. + + + [[nsa-client-registration-client-name]] +-* **client-name** ++`client-name`:: + A descriptive name used for the client. + The name may be used in certain scenarios, such as when displaying the name of the client in the auto-generated login page. + + [[nsa-client-registration-provider-id]] +-* **provider-id** +-A reference to the associated provider. May reference a `` element or use one of the common providers (google, github, facebook, okta). ++`provider-id` ++A reference to the associated provider. May reference a `` element or use one of the common providers (Google, Github, Facebook, Okta, and others). + + + [[nsa-provider]] + ==== +-The configuration information for an OAuth 2.0 or OpenID Connect 1.0 Provider. ++The `` element contains the configuration information for an OAuth 2.0 or OpenID Connect 1.0 Provider. + + + [[nsa-provider-parents]] + ===== Parent Elements of + +-* <> ++The parent element of the `` element is the <`>> element. + + + [[nsa-provider-attributes]] + ===== Attributes + ++The `` element has the following attributes: ++ + + [[nsa-provider-provider-id]] +-* **provider-id** ++`provider-id`:: + The ID that uniquely identifies the provider. + + + [[nsa-provider-authorization-uri]] +-* **authorization-uri** +-The Authorization Endpoint URI for the Authorization Server. ++`authorization-uri`:: ++The authorization endpoint URI for the authorization server. + + + [[nsa-provider-token-uri]] +-* **token-uri** +-The Token Endpoint URI for the Authorization Server. ++`token-uri`:: ++The token endpoint URI for the authorization server. + + + [[nsa-provider-user-info-uri]] +-* **user-info-uri** +-The UserInfo Endpoint URI used to access the claims/attributes of the authenticated end-user. ++`user-info-uri`:: ++The UserInfo endpoint URI used to access the claims and attributes of the authenticated end user. + + + [[nsa-provider-user-info-authentication-method]] +-* **user-info-authentication-method** +-The authentication method used when sending the access token to the UserInfo Endpoint. +-The supported values are *header*, *form* and *query*. ++`user-info-authentication-method`:: ++The authentication method used when sending the access token to the UserInfo endpoint. ++The supported values are `header`, `form`, and `query`. + + + [[nsa-provider-user-info-user-name-attribute]] +-* **user-info-user-name-attribute** +-The name of the attribute returned in the UserInfo Response that references the Name or Identifier of the end-user. ++`user-info-user-name-attribute`:: ++The name of the attribute returned in the UserInfo response that references the name or edentifier of the end-user. + + + [[nsa-provider-jwk-set-uri]] +-* **jwk-set-uri** +-The URI used to retrieve the https://tools.ietf.org/html/rfc7517[JSON Web Key (JWK)] Set from the Authorization Server, which contains the cryptographic key(s) used to verify the https://tools.ietf.org/html/rfc7515[JSON Web Signature (JWS)] of the ID Token and optionally the UserInfo Response. ++`jwk-set-uri`:: ++The URI used to retrieve the https://tools.ietf.org/html/rfc7517[JSON Web Key (JWK)] set from the authorization server, which contains the cryptographic key(s) used to verify the https://tools.ietf.org/html/rfc7515[JSON Web Signature (JWS)] of the ID Token and (optionally) the UserInfo response. + + + [[nsa-provider-issuer-uri]] +-* **issuer-uri** +-The URI used to initially configure a `ClientRegistration` using discovery of an OpenID Connect Provider's https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfig[Configuration endpoint] or an Authorization Server's https://tools.ietf.org/html/rfc8414#section-3[Metadata endpoint]. ++issuer-uri:: ++The URI used to initially configure a `ClientRegistration` by using discovery of an OpenID Connect Provider's https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfig[configuration endpoint] or an Authorization Server's https://tools.ietf.org/html/rfc8414#section-3[metadata endpoint]. + + [[nsa-oauth2-resource-server]] + ==== +-Adds a `BearerTokenAuthenticationFilter`, `BearerTokenAuthenticationEntryPoint`, and `BearerTokenAccessDeniedHandler` to the configuration. ++Adds a `BearerTokenAuthenticationFilter`, a `BearerTokenAuthenticationEntryPoint`, and a `BearerTokenAccessDeniedHandler` to the configuration. + In addition, either `` or `` must be specified. + + [[nsa-oauth2-resource-server-parents]] + ===== Parents Elements of + +-* <> ++The parent element of the `` is the <`>> element. + + [[nsa-oauth2-resource-server-children]] + ===== Child Elements of + +-* <> +-* <> ++The `` element has the following child elements: ++ ++* <`>> ++* <`>> + + [[nsa-oauth2-resource-server-attributes]] + ===== Attributes + ++The `` element has the following attributes: ++ + [[nsa-oauth2-resource-server-authentication-manager-resolver-ref]] +-* **authentication-manager-resolver-ref** +-Reference to an `AuthenticationManagerResolver` which will resolve the `AuthenticationManager` at request time ++`authentication-manager-resolver-ref`:: ++Reference to an `AuthenticationManagerResolver`, which resolves the `AuthenticationManager` at request time. + + [[nsa-oauth2-resource-server-bearer-token-resolver-ref]] +-* **bearer-token-resolver-ref** +-Reference to a `BearerTokenResolver` which will retrieve the bearer token from the request ++`bearer-token-resolver-ref`:: ++Reference to a `BearerTokenResolver`, which retrieves the bearer token from the request. + + [[nsa-oauth2-resource-server-entry-point-ref]] +-* **entry-point-ref** +-Reference to a `AuthenticationEntryPoint` which will handle unauthorized requests ++`entry-point-ref`:: ++Reference to a `AuthenticationEntryPoint`, which handles unauthorized requests. + + [[nsa-jwt]] +-==== +-Represents an OAuth 2.0 Resource Server that will authorize JWTs ++==== The element ++The `` element represents an OAuth 2.0 Resource Server that authorizes JWTs (JSON Web Tokens). + + + [[nsa-jwt-parents]] + ===== Parent Elements of + +-* <> ++The parent element of the `` element is the <`>> element. + + + [[nsa-jwt-attributes]] + ===== Attributes + ++The `` element has the following attributes: ++ + [[nsa-jwt-jwt-authentication-converter-ref]] +-* **jwt-authentication-converter-ref** +-Reference to a `Converter` ++`jwt-authentication-converter-ref`:: ++Reference to a `Converter`. + + [[nsa-jwt-decoder-ref]] +-* **jwt-decoder-ref** +-Reference to a `JwtDecoder`. This is a larger component that overrides `jwk-set-uri` ++`jwt-decoder-ref`:: ++Reference to a `JwtDecoder`. This is a larger component that overrides `jwk-set-uri`. + + [[nsa-jwt-jwk-set-uri]] +-* **jwk-set-uri** +-The JWK Set Uri used to load signing verification keys from an OAuth 2.0 Authorization Server ++`jwk-set-uri`:: ++The JWK Set URI used to load signing verification keys from an OAuth 2.0 Authorization Server. + + [[nsa-opaque-token]] +-==== +-Represents an OAuth 2.0 Resource Server that will authorize opaque tokens ++==== The Element ++Represents an OAuth 2.0 Resource Server that authorizes opaque tokens. + + [[nsa-opaque-token-parents]] + ===== Parent Elements of + +-* <> ++The parent element of the `> element. + + [[nsa-opaque-token-attributes]] + ===== Attributes + + [[nsa-opaque-token-introspector-ref]] +-* **introspector-ref** ++`introspector-ref`:: + Reference to an `OpaqueTokenIntrospector`. This is a larger component that overrides `introspection-uri`, `client-id`, and `client-secret`. + + [[nsa-opaque-token-introspection-uri]] +-* **introspection-uri** +-The Introspection Uri used to introspect the details of an opaque token. Should be accompanied with a `client-id` and `client-secret`. ++`introspection-uri`:: ++The Introspection URI used to introspect the details of an opaque token. It should be accompanied by a `client-id` and `client-secret`. + + [[nsa-opaque-token-client-id]] +-* **client-id** +-The Client Id to use for client authentication against the provided `introspection-uri`. ++`client-id`:: ++The client ID to use for client authentication against the provided `introspection-uri`. + + [[nsa-opaque-token-client-secret]] +-* **client-secret** +-The Client Secret to use for client authentication against the provided `introspection-uri`. ++`client-secret`:: ++The client secret to use for client authentication against the provided `introspection-uri`. + + [[nsa-http-basic]] + ==== +-Adds a `BasicAuthenticationFilter` and `BasicAuthenticationEntryPoint` to the configuration. +-The latter will only be used as the configuration entry point if form-based login is not enabled. ++The adds a `BasicAuthenticationFilter` and `BasicAuthenticationEntryPoint` to the configuration. ++The latter is used as the configuration entry point only if form-based login is not enabled. + + + [[nsa-http-basic-parents]] + ===== Parent Elements of + + +-* <> ++The parent element of the `` element is the <`>> element. + + + + [[nsa-http-basic-attributes]] + ===== Attributes + ++The `` element has the following attributes: ++ + + [[nsa-http-basic-authentication-details-source-ref]] +-* **authentication-details-source-ref** +-Reference to an `AuthenticationDetailsSource` which will be used by the authentication filter ++`authentication-details-source-ref`:: ++Reference to an `AuthenticationDetailsSource`, which is used by the authentication filter. + + + [[nsa-http-basic-entry-point-ref]] +-* **entry-point-ref** +-Sets the `AuthenticationEntryPoint` which is used by the `BasicAuthenticationFilter`. ++`entry-point-ref`:: ++Sets the `AuthenticationEntryPoint`, which is used by the `BasicAuthenticationFilter`. + + + [[nsa-http-firewall]] + ==== Element +-This is a top-level element which can be used to inject a custom implementation of `HttpFirewall` into the `FilterChainProxy` created by the namespace. ++`` is a top-level element that you can use to inject a custom implementation of `HttpFirewall` into the `FilterChainProxy` created by the namespace. + The default implementation should be suitable for most applications. + + + [[nsa-http-firewall-attributes]] + ===== Attributes + ++`` has a single attribute: + + [[nsa-http-firewall-ref]] +-* **ref** ++`ref`:: + Defines a reference to a Spring bean that implements `HttpFirewall`. + + + [[nsa-intercept-url]] + ==== +-This element is used to define the set of URL patterns that the application is interested in and to configure how they should be handled. +-It is used to construct the `FilterInvocationSecurityMetadataSource` used by the `FilterSecurityInterceptor`. +-It is also responsible for configuring a `ChannelProcessingFilter` if particular URLs need to be accessed by HTTPS, for example. ++`` element defines the set of URL patterns that the application is interested in and configures how they should be handled. ++It constructs the `FilterInvocationSecurityMetadataSource` used by the `FilterSecurityInterceptor`. ++It is also responsible for configuring a `ChannelProcessingFilter` (if particular URLs need to be accessed by HTTPS, for example). + When matching the specified patterns against an incoming request, the matching is done in the order in which the elements are declared. +-So the most specific patterns should come first and the most general should come last. ++So, the most specific patterns should come first and the most general should come last. + + + [[nsa-intercept-url-parents]] + ===== Parent Elements of + ++The parent elements of the `` element are: + +-* <> +-* <> +- ++* <`>> ++* <`>> + + + [[nsa-intercept-url-attributes]] + ===== Attributes + ++The `` element has the following parameters: + + [[nsa-intercept-url-access]] +-* **access** +-Lists the access attributes which will be stored in the `FilterInvocationSecurityMetadataSource` for the defined URL pattern/method combination. ++`access`:: ++Lists the access attributes, which are stored in the `FilterInvocationSecurityMetadataSource` for the defined URL pattern and method combination. + This should be a comma-separated list of the security configuration attributes (such as role names). + + + [[nsa-intercept-url-method]] +-* **method** +-The HTTP Method which will be used in combination with the pattern and servlet path (optional) to match an incoming request. +-If omitted, any method will match. +-If an identical pattern is specified with and without a method, the method-specific match will take precedence. ++`method`:: ++The HTTP Method that is used in combination with the pattern and servlet path (optional) to match an incoming request. ++If omitted, any method matchs. ++If an identical pattern is specified with and without a method, the method-specific match takes precedence. + + + [[nsa-intercept-url-pattern]] +-* **pattern** +-The pattern which defines the URL path. +-The content will depend on the `request-matcher` attribute from the containing http element, so will default to ant path syntax. ++`pattern`:: ++The pattern that defines the URL path. ++The content depends on the `request-matcher` attribute from the containing `` element, so it defaults to Ant path syntax. + + + [[nsa-intercept-url-request-matcher-ref]] +-* **request-matcher-ref** +-A reference to a `RequestMatcher` that will be used to determine if this `` is used. ++`request-matcher-ref`:: ++A reference to a `RequestMatcher` that is used to determine if this `` is used. + + + [[nsa-intercept-url-requires-channel]] +-* **requires-channel** +-Can be "http" or "https" depending on whether a particular URL pattern should be accessed over HTTP or HTTPS respectively. +-Alternatively the value "any" can be used when there is no preference. +-If this attribute is present on any `` element, then a `ChannelProcessingFilter` will be added to the filter stack and its additional dependencies added to the application context. ++`requires-channel`:: ++Can be `http` or `https`, depending on whether a particular URL pattern should be accessed over HTTP or HTTPS, respectively. ++Alternatively, you can use a value of `any` when you have no preference. ++If this attribute is present on any `` element, a `ChannelProcessingFilter` is added to the filter stack and its additional dependencies are added to the application context. + +-If a `` configuration is added, this will be used to by the `SecureChannelProcessor` and `InsecureChannelProcessor` beans to determine the ports used for redirecting to HTTP/HTTPS. ++If a `` configuration is added, it is used by the `SecureChannelProcessor` and `InsecureChannelProcessor` beans to determine the ports used for redirecting to HTTP and HTTPS. + +-NOTE: This property is invalid for <> ++NOTE: This property is invalid for <> + + [[nsa-intercept-url-servlet-path]] +-* **servlet-path** +-The servlet path which will be used in combination with the pattern and HTTP method to match an incoming request. +-This attribute is only applicable when <> is 'mvc'. +-In addition, the value is only required in the following 2 use cases: 1) There are 2 or more `HttpServlet` 's registered in the `ServletContext` that have mappings starting with `'/'` and are different; 2) The pattern starts with the same value of a registered `HttpServlet` path, excluding the default (root) `HttpServlet` `'/'`. ++`servlet-path`:: ++The servlet path to be used, in combination with the pattern and HTTP method, to match an incoming request. ++This attribute is only applicable when <> is `mvc`. ++In addition, the value is only required in the following two use cases: ++* Two or more `HttpServlet` instances that have mappings starting with `/` and are different are registered in the `ServletContext`. ++* The pattern starts with the same value of a registered `HttpServlet` path, excluding the default (root) `HttpServlet` `/`. + +-NOTE: This property is invalid for <> ++NOTE: This property is invalid for <> + + + [[nsa-jee]] + ==== +-Adds a J2eePreAuthenticatedProcessingFilter to the filter chain to provide integration with container authentication. + + +-[[nsa-jee-parents]] +-===== Parent Elements of ++The `` element a dds a `J2eePreAuthenticatedProcessingFilter` to the filter chain to provide integration with container authentication. + + +-* <> ++[[nsa-jee-parents]] ++===== Parent Elements of + ++The parent element of the `` element is the <`>> element. + + + [[nsa-jee-attributes]] + ===== Attributes + ++The `` element has the following attributes: + + [[nsa-jee-mappable-roles]] +-* **mappable-roles** +-A comma-separate list of roles to look for in the incoming HttpServletRequest. ++`mappable-roles`:: ++A comma-separated list of roles to look for in the incoming `HttpServletRequest`. + + + [[nsa-jee-user-service-ref]] +-* **user-service-ref** +-A reference to a user-service (or UserDetailsService bean) Id ++`user-service-ref`:: ++A reference to a user-service (or `UserDetailsService` bean) ID. + + + [[nsa-logout]] + ==== +-Adds a `LogoutFilter` to the filter stack. +-This is configured with a `SecurityContextLogoutHandler`. ++The `` element adds a `LogoutFilter` to the filter stack. ++It is configured by a `SecurityContextLogoutHandler`. + + + [[nsa-logout-parents]] + ===== Parent Elements of + +- +-* <> +- ++The parent element of the `` element is the <`>> element. + + + [[nsa-logout-attributes]] + ===== Attributes + ++The `` element has the following attributes: + + [[nsa-logout-delete-cookies]] +-* **delete-cookies** +-A comma-separated list of the names of cookies which should be deleted when the user logs out. ++`delete-cookies`:: ++A comma-separated list of the names of cookies that should be deleted when the user logs out. + + + [[nsa-logout-invalidate-session]] +-* **invalidate-session** ++`invalidate-session`:: + Maps to the `invalidateHttpSession` of the `SecurityContextLogoutHandler`. +-Defaults to "true", so the session will be invalidated on logout. ++Default: `true` (the session is invalidated on logout) + + + [[nsa-logout-logout-success-url]] +-* **logout-success-url** +-The destination URL which the user will be taken to after logging out. +-Defaults to /?logout (i.e. /login?logout) +- ++`logout-success-url`:: ++The destination URL to which the user is taken after logging out. ++Default: `/?logout` (usually `/login?logout`) + + +- +-Setting this attribute will inject the `SessionManagementFilter` with a `SimpleRedirectInvalidSessionStrategy` configured with the attribute value. +-When an invalid session ID is submitted, the strategy will be invoked, redirecting to the configured URL. ++Setting this attribute injects the `SessionManagementFilter` with a `SimpleRedirectInvalidSessionStrategy` configured with the attribute value. ++When an invalid session ID is submitted, the strategy is invoked, redirecting to the configured URL. + + + [[nsa-logout-logout-url]] +-* **logout-url** +-The URL which will cause a logout (i.e. which will be processed by the filter). +-Defaults to "/logout". ++`logout-url`:: ++The URL that causes a logout (which is processed by the filter). ++Default: `/logout` + + + [[nsa-logout-success-handler-ref]] +-* **success-handler-ref** +-May be used to supply an instance of `LogoutSuccessHandler` which will be invoked to control the navigation after logging out. ++`success-handler-ref`:: ++Can be used to supply an instance of `LogoutSuccessHandler` that is invoked to control the navigation after logging out. + + + [[nsa-openid-login]] + ==== +-Similar to `` and has the same attributes. +-The default value for `login-processing-url` is "/login/openid". +-An `OpenIDAuthenticationFilter` and `OpenIDAuthenticationProvider` will be registered. ++The `` element is similar to the `` element and has the same attributes. ++The default value for `login-processing-url` is `/login/openid`. ++An `OpenIDAuthenticationFilter` and a `OpenIDAuthenticationProvider` are registered. + The latter requires a reference to a `UserDetailsService`. +-Again, this can be specified by `id`, using the `user-service-ref` attribute, or will be located automatically in the application context. ++You can specify this reference by `id`, by using the `user-service-ref` attribute, or you can let it be automatically located in the application context. + + + [[nsa-openid-login-parents]] + ===== Parent Elements of + +- +-* <> +- ++The parent element of the `` element is the <`>> element. + + + [[nsa-openid-login-attributes]] + ===== Attributes + ++The `` element has the following attributes: + + [[nsa-openid-login-always-use-default-target]] +-* **always-use-default-target** +-Whether the user should always be redirected to the default-target-url after login. ++`always-use-default-target`:: ++Whether the user should always be redirected to the `default-target-url` after login. + + + [[nsa-openid-login-authentication-details-source-ref]] +-* **authentication-details-source-ref** +-Reference to an AuthenticationDetailsSource which will be used by the authentication filter ++`authentication-details-source-ref`:: ++Reference to an `AuthenticationDetailsSource` that is used by the authentication filter. + + + [[nsa-openid-login-authentication-failure-handler-ref]] +-* **authentication-failure-handler-ref** +-Reference to an AuthenticationFailureHandler bean which should be used to handle a failed authentication request. +-Should not be used in combination with authentication-failure-url as the implementation should always deal with navigation to the subsequent destination ++`authentication-failure-handler-ref`:: ++Reference to an `AuthenticationFailureHandler` bean that should be used to handle a failed authentication request. ++It should not be used in combination with `authentication-failure-url`, as the implementation should always deal with navigation to the subsequent destination. + + + [[nsa-openid-login-authentication-failure-url]] +-* **authentication-failure-url** ++authentication-failure-url:: + The URL for the login failure page. +-If no login failure URL is specified, Spring Security will automatically create a failure login URL at /login?login_error and a corresponding filter to render that login failure URL when requested. ++If no login failure URL is specified, Spring Security automatically creates a failure login URL at `/login?login_error` and a corresponding filter to render that login failure URL when requested. + + + [[nsa-openid-login-authentication-success-forward-url]] +-* **authentication-success-forward-url** ++authentication-success-forward-url:: + Maps a `ForwardAuthenticationSuccessHandler` to `authenticationSuccessHandler` property of `UsernamePasswordAuthenticationFilter`. + + + [[nsa-openid-login-authentication-failure-forward-url]] +-* **authentication-failure-forward-url** ++`authentication-failure-forward-url`:: + Maps a `ForwardAuthenticationFailureHandler` to `authenticationFailureHandler` property of `UsernamePasswordAuthenticationFilter`. + + + [[nsa-openid-login-authentication-success-handler-ref]] +-* **authentication-success-handler-ref** +-Reference to an AuthenticationSuccessHandler bean which should be used to handle a successful authentication request. +-Should not be used in combination with <> (or <>) as the implementation should always deal with navigation to the subsequent destination ++`authentication-success-handler-ref`:: ++Reference to an `AuthenticationSuccessHandler` bean that should be used to handle a successful authentication request. ++Should not be used in combination with <> (or <>) as the implementation should always deal with navigation to the subsequent destination + + + [[nsa-openid-login-default-target-url]] +-* **default-target-url** +-The URL that will be redirected to after successful authentication, if the user's previous action could not be resumed. ++`default-target-url`:: ++The URL to which to redirect after successful authentication, if the user's previous action could not be resumed. + This generally happens if the user visits a login page without having first requested a secured operation that triggers authentication. +-If unspecified, defaults to the root of the application. ++If unspecified, it defaults to the root of the application. + + + [[nsa-openid-login-login-page]] +-* **login-page** ++`login-page`:: + The URL for the login page. +-If no login URL is specified, Spring Security will automatically create a login URL at /login and a corresponding filter to render that login URL when requested. ++If no login URL is specified, Spring Security automatically creates a login URL at `/login` and a corresponding filter to render that login URL when requested. + + + [[nsa-openid-login-login-processing-url]] +-* **login-processing-url** +-The URL that the login form is posted to. +-If unspecified, it defaults to /login. ++`login-processing-url`:: ++The URL to which the login form is posted. ++If unspecified, it defaults to `/login`. + + + [[nsa-openid-login-password-parameter]] +-* **password-parameter** +-The name of the request parameter which contains the password. +-Defaults to "password". ++`password-parameter`:: ++The name of the request parameter that contains the password. ++Default: `password` + + + [[nsa-openid-login-user-service-ref]] +-* **user-service-ref** +-A reference to a user-service (or UserDetailsService bean) Id ++`user-service-ref`:: ++A reference to a user-service (or `UserDetailsService` bean) ID + + + [[nsa-openid-login-username-parameter]] +-* **username-parameter** +-The name of the request parameter which contains the username. +-Defaults to "username". ++`username-parameter`:: ++The name of the request parameter that contains the username. ++Default: `username` + + + [[nsa-openid-login-children]] + ===== Child Elements of +-* <> + ++The `` element has only one child attribute: <`>>. + + + [[nsa-attribute-exchange]] +-==== +-The `attribute-exchange` element defines the list of attributes which should be requested from the identity provider. +-An example can be found in the <> section of the namespace configuration chapter. +-More than one can be used, in which case each must have an `identifier-match` attribute, containing a regular expression which is matched against the supplied OpenID identifier. +-This allows different attribute lists to be fetched from different providers (Google, Yahoo etc). ++==== Element ++The `` element defines the list of attributes to request from the identity provider. ++You can find an example in the <> section of the namespace configuration chapter. ++You can use more than one. In that case, each must have an `identifier-match` attribute that contains a regular expression, which is matched against the supplied OpenID identifier. ++This lets different attribute lists be fetched from different providers (Google, Yahoo, and others). + + + [[nsa-attribute-exchange-parents]] + ===== Parent Elements of + +- +-* <> +- ++The parent element of the `` element is the <`>> element. + + + [[nsa-attribute-exchange-attributes]] + ===== Attributes + ++The `` element has a single attribute: ++ + + [[nsa-attribute-exchange-identifier-match]] +-* **identifier-match** +-A regular expression which will be compared against the claimed identity, when deciding which attribute-exchange configuration to use during authentication. ++`identifier-match`:: ++A regular expression that is compared against the claimed identity when deciding which `attribute-exchange` configuration to use during authentication. + + + [[nsa-attribute-exchange-children]] + ===== Child Elements of + +- +-* <> +- ++The `` element has a single child attribute: <`>>. + + + [[nsa-openid-attribute]] + ==== +-Attributes used when making an OpenID AX https://openid.net/specs/openid-attribute-exchange-1_0.html#fetch_request[ Fetch Request] ++The `` element defines the attributes to use when making an OpenID AX https://openid.net/specs/openid-attribute-exchange-1_0.html#fetch_request[ Fetch Request]. + + + [[nsa-openid-attribute-parents]] + ===== Parent Elements of + +- +-* <> +- ++The parent element of the `` element is the <> element. + + + [[nsa-openid-attribute-attributes]] + ===== Attributes + ++The `` element has the following attributes: + + [[nsa-openid-attribute-count]] +-* **count** +-Specifies the number of attributes that you wish to get back. +-For example, return 3 emails. +-The default value is 1. ++`count`:: ++Specifies the number of attributes that you wish to get back -- for example, return three emails. ++Default: 1 + + + [[nsa-openid-attribute-name]] +-* **name** +-Specifies the name of the attribute that you wish to get back. +-For example, email. ++`name`:: ++Specifies the name of the attribute that you wish to get back -- for example, `email`. + + + [[nsa-openid-attribute-required]] +-* **required** +-Specifies if this attribute is required to the OP, but does not error out if the OP does not return the attribute. +-Default is false. ++`required`:: ++Specifies whether this attribute is required to the OP but does not error out if the OP does not return the attribute. ++Default: `false` + + + [[nsa-openid-attribute-type]] +-* **type** +-Specifies the attribute type. +-For example, https://axschema.org/contact/email. ++`type`:: ++Specifies the attribute type -- for example, `https://axschema.org/contact/email`. + See your OP's documentation for valid attribute types. + + + [[nsa-port-mappings]] +-==== +-By default, an instance of `PortMapperImpl` will be added to the configuration for use in redirecting to secure and insecure URLs. +-This element can optionally be used to override the default mappings which that class defines. ++==== Element ++By default, an instance of `PortMapperImpl` is added to the configuration for use in redirecting to secure and insecure URLs. ++You can optionally use the `` element to override the default mappings that `PortMapperImpl` defines. + Each child `` element defines a pair of HTTP:HTTPS ports. +-The default mappings are 80:443 and 8080:8443. +-An example of overriding these can be found in <>. ++The default mappings are `80:443` and `8080:8443`. ++You can find an example of overriding these values in <>. + + + [[nsa-port-mappings-parents]] +-===== Parent Elements of +- +- +-* <> ++===== Parent Element of + ++The parent element of the `` element is the <`>> element. + + + [[nsa-port-mappings-children]] + ===== Child Elements of + +- +-* <> +- ++The `` element has a single child element: <>. + + + [[nsa-port-mapping]] + ==== +-Provides a method to map http ports to https ports when forcing a redirect. ++The `` element provides a method to map HTTP ports to HTTPS ports when forcing a redirect. + + + [[nsa-port-mapping-parents]] + ===== Parent Elements of + +- +-* <> ++The parent element of the `` element is the <`>> element. + + + + [[nsa-port-mapping-attributes]] + ===== Attributes + ++The `` element has the following attributes: + + [[nsa-port-mapping-http]] +-* **http** +-The http port to use. ++`http`:: ++The HTTP port to use. + + + [[nsa-port-mapping-https]] +-* **https** +-The https port to use. ++`https`:: ++The HTTPS port to use. + + + [[nsa-remember-me]] + ==== +-Adds the `RememberMeAuthenticationFilter` to the stack. +-This in turn will be configured with either a `TokenBasedRememberMeServices`, a `PersistentTokenBasedRememberMeServices` or a user-specified bean implementing `RememberMeServices` depending on the attribute settings. ++The `` element adds the `RememberMeAuthenticationFilter` to the stack. ++This filter is, in turn, configured with either a `TokenBasedRememberMeServices`, a `PersistentTokenBasedRememberMeServices`, or a user-specified bean that implements `RememberMeServices`, depending on the attribute settings. + + + [[nsa-remember-me-parents]] + ===== Parent Elements of + +- +-* <> +- ++The parent element of the `` element is the <`>> element. + + + [[nsa-remember-me-attributes]] + ===== Attributes + ++The `` element has the following attributes: + + [[nsa-remember-me-authentication-success-handler-ref]] +-* **authentication-success-handler-ref** +-Sets the `authenticationSuccessHandler` property on the `RememberMeAuthenticationFilter` if custom navigation is required. ++`authentication-success-handler-ref`:: ++Sets the `authenticationSuccessHandler` property on the `RememberMeAuthenticationFilter` when custom navigation is required. + The value should be the name of a `AuthenticationSuccessHandler` bean in the application context. + + + [[nsa-remember-me-data-source-ref]] +-* **data-source-ref** ++`data-source-ref`:: + A reference to a `DataSource` bean. +-If this is set, `PersistentTokenBasedRememberMeServices` will be used and configured with a `JdbcTokenRepositoryImpl` instance. ++If this attribute is set, `PersistentTokenBasedRememberMeServices` is used and configured with a `JdbcTokenRepositoryImpl` instance. + + + [[nsa-remember-me-remember-me-parameter]] +-* **remember-me-parameter** +-The name of the request parameter which toggles remember-me authentication. +-Defaults to "remember-me". +-Maps to the "parameter" property of `AbstractRememberMeServices`. ++`remember-me-parameter`:: ++The name of the request parameter that toggles remember-me authentication. ++Defaults: `remember-me` ++Maps to the `parameter` property of `AbstractRememberMeServices`. + + + [[nsa-remember-me-remember-me-cookie]] +-* **remember-me-cookie** +-The name of cookie which store the token for remember-me authentication. +-Defaults to "remember-me". +-Maps to the "cookieName" property of `AbstractRememberMeServices`. ++`remember-me-cookie`:: ++The name of the cookie that stores the token for remember-me authentication. ++Defaults: `remember-me` ++This attribute maps to the `cookieName` property of `AbstractRememberMeServices`. + + + [[nsa-remember-me-key]] +-* **key** +-Maps to the "key" property of `AbstractRememberMeServices`. +-Should be set to a unique value to ensure that remember-me cookies are only valid within the one application footnote:[ +-This doesn't affect the use of `PersistentTokenBasedRememberMeServices`, where the tokens are stored on the server side. +-]. +-If this is not set a secure random value will be generated. +-Since generating secure random values can take a while, setting this value explicitly can help improve startup times when using the remember-me functionality. ++`key`:: ++Maps to the `key` property of `AbstractRememberMeServices`. ++Should be set to a unique value to ensure that remember-me cookies are valid only within one application ++This key does not affect the use of `PersistentTokenBasedRememberMeServices`, where the tokens are stored on the server side. ++If this key is not set, a secure random value is generated. ++Since generating secure random values can take a while, explicitly setting this value can help improve startup times when you use the remember-me functionality. + + + [[nsa-remember-me-services-alias]] +-* **services-alias** +-Exports the internally defined `RememberMeServices` as a bean alias, allowing it to be used by other beans in the application context. ++`services-alias`:: ++Exports the internally defined `RememberMeServices` as a bean alias, letting it be used by other beans in the application context. + + + [[nsa-remember-me-services-ref]] +-* **services-ref** +-Allows complete control of the `RememberMeServices` implementation that will be used by the filter. +-The value should be the `id` of a bean in the application context which implements this interface. +-Should also implement `LogoutHandler` if a logout filter is in use. ++`services-ref`:: ++Allows complete control of the `RememberMeServices` implementation that is used by the filter. ++The value should be the `id` of a bean in the application context that implements this interface. ++It should also implement `LogoutHandler` if a logout filter is in use. + + + [[nsa-remember-me-token-repository-ref]] +-* **token-repository-ref** ++`token-repository-ref`:: + Configures a `PersistentTokenBasedRememberMeServices` but allows the use of a custom `PersistentTokenRepository` bean. + + + [[nsa-remember-me-token-validity-seconds]] +-* **token-validity-seconds** ++`token-validity-seconds`:: + Maps to the `tokenValiditySeconds` property of `AbstractRememberMeServices`. + Specifies the period in seconds for which the remember-me cookie should be valid. +-By default it will be valid for 14 days. ++By default, it is valid for 14 days. + + + [[nsa-remember-me-use-secure-cookie]] +-* **use-secure-cookie** +-It is recommended that remember-me cookies are only submitted over HTTPS and thus should be flagged as "secure". +-By default, a secure cookie will be used if the connection over which the login request is made is secure (as it should be). +-If you set this property to `false`, secure cookies will not be used. +-Setting it to `true` will always set the secure flag on the cookie. ++`use-secure-cookie`:: ++We recommend that you submit remember-me cookies over HTTPS and that you flag as "`secure`". ++By default, a secure cookie is used if the connection for the login request is secure (as it should be). ++If you set this property to `false`, secure cookies are not used. ++Setting it to `true` always sets the secure flag on the cookie. + This attribute maps to the `useSecureCookie` property of `AbstractRememberMeServices`. + + + [[nsa-remember-me-user-service-ref]] +-* **user-service-ref** ++`user-service-ref`:: + The remember-me services implementations require access to a `UserDetailsService`, so there has to be one defined in the application context. +-If there is only one, it will be selected and used automatically by the namespace configuration. +-If there are multiple instances, you can specify a bean `id` explicitly using this attribute. ++If there is only one, it is selected and automatically used by the namespace configuration. ++If there are multiple instances, you can specify a bean `id` explicitly by setting this attribute. + + + [[nsa-request-cache]] + ==== Element +-Sets the `RequestCache` instance which will be used by the `ExceptionTranslationFilter` to store request information before invoking an `AuthenticationEntryPoint`. ++Sets the `RequestCache` instance, which is used by the `ExceptionTranslationFilter` to store request information before invoking an `AuthenticationEntryPoint`. + + + [[nsa-request-cache-parents]] + ===== Parent Elements of + +-* <> ++The parent element of the `` element is the <`>> element. + + [[nsa-request-cache-attributes]] + ===== Attributes + ++The `` element has only one attribute: + + [[nsa-request-cache-ref]] +-* **ref** ++`ref`:: + Defines a reference to a Spring bean that is a `RequestCache`. + + + [[nsa-session-management]] + ==== +-Session-management related functionality is implemented by the addition of a `SessionManagementFilter` to the filter stack. ++Session-management functionality is implemented by the addition of a `SessionManagementFilter` to the filter stack. This element adds that filter. + + + [[nsa-session-management-parents]] + ===== Parent Elements of + + +-* <> +- ++The parent element of the `` element is the <`>> element. + + + [[nsa-session-management-attributes]] + ===== Attributes + ++The `` has the following attributes: + + [[nsa-session-management-invalid-session-url]] +-* **invalid-session-url** +-Setting this attribute will inject the `SessionManagementFilter` with a `SimpleRedirectInvalidSessionStrategy` configured with the attribute value. +-When an invalid session ID is submitted, the strategy will be invoked, redirecting to the configured URL. ++`invalid-session-url`:: ++Setting this attribute injects a `SessionManagementFilter` with a `SimpleRedirectInvalidSessionStrategy` that is configured with the attribute value. ++When an invalid session ID is submitted, the strategy is invoked, redirecting to the configured URL. + + [[nsa-session-management-invalid-session-strategy-ref]] +-* **invalid-session-url** +-Allows injection of the InvalidSessionStrategy instance used by the SessionManagementFilter. +-Use either this or the `invalid-session-url` attribute but not both. ++`invalid-session-url`:: ++Allows injection of the `InvalidSessionStrategy` instance, which is used by the `SessionManagementFilter`. ++Use either this attribute or the `invalid-session-url` attribute but not both. + + [[nsa-session-management-session-authentication-error-url]] +-* **session-authentication-error-url** +-Defines the URL of the error page which should be shown when the SessionAuthenticationStrategy raises an exception. +-If not set, an unauthorized (401) error code will be returned to the client. +-Note that this attribute doesn't apply if the error occurs during a form-based login, where the URL for authentication failure will take precedence. ++`session-authentication-error-url` ++Defines the URL of the error page, which should be shown when the `SessionAuthenticationStrategy` raises an exception. ++If not set, an unauthorized (401) error code is returned to the client. ++Note that this attribute does not apply if the error occurs during a form-based login, where the URL for authentication failure takes precedence. + + + [[nsa-session-management-session-authentication-strategy-ref]] +-* **session-authentication-strategy-ref** +-Allows injection of the SessionAuthenticationStrategy instance used by the SessionManagementFilter ++`session-authentication-strategy-ref`:: ++Allows injection of a `SessionAuthenticationStrategy` instance, which is used by the `SessionManagementFilter`. + + + [[nsa-session-management-session-fixation-protection]] +-* **session-fixation-protection** +-Indicates how session fixation protection will be applied when a user authenticates. +-If set to "none", no protection will be applied. +-"newSession" will create a new empty session, with only Spring Security-related attributes migrated. +-"migrateSession" will create a new session and copy all session attributes to the new session. +-In Servlet 3.1 (Java EE 7) and newer containers, specifying "changeSessionId" will keep the existing session and use the container-supplied session fixation protection (HttpServletRequest#changeSessionId()). +-Defaults to "changeSessionId" in Servlet 3.1 and newer containers, "migrateSession" in older containers. +-Throws an exception if "changeSessionId" is used in older containers. +- +-+ +- ++session-fixation-protection:: ++Indicates how session fixation protection is applied when a user authenticates. ++If set to `none`, no protection is applied. ++`newSession` creates a new empty session, with only Spring Security-related attributes migrated. ++`migrateSession` creates a new session and copies all session attributes to the new session. ++In Servlet 3.1 (Java EE 7) and newer containers, specifying `changeSessionId` keeps the existing session and uses the container-supplied session fixation protection (`HttpServletRequest#changeSessionId()`). ++It defaults to `changeSessionId` in Servlet 3.1 and newer containers, `migrateSession` in older containers. ++It throws an exception if `changeSessionId` is used in older containers. + If session fixation protection is enabled, the `SessionManagementFilter` is injected with an appropriately configured `DefaultSessionAuthenticationStrategy`. +-See the Javadoc for this class for more details. ++See the {security-api-url}org/springframework/security/web/session/SessionManagementFilter.html[Javadoc for `SessionManagementFilter`] for more details. + + + [[nsa-session-management-children]] + ===== Child Elements of + +- +-* <> +- ++The `` element has only one child element: <`>> + + + [[nsa-concurrency-control]] + ==== +-Adds support for concurrent session control, allowing limits to be placed on the number of active sessions a user can have. +-A `ConcurrentSessionFilter` will be created, and a `ConcurrentSessionControlAuthenticationStrategy` will be used with the `SessionManagementFilter`. +-If a `form-login` element has been declared, the strategy object will also be injected into the created authentication filter. +-An instance of `SessionRegistry` (a `SessionRegistryImpl` instance unless the user wishes to use a custom bean) will be created for use by the strategy. ++The `` adds support for concurrent session control, letting limits be placed on the number of active sessions a user can have. ++A `ConcurrentSessionFilter` is created, and a `ConcurrentSessionControlAuthenticationStrategy` is used with the `SessionManagementFilter`. ++If a `form-login` element has been declared, the strategy object is also injected into the created authentication filter. ++An instance of `SessionRegistry` (a `SessionRegistryImpl` instance unless the user wishes to use a custom bean) is created for use by the strategy. + + + [[nsa-concurrency-control-parents]] + ===== Parent Elements of + +- +-* <> +- ++The parent element of the `` element is the <`>> element. + + + [[nsa-concurrency-control-attributes]] + ===== Attributes + ++The `` element has the following attributes: ++ + + [[nsa-concurrency-control-error-if-maximum-exceeded]] +-* **error-if-maximum-exceeded** +-If set to "true" a `SessionAuthenticationException` will be raised when a user attempts to exceed the maximum allowed number of sessions. +-The default behaviour is to expire the original session. ++`error-if-maximum-exceeded`:: ++If set to `true`, a `SessionAuthenticationException` is raised when a user attempts to exceed the maximum allowed number of sessions. ++The default behavior is to expire the original session. + + + [[nsa-concurrency-control-expired-url]] +-* **expired-url** +-The URL a user will be redirected to if they attempt to use a session which has been "expired" by the concurrent session controller because the user has exceeded the number of allowed sessions and has logged in again elsewhere. +-Should be set unless `exception-if-maximum-exceeded` is set. +-If no value is supplied, an expiry message will just be written directly back to the response. ++`expired-url`:: ++The URL to which a user is redirected if they attempt to use a session which has been "`expired`" by the concurrent session controller because the user has exceeded the number of allowed sessions and has logged in again elsewhere. ++This attribute should be set unless `exception-if-maximum-exceeded` is set. ++If no value is supplied, an expiry message is written directly back to the response. + + [[nsa-concurrency-control-expired-session-strategy-ref]] +-* **expired-url** +-Allows injection of the ExpiredSessionStrategy instance used by the ConcurrentSessionFilter ++`expired-url`:: ++Allows injection of an `ExpiredSessionStrategy` instance, which is used by the `ConcurrentSessionFilter`. + + [[nsa-concurrency-control-max-sessions]] +-* **max-sessions** ++`max-sessions`:: + Maps to the `maximumSessions` property of `ConcurrentSessionControlAuthenticationStrategy`. + Specify `-1` as the value to support unlimited sessions. + + + [[nsa-concurrency-control-session-registry-alias]] +-* **session-registry-alias** ++`session-registry-alias`:: ++Exposes an internal bean and gives it a name that you use elsewhere in your configuration + It can also be useful to have a reference to the internal session registry for use in your own beans or an admin interface. +-You can expose the internal bean using the `session-registry-alias` attribute, giving it a name that you can use elsewhere in your configuration. + + + [[nsa-concurrency-control-session-registry-ref]] +-* **session-registry-ref** +-The user can supply their own `SessionRegistry` implementation using the `session-registry-ref` attribute. +-The other concurrent session control beans will be wired up to use it. ++`session-registry-ref`:: ++Specifies a `SessionRegistry` implementation to use. ++The other concurrent session control beans are wired up to use it. + + + [[nsa-x509]] + ==== +-Adds support for X.509 authentication. +-An `X509AuthenticationFilter` will be added to the stack and an `Http403ForbiddenEntryPoint` bean will be created. +-The latter will only be used if no other authentication mechanisms are in use (its only functionality is to return an HTTP 403 error code). +-A `PreAuthenticatedAuthenticationProvider` will also be created which delegates the loading of user authorities to a `UserDetailsService`. ++The `` element adds support for X.509 authentication. ++An `X509AuthenticationFilter` is added to the stack, and an `Http403ForbiddenEntryPoint` bean is created. ++The latter is used only if no other authentication mechanisms are in use. (Its only functionality is to return an HTTP 403 error code.) ++A `PreAuthenticatedAuthenticationProvider` is also created. It delegates the loading of user authorities to a `UserDetailsService`. + + + [[nsa-x509-parents]] + ===== Parent Elements of + +- +-* <> +- ++The parent element of the `` element is the <`>> element. + + + [[nsa-x509-attributes]] + ===== Attributes + ++The `` element has the following attributes: + + [[nsa-x509-authentication-details-source-ref]] +-* **authentication-details-source-ref** +-A reference to an `AuthenticationDetailsSource` ++`authentication-details-source-ref`:: ++A reference to an `AuthenticationDetailsSource`. + + + [[nsa-x509-subject-principal-regex]] +-* **subject-principal-regex** +-Defines a regular expression which will be used to extract the username from the certificate (for use with the `UserDetailsService`). ++`subject-principal-regex`:: ++Defines a regular expression, which is used to extract the username from the certificate (for use with the `UserDetailsService`). + + + [[nsa-x509-user-service-ref]] +-* **user-service-ref** +-Allows a specific `UserDetailsService` to be used with X.509 in the case where multiple instances are configured. +-If not set, an attempt will be made to locate a suitable instance automatically and use that. ++`user-service-ref`:: ++Lets a specific `UserDetailsService` be used with X.509 when where multiple instances are configured. ++If not set, an attempt is made to locate a suitable instance automatically and use that. + + + [[nsa-filter-chain-map]] + ==== +-Used to explicitly configure a FilterChainProxy instance with a FilterChainMap ++The `` explicitly configures a `FilterChainProxy` instance with a `FilterChainMap`. + + + [[nsa-filter-chain-map-attributes]] + ===== Attributes + ++The `` element has one attribute: ++ + + [[nsa-filter-chain-map-request-matcher]] +-* **request-matcher** ++`request-matcher`:: + Defines the strategy to use for matching incoming requests. +-Currently the options are 'ant' (for ant path patterns), 'regex' for regular expressions and 'ciRegex' for case-insensitive regular expressions. ++Currently, the options are `ant` (for Ant path patterns), `regex` (for regular expressions), and `ciRegex` (for case-insensitive regular expressions). + + + [[nsa-filter-chain-map-children]] + ===== Child Elements of + +- +-* <> +- ++The `` element has one child element: <`>>. + + + [[nsa-filter-chain]] + ==== +-Used within to define a specific URL pattern and the list of filters which apply to the URLs matching that pattern. +-When multiple filter-chain elements are assembled in a list in order to configure a FilterChainProxy, the most specific patterns must be placed at the top of the list, with most general ones at the bottom. ++ ++The `` element is used within a `` to define a specific URL pattern and the list of filters that apply to the URLs that match that pattern. ++When multiple `` elements are assembled in a list, to configure a `FilterChainProxy`, the most specific patterns must be placed at the top of the list, with the most general ones at the bottom. + + + [[nsa-filter-chain-parents]] + ===== Parent Elements of + +- +-* <> +- ++The parent element of the `` element is the <`>> element. + + + [[nsa-filter-chain-attributes]] + ===== Attributes + ++The `` element has the following attributes: + + [[nsa-filter-chain-filters]] +-* **filters** +-A comma separated list of references to Spring beans that implement `Filter`. +-The value "none" means that no `Filter` should be used for this `FilterChain`. ++`filters`:: ++A comma-separated list of references to Spring beans that implement `Filter`. ++A value of `none` means that no `Filter` should be used for this `FilterChain`. + + + [[nsa-filter-chain-pattern]] +-* **pattern** +-A pattern that creates RequestMatcher in combination with the <> ++`pattern`:: ++A pattern that creates `RequestMatcher` in combination with the <`>> element. + + + [[nsa-filter-chain-request-matcher-ref]] +-* **request-matcher-ref** +-A reference to a `RequestMatcher` that will be used to determine if any `Filter` from the `filters` attribute should be invoked. ++`request-matcher-ref`:: ++A reference to a `RequestMatcher` that is used to determine if any `Filter` from the `filters` attribute should be invoked. + + + [[nsa-filter-security-metadata-source]] +-==== +-Used to explicitly configure a FilterSecurityMetadataSource bean for use with a FilterSecurityInterceptor. +-Usually only needed if you are configuring a FilterChainProxy explicitly, rather than using the element. +-The intercept-url elements used should only contain pattern, method and access attributes. +-Any others will result in a configuration error. ++==== Element ++The `` is used to explicitly configure a `FilterSecurityMetadataSource` bean for use with a `FilterSecurityInterceptor`. ++The `` is usually only needed if you explicitly configure a `FilterChainProxy` rather than use the `` element. ++The `` elements should contain only pattern, method, and access attributes. ++Any others result in a configuration error. + + + [[nsa-filter-security-metadata-source-attributes]] + ===== Attributes + ++The `` element has the following attributes: + + [[nsa-filter-security-metadata-source-id]] +-* **id** +-A bean identifier, used for referring to the bean elsewhere in the context. ++`id`:: ++A bean identifier, which is used for referring to the bean elsewhere in the context. + + + [[nsa-filter-security-metadata-source-request-matcher]] +-* **request-matcher** ++`request-matcher`:: + Defines the strategy use for matching incoming requests. +-Currently the options are 'ant' (for ant path patterns), 'regex' for regular expressions and 'ciRegex' for case-insensitive regular expressions. ++Currently the options are `ant` (for Ant path patterns), `regex` (for regular expressions), and `ciRegex` (for case-insensitive regular expressions). + + + [[nsa-filter-security-metadata-source-use-expressions]] +-* **use-expressions** +-Enables the use of expressions in the 'access' attributes in elements rather than the traditional list of configuration attributes. +-Defaults to 'true'. ++use-expressions:: ++Enables the use of expressions in the `access` attributes in `` elements rather than the traditional list of configuration attributes. ++Default: `true` + If enabled, each attribute should contain a single Boolean expression. +-If the expression evaluates to 'true', access will be granted. ++If the expression evaluates to `true`, access is granted. + + + [[nsa-filter-security-metadata-source-children]] + ===== Child Elements of + +- +-* <> ++The `` has a single child element: <`>>. + + [[nsa-websocket-security]] + === WebSocket Security +@@ -1997,145 +2021,160 @@ Spring Security 4.0+ provides support for authorizing messages. + One concrete example of where this is useful is to provide authorization in WebSocket based applications. + + [[nsa-websocket-message-broker]] +-==== ++==== Element + +-The websocket-message-broker element has two different modes. +-If the <> is not specified, then it will do the following things: ++The `` element has two different modes. ++If the <> is not specified, it does the following things: + +-* Ensure that any SimpAnnotationMethodMessageHandler has the AuthenticationPrincipalArgumentResolver registered as a custom argument resolver. +-This allows the use of `@AuthenticationPrincipal` to resolve the principal of the current `Authentication` +-* Ensures that the SecurityContextChannelInterceptor is automatically registered for the clientInboundChannel. +-This populates the SecurityContextHolder with the user that is found in the Message +-* Ensures that a ChannelSecurityInterceptor is registered with the clientInboundChannel. ++* Ensure that any `SimpAnnotationMethodMessageHandler` has the `AuthenticationPrincipalArgumentResolver` registered as a custom argument resolver. ++This allows the use of `@AuthenticationPrincipal` to resolve the principal of the current `Authentication`. ++* Ensures that the `SecurityContextChannelInterceptor` is automatically registered for the `clientInboundChannel`. ++This populates the `SecurityContextHolder` with the user that is found in the message. ++* Ensures that a `ChannelSecurityInterceptor` is registered with the `clientInboundChannel`. + This allows authorization rules to be specified for a message. +-* Ensures that a CsrfChannelInterceptor is registered with the clientInboundChannel. ++* Ensures that a `CsrfChannelInterceptor` is registered with the `clientInboundChannel`. + This ensures that only requests from the original domain are enabled. +-* Ensures that a CsrfTokenHandshakeInterceptor is registered with WebSocketHttpRequestHandler, TransportHandlingSockJsService, or DefaultSockJsService. +-This ensures that the expected CsrfToken from the HttpServletRequest is copied into the WebSocket Session attributes. ++* Ensures that a `CsrfTokenHandshakeInterceptor` is registered with a `WebSocketHttpRequestHandler`, a `TransportHandlingSockJsService`, or a `DefaultSockJsService`. ++This ensures that the expected `CsrfToken` from the `HttpServletRequest` is copied into the WebSocket Session attributes. + +-If additional control is necessary, the id can be specified and a ChannelSecurityInterceptor will be assigned to the specified id. +-All the wiring with Spring's messaging infrastructure can then be done manually. +-This is more cumbersome, but provides greater control over the configuration. ++If additional control is necessary, you can specify the ID, and a `ChannelSecurityInterceptor` is assigned to the specified ID. ++You can then manually wire Spring's messaging infrastructure. ++This is more cumbersome, but doing so provides greater control over the configuration. + + + [[nsa-websocket-message-broker-attributes]] + ===== Attributes + ++The `` element has the following attributes: ++ + [[nsa-websocket-message-broker-id]] +-* **id** A bean identifier, used for referring to the ChannelSecurityInterceptor bean elsewhere in the context. ++`id`:: ++A bean identifier, used to refer to the `ChannelSecurityInterceptor` bean elsewhere in the context. + If specified, Spring Security requires explicit configuration within Spring Messaging. +-If not specified, Spring Security will automatically integrate with the messaging infrastructure as described in <> ++If not specified, Spring Security automatically integrates with the messaging infrastructure, as described in <> + + [[nsa-websocket-message-broker-same-origin-disabled]] +-* **same-origin-disabled** Disables the requirement for CSRF token to be present in the Stomp headers (default false). +-Changing the default is useful if it is necessary to allow other origins to make SockJS connections. ++`same-origin-disabled`:: ++Disables the requirement for a CSRF token to be present in the Stomp headers. ++Default: `false` ++Changing the default lets other origins make SockJS connections. + + [[nsa-websocket-message-broker-children]] + ===== Child Elements of + ++The `` element has the following child elements: + +-* <> +-* <> ++* <`>> ++* <`>> + + [[nsa-intercept-message]] +-==== ++==== Element + +-Defines an authorization rule for a message. ++The `` defines an authorization rule for a message. + + + [[nsa-intercept-message-parents]] + ===== Parent Elements of + +- +-* <> ++The parent element of the `` element is the <> element. + + + [[nsa-intercept-message-attributes]] + ===== Attributes + ++The `` element has the following attributes: ++ + [[nsa-intercept-message-pattern]] +-* **pattern** An ant based pattern that matches on the Message destination. +-For example, "/**" matches any Message with a destination; "/admin/**" matches any Message that has a destination that starts with "/admin/**". ++`pattern`:: ++An Ant-based pattern that matches on the message destination. ++For example, `/**` matches any message with a destination, while `/admin/**` matches any message that has a destination that starts with `/admin/`. + + [[nsa-intercept-message-type]] +-* **type** The type of message to match on. +-Valid values are defined in SimpMessageType (i.e. CONNECT, CONNECT_ACK, HEARTBEAT, MESSAGE, SUBSCRIBE, UNSUBSCRIBE, DISCONNECT, DISCONNECT_ACK, OTHER). ++`type`:: ++The type of message to match on. ++SimpMessageType defines the valid values: `CONNECT`, `CONNECT_ACK`, `HEARTBEAT`, `MESSAGE`, `SUBSCRIBE`, `UNSUBSCRIBE`, `DISCONNECT`, `DISCONNECT_ACK`, and `OTHER`). + + [[nsa-intercept-message-access]] +-* **access** The expression used to secure the Message. +-For example, "denyAll" will deny access to all of the matching Messages; "permitAll" will grant access to all of the matching Messages; "hasRole('ADMIN') requires the current user to have the role 'ROLE_ADMIN' for the matching Messages. ++`access`:: ++The expression used to secure the message. ++Here are some examples: +++ ++* `denyAll`: Denies access to all of the matching messages. ++* `permitAll`: Grants access to all of the matching Messages. ++* `hasRole('ADMIN')`: Requires the current user to have a role of `ROLE_ADMIN` for the matching messages. + + [[nsa-authentication]] + === Authentication Services + Before Spring Security 3.0, an `AuthenticationManager` was automatically registered internally. +-Now you must register one explicitly using the `` element. +-This creates an instance of Spring Security's `ProviderManager` class, which needs to be configured with a list of one or more `AuthenticationProvider` instances. +-These can either be created using syntax elements provided by the namespace, or they can be standard bean definitions, marked for addition to the list using the `authentication-provider` element. ++Now you must register one explicitly by using the `` element. ++Doing so creates an instance of Spring Security's `ProviderManager` class, which needs to be configured with a list of one or more `AuthenticationProvider` instances. ++You can create these instances either by using syntax elements provided by the namespace or by using standard bean definitions, marked for addition to the list by using the `authentication-provider` element. + + + [[nsa-authentication-manager]] +-==== +-Every Spring Security application which uses the namespace must have include this element somewhere. +-It is responsible for registering the `AuthenticationManager` which provides authentication services to the application. +-All elements which create `AuthenticationProvider` instances should be children of this element. ++==== Element ++Every Spring Security application that uses the namespace must include the `` element somewhere. ++It is responsible for registering the `AuthenticationManager`, which provides authentication services to the application. ++All elements that create `AuthenticationProvider` instances should be children of this element. + + + [[nsa-authentication-manager-attributes]] + ===== Attributes + ++The `` element has the following attributes: + + [[nsa-authentication-manager-alias]] +-* **alias** +-This attribute allows you to define an alias name for the internal instance for use in your own configuration. ++`alias`:: ++This attribute lets you define an alias name for the internal instance to use in your own configuration. + + + [[nsa-authentication-manager-erase-credentials]] +-* **erase-credentials** +-If set to true, the AuthenticationManager will attempt to clear any credentials data in the returned Authentication object, once the user has been authenticated. +-Literally it maps to the `eraseCredentialsAfterAuthentication` property of the <>. ++`erase-credentials`:: ++If set to `true`, the `AuthenticationManager` tries to clear any credentials data in the returned `Authentication` object, once the user has been authenticated. ++Literally, it maps to the `eraseCredentialsAfterAuthentication` property of the <>. + + + [[nsa-authentication-manager-id]] +-* **id** +-This attribute allows you to define an id for the internal instance for use in your own configuration. +-It is the same as the alias element, but provides a more consistent experience with elements that use the id attribute. ++`id`:: ++This attribute lets you define an ID for the internal instance to use in your own configuration. ++It is the same as the `alias` element but provides a more consistent experience with elements that use the `id` attribute. + + + [[nsa-authentication-manager-children]] + ===== Child Elements of + ++The `` element has the following child elements: + +-* <> +-* <> ++* <`>> ++* <`>> + + + + [[nsa-authentication-provider]] +-==== +-Unless used with a `ref` attribute, this element is shorthand for configuring a `DaoAuthenticationProvider`. +-`DaoAuthenticationProvider` loads user information from a `UserDetailsService` and compares the username/password combination with the values supplied at login. +-The `UserDetailsService` instance can be defined either by using an available namespace element (`jdbc-user-service` or by using the `user-service-ref` attribute to point to a bean defined elsewhere in the application context). +- ++==== Element ++Unless used with a `ref` attribute, the `` element is shorthand for configuring a `DaoAuthenticationProvider`. ++A `DaoAuthenticationProvider` loads user information from a `UserDetailsService` and compares the username and password combination with the values supplied at login. ++You can define the `UserDetailsService` instance either by using an available namespace element (`jdbc-user-service`) or by using the `user-service-ref` attribute to point to a bean defined elsewhere in the application context. + + + [[nsa-authentication-provider-parents]] + ===== Parent Elements of + +- +-* <> +- ++The parent element of the `` element is the <`>> element. + + + [[nsa-authentication-provider-attributes]] + ===== Attributes + ++The `` element has the following attributes: + + [[nsa-authentication-provider-ref]] +-* **ref** ++ref:: + Defines a reference to a Spring bean that implements `AuthenticationProvider`. +- +-If you have written your own `AuthenticationProvider` implementation (or want to configure one of Spring Security's own implementations as a traditional bean for some reason, then you can use the following syntax to add it to the internal list of `ProviderManager`: +- +++ ++If you have written your own `AuthenticationProvider` implementation (or want to configure one of Spring Security's implementations as a traditional bean for some reason), you can use the following syntax to add it to the internal list of `ProviderManager`: +++ ++==== + [source,xml] + ---- + +@@ -2145,66 +2184,63 @@ If you have written your own `AuthenticationProvider` implementation (or want to + + + ---- +- +- ++==== + + + [[nsa-authentication-provider-user-service-ref]] +-* **user-service-ref** +-A reference to a bean that implements UserDetailsService that may be created using the standard bean element or the custom user-service element. ++`user-service-ref`:: ++A reference to a bean that implements `UserDetailsService`, which may be created by using the standard bean element or the custom user-service element. + + + [[nsa-authentication-provider-children]] + ===== Child Elements of + ++The `` element has the following child elements: + +-* <> +-* <> +-* <> +-* <> +- ++* <`>> ++* <`>> ++* <`>> ++* <`>> + + + [[nsa-jdbc-user-service]] + ==== +-Causes creation of a JDBC-based UserDetailsService. ++The `` element causes the creation of a JDBC-based `UserDetailsService`. + + + [[nsa-jdbc-user-service-attributes]] + ===== Attributes + ++The `` element has the following attributes: + + [[nsa-jdbc-user-service-authorities-by-username-query]] +-* **authorities-by-username-query** ++`authorities-by-username-query`:: + An SQL statement to query for a user's granted authorities given a username. +- +-The default is +- +++ ++The default is as follows: ++==== + [source] + ---- + select username, authority from authorities where username = ? + ---- +- +- +- ++==== + + [[nsa-jdbc-user-service-cache-ref]] +-* **cache-ref** +-Defines a reference to a cache for use with a UserDetailsService. ++`cache-ref`:: ++Defines a reference to a cache for use with a `UserDetailsService`. + + + [[nsa-jdbc-user-service-data-source-ref]] +-* **data-source-ref** +-The bean ID of the DataSource which provides the required tables. ++`data-source-ref`:: ++The bean ID of the DataSource that provides the required tables. + + + [[nsa-jdbc-user-service-group-authorities-by-username-query]] +-* **group-authorities-by-username-query** +-An SQL statement to query user's group authorities given a username. +-The default is +- ++`group-authorities-by-username-query`:: ++An SQL statement to query user's group authorities, given a username. ++The default is as follows: + + +- ++==== + [source] + ---- + select +@@ -2214,750 +2250,718 @@ groups g, group_members gm, group_authorities ga + where + gm.username = ? and g.id = ga.group_id and g.id = gm.group_id + ---- +- +- +- ++==== + + [[nsa-jdbc-user-service-id]] +-* **id** +-A bean identifier, used for referring to the bean elsewhere in the context. +- ++`id`:: ++A bean identifier, which is used for referring to the bean elsewhere in the context. + + [[nsa-jdbc-user-service-role-prefix]] +-* **role-prefix** +-A non-empty string prefix that will be added to role strings loaded from persistent storage (default is "ROLE_"). +-Use the value "none" for no prefix in cases where the default is non-empty. +- ++`role-prefix`:: ++A non-empty string prefix that is added to role strings loaded from persistent storage. ++Default: `ROLE_` ++Use a value of `none` for no prefix in cases where the default should be non-empty. + + [[nsa-jdbc-user-service-users-by-username-query]] +-* **users-by-username-query** +-An SQL statement to query a username, password, and enabled status given a username. +-The default is +- ++`users-by-username-query`:: ++An SQL statement to query a username, password, and enabled status, given a username. ++The default is as follows: + + +- ++==== + [source] + ---- + select username, password, enabled from users where username = ? + ---- +- ++==== + + + + [[nsa-password-encoder]] +-==== +-Authentication providers can optionally be configured to use a password encoder as described in the <>. +-This will result in the bean being injected with the appropriate `PasswordEncoder` instance. ++==== Element ++Injects a bean with the appropriate `PasswordEncoder` instance. ++Authentication providers can optionally be configured to use a password encoder, as described in the <>. + + + [[nsa-password-encoder-parents]] + ===== Parent Elements of + ++The `` element has the following parent elements: + +-* <> +-* <> ++* <`>> ++* <`>> + + + + [[nsa-password-encoder-attributes]] + ===== Attributes + ++The `` element has the following attributes: + + [[nsa-password-encoder-hash]] +-* **hash** +-Defines the hashing algorithm used on user passwords. +-We recommend strongly against using MD4, as it is a very weak hashing algorithm. ++`hash`:: ++Defines the hashing algorithm for user passwords. ++IMPORTANT: We recommend strongly against using MD4, as it is a very weak hashing algorithm. + + + [[nsa-password-encoder-ref]] +-* **ref** ++`ref`:: + Defines a reference to a Spring bean that implements `PasswordEncoder`. + + + [[nsa-user-service]] +-==== +-Creates an in-memory UserDetailsService from a properties file or a list of "user" child elements. +-Usernames are converted to lower-case internally to allow for case-insensitive lookups, so this should not be used if case-sensitivity is required. ++==== Element ++The `` element creates an in-memory `UserDetailsService` from a properties file or a list of `` child elements. ++Usernames are converted to lower case internally, to allow for case-insensitive lookups, so do not use this element if you need case-sensitivity. + + + [[nsa-user-service-attributes]] + ===== Attributes + ++The `` element has the following attributes: + + [[nsa-user-service-id]] +-* **id** +-A bean identifier, used for referring to the bean elsewhere in the context. ++`id`:: ++A bean identifier, used to refer to the bean elsewhere in the context. + + + [[nsa-user-service-properties]] +-* **properties** +-The location of a Properties file where each line is in the format of +- ++`properties`:: ++The location of a properties file, in which each line is in the format of + + +- ++==== + [source] + ---- + username=password,grantedAuthority[,grantedAuthority][,enabled|disabled] + ---- +- +- ++==== + + + [[nsa-user-service-children]] +-===== Child Elements of +- +- +-* <> ++===== Child Element of + ++The `` element has a single child element: <`>>. ++Multiple `` elements can be present. + + + [[nsa-user]] +-==== +-Represents a user in the application. ++==== Element ++The `` represents a user in the application. + + + [[nsa-user-parents]] +-===== Parent Elements of +- +- +-* <> ++===== Parent Element of + ++The parent element of the `` element is the <`>> element. + + + [[nsa-user-attributes]] + ===== Attributes + ++The `` element has the following elements: + + [[nsa-user-authorities]] +-* **authorities** +-One of more authorities granted to the user. +-Separate authorities with a comma (but no space). +-For example, "ROLE_USER,ROLE_ADMINISTRATOR" +- ++`authorities`:: ++One of more authorities to be granted to the user. ++Separate authorities with a comma (but no space) -- for example, `ROLE_USER,ROLE_ADMINISTRATOR`. + + [[nsa-user-disabled]] +-* **disabled** +-Can be set to "true" to mark an account as disabled and unusable. +- ++`disabled`:: ++Set to `true` to mark an account as disabled and unusable. + + [[nsa-user-locked]] +-* **locked** +-Can be set to "true" to mark an account as locked and unusable. +- ++`locked`:: ++Set to `true` to mark an account as locked and unusable. + + [[nsa-user-name]] +-* **name** ++`name`:: + The username assigned to the user. + +- + [[nsa-user-password]] +-* **password** ++`password`:: + The password assigned to the user. +-This may be hashed if the corresponding authentication provider supports hashing (remember to set the "hash" attribute of the "user-service" element). +-This attribute be omitted in the case where the data will not be used for authentication, but only for accessing authorities. +-If omitted, the namespace will generate a random value, preventing its accidental use for authentication. +-Cannot be empty. ++This value may be hashed if the corresponding authentication provider supports hashing (remember to set the `hash` attribute of the `user-service` element). ++You can omit this attribute when the data is not used for authentication but only for accessing authorities. ++If omitted, the namespace generates a random value, preventing its accidental use for authentication. ++This attribute cannot be empty. + + + [[nsa-method-security]] + === Method Security + ++The Spring Security namespace provides a number elements to enable method security. ++ + + [[nsa-global-method-security]] +-==== +-This element is the primary means of adding support for securing methods on Spring Security beans. +-Methods can be secured by the use of annotations (defined at the interface or class level) or by defining a set of pointcuts as child elements, using AspectJ syntax. ++==== element ++The `` element is the primary means of adding support for securing methods on Spring Security beans. ++You can secure methods by using annotations (defined at the interface or class level) or by defining a set of pointcuts as child elements with AspectJ syntax. + + + [[nsa-global-method-security-attributes]] + ===== Attributes + ++The `` element has the following attributes: + + [[nsa-global-method-security-access-decision-manager-ref]] +-* **access-decision-manager-ref** +-Method security uses the same `AccessDecisionManager` configuration as web security, but this can be overridden using this attribute. +-By default an AffirmativeBased implementation is used for with a RoleVoter and an AuthenticatedVoter. +- ++`access-decision-manager-ref`:: ++Method security uses the same `AccessDecisionManager` configuration as web security, but using this attribute can override this arrangement. ++By default, an `AffirmativeBased` implementation is used with a `RoleVoter` and an `AuthenticatedVoter`. + + [[nsa-global-method-security-authentication-manager-ref]] +-* **authentication-manager-ref** +-A reference to an `AuthenticationManager` that should be used for method security. +- ++`authentication-manager-ref`:: ++A reference to the `AuthenticationManager` that should be used for method security. + + [[nsa-global-method-security-jsr250-annotations]] +-* **jsr250-annotations** +-Specifies whether JSR-250 style attributes are to be used (for example "RolesAllowed"). +-This will require the javax.annotation.security classes on the classpath. +-Setting this to true also adds a `Jsr250Voter` to the `AccessDecisionManager`, so you need to make sure you do this if you are using a custom implementation and want to use these annotations. ++`jsr250-annotations`:: ++Specifies whether JSR-250 style attributes are to be used (for example, `RolesAllowed`). ++Doing so requires the `javax.annotation.security` classes to be on the classpath. ++Setting this to `true` also adds a `Jsr250Voter` to the `AccessDecisionManager`, so you need to make sure that you do so if you use a custom implementation and want to use these annotations. + + + [[nsa-global-method-security-metadata-source-ref]] +-* **metadata-source-ref** +-An external `MethodSecurityMetadataSource` instance can be supplied which will take priority over other sources (such as the default annotations). +- ++metadata-source-ref:: ++You can supply an external `MethodSecurityMetadataSource` instance, which will take priority over other sources (such as the default annotations). + + [[nsa-global-method-security-mode]] +-* **mode** +-This attribute can be set to "aspectj" to specify that AspectJ should be used instead of the default Spring AOP. +-Secured methods must be woven with the `AnnotationSecurityAspect` from the `spring-security-aspects` module. +- +-It is important to note that AspectJ follows Java's rule that annotations on interfaces are not inherited. +-This means that methods that define the Security annotations on the interface will not be secured. +-Instead, you must place the Security annotation on the class when using AspectJ. +- ++mode:: ++You can set this attribute to `aspectj` to specify that AspectJ should be used instead of the default Spring AOP. ++You must weave secured methods with the `AnnotationSecurityAspect` from the `spring-security-aspects` module. +++ ++NOTE: AspectJ follows Java's rule that annotations on interfaces are not inherited. ++This means that methods that define the Security annotations on the interface are not secured. ++Instead, you must place the Security annotation on the class when you use AspectJ. + + [[nsa-global-method-security-order]] +-* **order** +-Allows the advice "order" to be set for the method security interceptor. +- ++`order`:: ++Lets the `order` advice be set for the method security interceptor. + + [[nsa-global-method-security-pre-post-annotations]] +-* **pre-post-annotations** +-Specifies whether the use of Spring Security's pre and post invocation annotations (@PreFilter, @PreAuthorize, @PostFilter, @PostAuthorize) should be enabled for this application context. +-Defaults to "disabled". +- ++`pre-post-annotations`:: ++Specifies whether the use of Spring Security's pre- and post-invocation annotations (`@PreFilter`, `@PreAuthorize`, `@PostFilter`, and `@PostAuthorize`) should be enabled for this application context. ++Default: `disabled` + + [[nsa-global-method-security-proxy-target-class]] +-* **proxy-target-class** +-If true, class based proxying will be used instead of interface based proxying. +- ++`proxy-target-class`:: ++If `true`, class-based proxying is used instead of interface-based proxying. + + [[nsa-global-method-security-run-as-manager-ref]] +-* **run-as-manager-ref** +-A reference to an optional `RunAsManager` implementation which will be used by the configured `MethodSecurityInterceptor` +- ++`run-as-manager-ref`:: ++A reference to an optional `RunAsManager` implementation, which is used by the configured `MethodSecurityInterceptor`. + + [[nsa-global-method-security-secured-annotations]] +-* **secured-annotations** +-Specifies whether the use of Spring Security's @Secured annotations should be enabled for this application context. +-Defaults to "disabled". ++`secured-annotations`:: ++Specifies whether the use of Spring Security's `@Secured` annotations should be enabled for this application context. ++Default: `disabled` + + + [[nsa-global-method-security-children]] + ===== Child Elements of + ++The `` has the following child elements: + +-* <> +-* <> +-* <> +-* <> +- ++* <`>> ++* <`>> ++* <`>> ++* <`>> + + + [[nsa-after-invocation-provider]] +-==== +-This element can be used to decorate an `AfterInvocationProvider` for use by the security interceptor maintained by the `` namespace. +-You can define zero or more of these within the `global-method-security` element, each with a `ref` attribute pointing to an `AfterInvocationProvider` bean instance within your application context. ++==== Element ++You can use the `` element to decorate an `AfterInvocationProvider` for use by the security interceptor that is maintained by the `` namespace. ++You can define zero or more of these elements within the `global-method-security` element, each with a `ref` attribute that points to an `AfterInvocationProvider` bean instance within your application context. + + + [[nsa-after-invocation-provider-parents]] + ===== Parent Elements of + +- +-* <> +- ++The parent element of the `` is the <`>> element. + + + [[nsa-after-invocation-provider-attributes]] + ===== Attributes + ++The `` element has a single attribute: + + [[nsa-after-invocation-provider-ref]] +-* **ref** ++`ref`:: + Defines a reference to a Spring bean that implements `AfterInvocationProvider`. + + + [[nsa-pre-post-annotation-handling]] + ==== +-Allows the default expression-based mechanism for handling Spring Security's pre and post invocation annotations (@PreFilter, @PreAuthorize, @PostFilter, @PostAuthorize) to be replaced entirely. +-Only applies if these annotations are enabled. ++The `` lets us entirely replace the default expression-based mechanism for handling Spring Security's pre- and post-invocation annotations (`@PreFilter`, `@PreAuthorize`, `@PostFilter`, `@PostAuthorize`). ++It applies only if these annotations are enabled. + + + [[nsa-pre-post-annotation-handling-parents]] + ===== Parent Elements of + +- +-* <> +- ++The parent element of the `` element is the <`>> element. + + + [[nsa-pre-post-annotation-handling-children]] + ===== Child Elements of + ++The `` element has the following children: + +-* <> +-* <> +-* <> ++* <`>> ++* <`>> ++* <`>> + + + + [[nsa-invocation-attribute-factory]] + ==== +-Defines the PrePostInvocationAttributeFactory instance which is used to generate pre and post invocation metadata from the annotated methods. ++The `` element defines the `PrePostInvocationAttributeFactory` instance to use to generate pre- and post-invocation metadata from the annotated methods. + + + [[nsa-invocation-attribute-factory-parents]] + ===== Parent Elements of + +- +-* <> +- ++The parent element of the `` element is the <> element. + + + [[nsa-invocation-attribute-factory-attributes]] + ===== Attributes + ++The `` has a single attribute: + + [[nsa-invocation-attribute-factory-ref]] +-* **ref** +-Defines a reference to a Spring bean Id. ++`ref`:: ++Defines a reference to a Spring bean ID. + + + [[nsa-post-invocation-advice]] + ==== +-Customizes the `PostInvocationAdviceProvider` with the ref as the `PostInvocationAuthorizationAdvice` for the element. ++The `` element customizes the `PostInvocationAdviceProvider` with the value of the `ref` attribute as the `PostInvocationAuthorizationAdvice` for the `` element. + + + [[nsa-post-invocation-advice-parents]] + ===== Parent Elements of + +- +-* <> +- ++The parent element of the `` element is the <`>> element. + + + [[nsa-post-invocation-advice-attributes]] + ===== Attributes + ++The `` has a single attribute: + + [[nsa-post-invocation-advice-ref]] +-* **ref** +-Defines a reference to a Spring bean Id. ++`ref`:: ++Defines a reference to a Spring bean ID. + + + [[nsa-pre-invocation-advice]] + ==== +-Customizes the `PreInvocationAuthorizationAdviceVoter` with the ref as the `PreInvocationAuthorizationAdviceVoter` for the element. ++The `` element customizes the `PreInvocationAuthorizationAdviceVoter` with the value of the `ref` attribute as the `PreInvocationAuthorizationAdviceVoter` for the `` element. + + + [[nsa-pre-invocation-advice-parents]] + ===== Parent Elements of + +- +-* <> +- ++The parent element of the `` is the <`>> element. + + + [[nsa-pre-invocation-advice-attributes]] + ===== Attributes + ++The `` element has a single attribute: + + [[nsa-pre-invocation-advice-ref]] +-* **ref** +-Defines a reference to a Spring bean Id. ++ref:: ++Defines a reference to a Spring bean ID. + + + [[nsa-protect-pointcut]] +-==== Securing Methods using +-`` +-Rather than defining security attributes on an individual method or class basis using the `@Secured` annotation, you can define cross-cutting security constraints across whole sets of methods and interfaces in your service layer using the `` element. ++==== Securing Methods by Using ++Rather than defining security attributes on an individual method or class basis by using the `@Secured` annotation, you can define cross-cutting security constraints across whole sets of methods and interfaces in your service layer by using the `` element. + You can find an example in the <>. + + + [[nsa-protect-pointcut-parents]] + ===== Parent Elements of + +- +-* <> ++The parent element of the `` element is the <`>> element. + + + + [[nsa-protect-pointcut-attributes]] + ===== Attributes + ++The `` has the following attributes: + + [[nsa-protect-pointcut-access]] +-* **access** +-Access configuration attributes list that applies to all methods matching the pointcut, e.g. +-"ROLE_A,ROLE_B" ++`access`:: ++Access configuration attributes list that applies to all methods that match the pointcut -- for example, ++`ROLE_A,ROLE_B`. + + + [[nsa-protect-pointcut-expression]] +-* **expression** +-An AspectJ expression, including the `execution` keyword. +-For example, `execution(int com.foo.TargetObject.countLength(String))`. ++`expression`:: ++An AspectJ expression, including the `execution` keyword -- for example, `execution(int com.foo.TargetObject.countLength(String))`. + + + [[nsa-intercept-methods]] + ==== +-Can be used inside a bean definition to add a security interceptor to the bean and set up access configuration attributes for the bean's methods ++You can use the `` element inside a bean definition to add a security interceptor to the bean and set up access configuration attributes for the bean's methods + + + [[nsa-intercept-methods-attributes]] + ===== Attributes + ++The `` element has a single attribute: + + [[nsa-intercept-methods-access-decision-manager-ref]] +-* **access-decision-manager-ref** +-Optional AccessDecisionManager bean ID to be used by the created method security interceptor. ++`access-decision-manager-ref`:: ++Optional `AccessDecisionManager` bean ID to be used by the created method security interceptor. + + + [[nsa-intercept-methods-children]] + ===== Child Elements of + +- +-* <> +- ++The parent element of the `` is the <`>> element. + + + [[nsa-method-security-metadata-source]] + ==== +-Creates a MethodSecurityMetadataSource instance ++The `` element creates a `MethodSecurityMetadataSource` instance. + + + [[nsa-method-security-metadata-source-attributes]] + ===== Attributes + ++The `` element has the following attributes: + + [[nsa-method-security-metadata-source-id]] +-* **id** ++`id`:: + A bean identifier, used for referring to the bean elsewhere in the context. + + + [[nsa-method-security-metadata-source-use-expressions]] +-* **use-expressions** +-Enables the use of expressions in the 'access' attributes in elements rather than the traditional list of configuration attributes. +-Defaults to 'false'. ++`use-expressions`:: ++Enables the use of expressions in the `access` attributes of `` elements rather than the traditional list of configuration attributes. ++Default: `false` + If enabled, each attribute should contain a single Boolean expression. +-If the expression evaluates to 'true', access will be granted. ++If the expression evaluates to `true`, access is granted. + + + [[nsa-method-security-metadata-source-children]] + ===== Child Elements of + +- +-* <> +- ++The `` has a single child element: <`>>. + + + [[nsa-protect]] + ==== +-Defines a protected method and the access control configuration attributes that apply to it. +-We strongly advise you NOT to mix "protect" declarations with any services provided "global-method-security". ++The `` element defines a protected method and the access control configuration attributes that apply to it. ++We strongly advise you NOT to mix "`protect`" declarations with any services provided by `` element. + + + [[nsa-protect-parents]] + ===== Parent Elements of + ++The `` element has two parent elements: + +-* <> +-* <> +- ++* <`>> ++* <`>> + + + [[nsa-protect-attributes]] + ===== Attributes + ++The `` element has the following attributes: + + [[nsa-protect-access]] +-* **access** +-Access configuration attributes list that applies to the method, e.g. +-"ROLE_A,ROLE_B". ++`access`:: ++Access configuration attributes list that applies to the method -- for example, ++`ROLE_A,ROLE_B`. + + + [[nsa-protect-method]] +-* **method** +-A method name ++`method`:: ++A method name. + + + [[nsa-ldap]] + === LDAP Namespace Options +-LDAP is covered in some details in <>. +-We will expand on that here with some explanation of how the namespace options map to Spring beans. ++LDAP is covered in some detail in <>. ++We expand on that here with some explanation of how the namespace options map to Spring beans. + The LDAP implementation uses Spring LDAP extensively, so some familiarity with that project's API may be useful. + + + [[nsa-ldap-server]] +-==== Defining the LDAP Server using the +-`` Element +-This element sets up a Spring LDAP `ContextSource` for use by the other LDAP beans, defining the location of the LDAP server and other information (such as a username and password, if it doesn't allow anonymous access) for connecting to it. +-It can also be used to create an embedded server for testing. ++==== Defining the LDAP Server by Using the Element ++The `` element sets up a Spring LDAP `ContextSource` for use by the other LDAP beans, defining the location of the LDAP server and other information (such as a username and password, if it does not allow anonymous access) for connecting to it. ++You can also use it to create an embedded server for testing. + Details of the syntax for both options are covered in the <>. +-The actual `ContextSource` implementation is `DefaultSpringSecurityContextSource` which extends Spring LDAP's `LdapContextSource` class. ++The actual `ContextSource` implementation is `DefaultSpringSecurityContextSource`, which extends Spring LDAP's `LdapContextSource` class. + The `manager-dn` and `manager-password` attributes map to the latter's `userDn` and `password` properties respectively. + +-If you only have one server defined in your application context, the other LDAP namespace-defined beans will use it automatically. +-Otherwise, you can give the element an "id" attribute and refer to it from other namespace beans using the `server-ref` attribute. ++If you have only one server defined in your application context, the other LDAP namespace-defined beans use it automatically. ++Otherwise, you can give the element an `id` attribute and refer to it from other namespace beans by using the `server-ref` attribute. + This is actually the bean `id` of the `ContextSource` instance, if you want to use it in other traditional Spring beans. + + + [[nsa-ldap-server-attributes]] + ===== Attributes + ++The `` element has the following attributes: ++ + [[nsa-ldap-server-mode]] +-* **mode** +-Explicitly specifies which embedded ldap server should use. Values are `apacheds` and `unboundid`. By default, it will depends if the library is available in the classpath. ++`mode`:: ++Explicitly specifies which embedded LDAP server to use. Valid values are `apacheds` and `unboundid`. By default, it depends on whether the library is available in the classpath. + + [[nsa-ldap-server-id]] +-* **id** ++`id`:: + A bean identifier, used for referring to the bean elsewhere in the context. + + + [[nsa-ldap-server-ldif]] +-* **ldif** ++`ldif`:: + Explicitly specifies an ldif file resource to load into an embedded LDAP server. +-The ldif should be a Spring resource pattern (i.e. classpath:init.ldif). +-The default is classpath*:*.ldif ++The ldif file should be a Spring resource pattern (such as `classpath:init.ldif`). ++Default: `classpath*:*.ldif` + + + [[nsa-ldap-server-manager-dn]] +-* **manager-dn** +-Username (DN) of the "manager" user identity which will be used to authenticate to a (non-embedded) LDAP server. +-If omitted, anonymous access will be used. ++`manager-dn`:: ++Username (DN) of the "`manager`" user identity, which is used to authenticate to a (non-embedded) LDAP server. ++If omitted, anonymous access is used. + + + [[nsa-ldap-server-manager-password]] +-* **manager-password** ++`manager-password`:: + The password for the manager DN. +-This is required if the manager-dn is specified. ++This is required if the `manager-dn` is specified. + + + [[nsa-ldap-server-port]] +-* **port** ++`port`:: + Specifies an IP port number. +-Used to configure an embedded LDAP server, for example. +-The default value is 33389. ++You can use use it to configure an embedded LDAP server, for example. ++The default value is `33389`. + + + [[nsa-ldap-server-root]] +-* **root** ++`root`:: + Optional root suffix for the embedded LDAP server. +-Default is "dc=springframework,dc=org" ++Default: `dc=springframework,dc=org` + + + [[nsa-ldap-server-url]] +-* **url** +-Specifies the ldap server URL when not using the embedded LDAP server. ++url:: ++Specifies the LDAP server URL when not using the embedded LDAP server. + + + [[nsa-ldap-authentication-provider]] + ==== + This element is shorthand for the creation of an `LdapAuthenticationProvider` instance. +-By default this will be configured with a `BindAuthenticator` instance and a `DefaultAuthoritiesPopulator`. ++By default, this is configured with a `BindAuthenticator` instance and a `DefaultAuthoritiesPopulator`. + As with all namespace authentication providers, it must be included as a child of the `authentication-provider` element. + + + [[nsa-ldap-authentication-provider-parents]] + ===== Parent Elements of + +- +-* <> +- ++The parent element of the `` is the <`>> element. + + + [[nsa-ldap-authentication-provider-attributes]] + ===== Attributes + ++The `` element has the following attributes: + + [[nsa-ldap-authentication-provider-group-role-attribute]] +-* **group-role-attribute** +-The LDAP attribute name which contains the role name which will be used within Spring Security. +-Maps to the ``DefaultLdapAuthoritiesPopulator``'s `groupRoleAttribute` property. +-Defaults to "cn". ++`group-role-attribute`:: ++The LDAP attribute name, which contains the role name that is used within Spring Security. ++Maps to the `groupRoleAttribute` property of the `DefaultLdapAuthoritiesPopulator`. ++Default: `cn` + + + [[nsa-ldap-authentication-provider-group-search-base]] +-* **group-search-base** ++`group-search-base`:: + Search base for group membership searches. +-Maps to the ``DefaultLdapAuthoritiesPopulator``'s `groupSearchBase` constructor argument. +-Defaults to "" (searching from the root). ++Maps to the `groupSearchBase` constructor argument of `DefaultLdapAuthoritiesPopulator`. ++Default: `""` (searching from the root) + + + [[nsa-ldap-authentication-provider-group-search-filter]] +-* **group-search-filter** ++`group-search-filter`:: + Group search filter. +-Maps to the ``DefaultLdapAuthoritiesPopulator``'s `groupSearchFilter` property. +-Defaults to `+(uniqueMember={0})+`. ++Maps to the `groupSearchFilter` property of `DefaultLdapAuthoritiesPopulator`. + The substituted parameter is the DN of the user. ++Default: `+(uniqueMember={0})+` + + + [[nsa-ldap-authentication-provider-role-prefix]] +-* **role-prefix** +-A non-empty string prefix that will be added to role strings loaded from persistent. +-Maps to the ``DefaultLdapAuthoritiesPopulator``'s `rolePrefix` property. +-Defaults to "ROLE_". +-Use the value "none" for no prefix in cases where the default is non-empty. ++`role-prefix`:: ++A non-empty string prefix that is added to role strings loaded from persistent storage. ++Maps to the `rolePrefix` property of `DefaultLdapAuthoritiesPopulator`. ++Use a value of `none` for no prefix in cases where the default is non-empty. ++Default: `ROLE_` + + + [[nsa-ldap-authentication-provider-server-ref]] +-* **server-ref** ++`server-ref`:: + The optional server to use. +-If omitted, and a default LDAP server is registered (using with no Id), that server will be used. ++If omitted, and a default LDAP server is registered (by using `` with no ID), that server is used. + + + [[nsa-ldap-authentication-provider-user-context-mapper-ref]] +-* **user-context-mapper-ref** +-Allows explicit customization of the loaded user object by specifying a UserDetailsContextMapper bean which will be called with the context information from the user's directory entry ++`user-context-mapper-ref`:: ++Allows explicit customization of the loaded user object by specifying a `UserDetailsContextMapper` bean, which is called with the context information from the user's directory entry. + + + [[nsa-ldap-authentication-provider-user-details-class]] +-* **user-details-class** +-Allows the objectClass of the user entry to be specified. +-If set, the framework will attempt to load standard attributes for the defined class into the returned UserDetails object ++`user-details-class`:: ++Lets the `objectClass` of the user entry be specified. ++If set, the framework tries to load standard attributes for the defined class into the returned `UserDetails` object + + + [[nsa-ldap-authentication-provider-user-dn-pattern]] +-* **user-dn-pattern** +-If your users are at a fixed location in the directory (i.e. you can work out the DN directly from the username without doing a directory search), you can use this attribute to map directly to the DN. ++user-dn-pattern:: ++If your users are at a fixed location in the directory (that is, you can work out the DN directly from the username without doing a directory search), you can use this attribute to map directly to the DN. + It maps directly to the `userDnPatterns` property of `AbstractLdapAuthenticator`. +-The value is a specific pattern used to build the user's DN, for example `+uid={0},ou=people+`. +-The key `+{0}+` must be present and will be substituted with the username. ++The value is a specific pattern used to build the user's DN -- for example, `+uid={0},ou=people+`. ++The `+{0}+` key must be present and is substituted with the username. + + + [[nsa-ldap-authentication-provider-user-search-base]] +-* **user-search-base** ++`user-search-base`:: + Search base for user searches. +-Defaults to "". +-Only used with a 'user-search-filter'. +- ++Only used with a `user-search-filter`. ++Default `""` + + +- +-If you need to perform a search to locate the user in the directory, then you can set these attributes to control the search. +-The `BindAuthenticator` will be configured with a `FilterBasedLdapUserSearch` and the attribute values map directly to the first two arguments of that bean's constructor. +-If these attributes aren't set and no `user-dn-pattern` has been supplied as an alternative, then the default search values of `+user-search-filter="(uid={0})"+` and `user-search-base=""` will be used. ++If you need to perform a search to locate the user in the directory, you can set these attributes to control the search. ++The `BindAuthenticator` is configured with a `FilterBasedLdapUserSearch`, and the attribute values map directly to the first two arguments of that bean's constructor. ++If these attributes are not set and no `user-dn-pattern` has been supplied as an alternative, the default search values of `+user-search-filter="(uid={0})"+` and `user-search-base=""` are used. + + + [[nsa-ldap-authentication-provider-user-search-filter]] +-* **user-search-filter** +-The LDAP filter used to search for users (optional). +-For example `+(uid={0})+`. ++`user-search-filter`:: ++The LDAP filter used to search for users (optional) -- for example, `+(uid={0})+`. + The substituted parameter is the user's login name. +- + + +- +-If you need to perform a search to locate the user in the directory, then you can set these attributes to control the search. +-The `BindAuthenticator` will be configured with a `FilterBasedLdapUserSearch` and the attribute values map directly to the first two arguments of that bean's constructor. +-If these attributes aren't set and no `user-dn-pattern` has been supplied as an alternative, then the default search values of `+user-search-filter="(uid={0})"+` and `user-search-base=""` will be used. ++If you need to perform a search to locate the user in the directory, you can set these attributes to control the search. ++The `BindAuthenticator` is configured with a `FilterBasedLdapUserSearch`, and the attribute values map directly to the first two arguments of that bean's constructor. ++If these attributes are not set and no `user-dn-pattern` has been supplied as an alternative, the default search values of `+user-search-filter="(uid={0})"+` and `user-search-base=""` is used. + + + [[nsa-ldap-authentication-provider-children]] + ===== Child Elements of + +- +-* <> +- ++The `` has a single child element: <`>>. + + + [[nsa-password-compare]] + ==== +-This is used as child element to `` and switches the authentication strategy from `BindAuthenticator` to `PasswordComparisonAuthenticator`. ++The `` element is used as a child element to `` and switches the authentication strategy from `BindAuthenticator` to `PasswordComparisonAuthenticator`. + + + [[nsa-password-compare-parents]] + ===== Parent Elements of + +- +-* <> +- ++The parent element of the `` element is the <`>> element. + + + [[nsa-password-compare-attributes]] + ===== Attributes + ++The `` has the following attributes: + + [[nsa-password-compare-hash]] +-* **hash** ++`hash`:: + Defines the hashing algorithm used on user passwords. + We recommend strongly against using MD4, as it is a very weak hashing algorithm. + + + [[nsa-password-compare-password-attribute]] +-* **password-attribute** +-The attribute in the directory which contains the user password. +-Defaults to "userPassword". ++`password-attribute`:: ++The attribute in the directory that contains the user password. ++Default: `userPassword` + + + [[nsa-password-compare-children]] + ===== Child Elements of + +- +-* <> +- ++The `` element has a single child element: <`>>. + + + [[nsa-ldap-user-service]] + ==== +-This element configures an LDAP `UserDetailsService`. +-The class used is `LdapUserDetailsService` which is a combination of a `FilterBasedLdapUserSearch` and a `DefaultLdapAuthoritiesPopulator`. +-The attributes it supports have the same usage as in ``. ++The `` element configures an LDAP `UserDetailsService`. ++It uses `LdapUserDetailsService`, which is a combination of a `FilterBasedLdapUserSearch` and a `DefaultLdapAuthoritiesPopulator`. ++The attributes it supports have the same usage as ``. + + + [[nsa-ldap-user-service-attributes]] + ===== Attributes + ++The `` element has the following attributes: ++ + + [[nsa-ldap-user-service-cache-ref]] +-* **cache-ref** +-Defines a reference to a cache for use with a UserDetailsService. ++`cache-ref`:: ++Defines a reference to a cache for use with a `UserDetailsService`. + + + [[nsa-ldap-user-service-group-role-attribute]] +-* **group-role-attribute** +-The LDAP attribute name which contains the role name which will be used within Spring Security. +-Defaults to "cn". ++`group-role-attribute`:: ++The LDAP attribute name that contains the role name to be used within Spring Security. ++Default: `cn` + + + [[nsa-ldap-user-service-group-search-base]] +-* **group-search-base** ++`group-search-base`:: + Search base for group membership searches. +-Defaults to "" (searching from the root). ++Default: `""` (searching from the root) + + + [[nsa-ldap-user-service-group-search-filter]] +-* **group-search-filter** ++`group-search-filter`:: + Group search filter. +-Defaults to `+(uniqueMember={0})+`. + The substituted parameter is the DN of the user. ++Default: `+(uniqueMember={0})+` + + + [[nsa-ldap-user-service-id]] +-* **id** ++`id`:: + A bean identifier, used for referring to the bean elsewhere in the context. + + + [[nsa-ldap-user-service-role-prefix]] +-* **role-prefix** +-A non-empty string prefix that will be added to role strings loaded from persistent storage (e.g. +-"ROLE_"). +-Use the value "none" for no prefix in cases where the default is non-empty. ++role-prefix:: ++A non-empty string prefix that is added to role strings loaded from persistent storage (for example, ++`ROLE_`). ++Use a value of `none` for no prefix in cases where the default is non-empty. + + + [[nsa-ldap-user-service-server-ref]] +-* **server-ref** ++`server-ref`:: + The optional server to use. +-If omitted, and a default LDAP server is registered (using with no Id), that server will be used. ++If omitted and a default LDAP server is registered (by using `` with no ID), that server is used. + + + [[nsa-ldap-user-service-user-context-mapper-ref]] +-* **user-context-mapper-ref** +-Allows explicit customization of the loaded user object by specifying a UserDetailsContextMapper bean which will be called with the context information from the user's directory entry ++`user-context-mapper-ref`:: ++Allows explicit customization of the loaded user object by specifying a `UserDetailsContextMapper` bean, which is called with the context information from the user's directory entry. + + + [[nsa-ldap-user-service-user-details-class]] +-* **user-details-class** +-Allows the objectClass of the user entry to be specified. +-If set, the framework will attempt to load standard attributes for the defined class into the returned UserDetails object ++`user-details-class`:: ++Lets the `objectClass` of the user entry be specified. ++If set, the framework tries to load standard attributes for the defined class into the returned `UserDetails` object. + + + [[nsa-ldap-user-service-user-search-base]] +-* **user-search-base** ++`user-search-base`:: + Search base for user searches. +-Defaults to "". +-Only used with a 'user-search-filter'. ++It is used only with a <`>> element. ++Default: `""` + + + [[nsa-ldap-user-service-user-search-filter]] +-* **user-search-filter** +-The LDAP filter used to search for users (optional). +-For example `+(uid={0})+`. ++`user-search-filter`:: ++The LDAP filter used to search for users (optional) -- for example, `+(uid={0})+`. + The substituted parameter is the user's login name. +diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/architecture/delegating-filter-proxy.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/architecture/delegating-filter-proxy.adoc +index d7c3d45ed3..5743b93868 100644 +--- a/docs/manual/src/docs/asciidoc/_includes/servlet/architecture/delegating-filter-proxy.adoc ++++ b/docs/manual/src/docs/asciidoc/_includes/servlet/architecture/delegating-filter-proxy.adoc +@@ -2,17 +2,19 @@ + = DelegatingFilterProxy + + Spring provides a `Filter` implementation named {security-api-url}org/springframework/web/filter/DelegatingFilterProxy.html/[`DelegatingFilterProxy`] that allows bridging between the Servlet container's lifecycle and Spring's `ApplicationContext`. +-The Servlet container allows registering ``Filter``s using its own standards, but it is not aware of Spring defined Beans. +-`DelegatingFilterProxy` can be registered via standard Servlet container mechanisms, but delegate all the work to a Spring Bean that implements `Filter`. ++The Servlet container allows registering `Filter` instances by using its own standards, but it is not aware of Spring-defined Beans. ++You can register `DelegatingFilterProxy` through the standard Servlet container mechanisms but delegate all the work to a Spring Bean that implements `Filter`. + +-Here is a picture of how `DelegatingFilterProxy` fits into the <>. ++Here is a picture of how `DelegatingFilterProxy` fits into the <>. + + .DelegatingFilterProxy + [[servlet-delegatingfilterproxy-figure]] + image::{figures}/delegatingfilterproxy.png[] + + `DelegatingFilterProxy` looks up __Bean Filter~0~__ from the `ApplicationContext` and then invokes __Bean Filter~0~__. +-The pseudo code of `DelegatingFilterProxy` can be seen below. ++The following listing shows pseudo code of `DelegatingFilterProxy`: ++ ++// FIXME: Use real code from a real repository rather than pseudo code. + + .`DelegatingFilterProxy` Pseudo Code + ==== +@@ -41,6 +43,6 @@ fun doFilter(request: ServletRequest, response: ServletResponse, chain: FilterCh + ---- + ==== + +-Another benefit of `DelegatingFilterProxy` is that it allows delaying looking `Filter` bean instances. +-This is important because the container needs to register the `Filter` instances before the container can startup. +-However, Spring typically uses a `ContextLoaderListener` to load the Spring Beans which will not be done until after the `Filter` instances need to be registered. ++Another benefit of `DelegatingFilterProxy` is that it allows delaying looking up `Filter` bean instances. ++This is important because the container needs to register the `Filter` instances before the container can start up. ++However, Spring typically uses a `ContextLoaderListener` to load the Spring Beans, which is not done until after the `Filter` instances need to be registered. +diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/architecture/exception-translation-filter.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/architecture/exception-translation-filter.adoc +index 67cad58ddf..f3c97ed7de 100644 +--- a/docs/manual/src/docs/asciidoc/_includes/servlet/architecture/exception-translation-filter.adoc ++++ b/docs/manual/src/docs/asciidoc/_includes/servlet/architecture/exception-translation-filter.adoc +@@ -8,29 +8,29 @@ The {security-api-url}org/springframework/security/web/access/ExceptionTranslati + + `ExceptionTranslationFilter` is inserted into the <> as one of the <>. + +-image::{figures}/exceptiontranslationfilter.png[] ++The following image shows the relationship of `ExceptionTranslationFilter` to other components: + ++image::{figures}/exceptiontranslationfilter.png[] + + * image:{icondir}/number_1.png[] First, the `ExceptionTranslationFilter` invokes `FilterChain.doFilter(request, response)` to invoke the rest of the application. +-* image:{icondir}/number_2.png[] If the user is not authenticated or it is an `AuthenticationException`, then __Start Authentication__. +-** The <> is cleared out ++* image:{icondir}/number_2.png[] If the user is not authenticated or it is an `AuthenticationException`, __Start Authentication__. ++** The <> is cleared out. + ** The `HttpServletRequest` is saved in the {security-api-url}org/springframework/security/web/savedrequest/RequestCache.html[`RequestCache`]. + When the user successfully authenticates, the `RequestCache` is used to replay the original request. + // FIXME: add link to authentication success + ** The `AuthenticationEntryPoint` is used to request credentials from the client. + For example, it might redirect to a log in page or send a `WWW-Authenticate` header. + // FIXME: link to AuthenticationEntryPoint +-* image:{icondir}/number_3.png[] Otherwise if it is an `AccessDeniedException`, then __Access Denied__. ++* image:{icondir}/number_3.png[] Otherwise, if it is an `AccessDeniedException`, then __Access Denied__. + The `AccessDeniedHandler` is invoked to handle access denied. + // FIXME: link to AccessDeniedHandler + +-[NOTE] +-==== +-If the application does not throw an `AccessDeniedException` or an `AuthenticationException`, then `ExceptionTranslationFilter` does not do anything. +-==== ++NOTE: If the application does not throw an `AccessDeniedException` or an `AuthenticationException`, `ExceptionTranslationFilter` does not do anything. + + The pseudocode for `ExceptionTranslationFilter` looks something like this: + ++// FIXME: Use real code from a real repository rather than pseudo code ++ + .ExceptionTranslationFilter pseudocode + [source,java] + ---- +@@ -44,7 +44,7 @@ try { + } + } + ---- +-<1> You will recall from <> that invoking `FilterChain.doFilter(request, response)` is the equivalent of invoking the rest of the application. +-This means that if another part of the application, (i.e. <> or method security) throws an `AuthenticationException` or `AccessDeniedException` it will be caught and handled here. +-<2> If the user is not authenticated or it is an `AuthenticationException`, then __Start Authentication__. ++<1> As described in <>, invoking `FilterChain.doFilter(request, response)` is the equivalent of invoking the rest of the application. ++This means that if another part of the application, (<> or method security) throws an `AuthenticationException` or `AccessDeniedException` it is caught and handled here. ++<2> If the user is not authenticated or it is an `AuthenticationException`, __Start Authentication__. + <3> Otherwise, __Access Denied__ +diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/architecture/filter-chain-proxy.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/architecture/filter-chain-proxy.adoc +index 0b15efeec9..d69cbdb423 100644 +--- a/docs/manual/src/docs/asciidoc/_includes/servlet/architecture/filter-chain-proxy.adoc ++++ b/docs/manual/src/docs/asciidoc/_includes/servlet/architecture/filter-chain-proxy.adoc +@@ -5,6 +5,8 @@ Spring Security's Servlet support is contained within `FilterChainProxy`. + `FilterChainProxy` is a special `Filter` provided by Spring Security that allows delegating to many `Filter` instances through <>. + Since `FilterChainProxy` is a Bean, it is typically wrapped in a <>. + ++The following image shows the role of `FilterChainProxy`. ++ + .FilterChainProxy + [[servlet-filterchainproxy-figure]] + image::{figures}/filterchainproxy.png[] +diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/architecture/filters.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/architecture/filters.adoc +index 4b63aa4deb..54aaee9b4a 100644 +--- a/docs/manual/src/docs/asciidoc/_includes/servlet/architecture/filters.adoc ++++ b/docs/manual/src/docs/asciidoc/_includes/servlet/architecture/filters.adoc +@@ -1,21 +1,21 @@ + [[servlet-filters-review]] +-= A Review of ``Filter``s ++= A Review of Filters + +-Spring Security's Servlet support is based on Servlet ``Filter``s, so it is helpful to look at the role of ``Filter``s generally first. +-The picture below shows the typical layering of the handlers for a single HTTP request. ++Spring Security's Servlet support is based on Servlet Filters, so it is helpful to look at the role of Filters generally first. ++The following image shows the typical layering of the handlers for a single HTTP request. + + .FilterChain + [[servlet-filterchain-figure]] + image::{figures}/filterchain.png[] + +-The client sends a request to the application, and the container creates a `FilterChain` which contains the ``Filter``s and `Servlet` that should process the `HttpServletRequest` based on the path of the request URI. +-In a Spring MVC application the `Servlet` is an instance of https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#mvc-servlet[`DispatcherServlet`]. +-At most one `Servlet` can handle a single `HttpServletRequest` and `HttpServletResponse`. ++The client sends a request to the application, and the container creates a `FilterChain`, which contains the `Filter` instances and `Servlet` that should process the `HttpServletRequest`, based on the path of the request URI. ++In a Spring MVC application, the `Servlet` is an instance of https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#mvc-servlet[`DispatcherServlet`]. ++At most, one `Servlet` can handle a single `HttpServletRequest` and `HttpServletResponse`. + However, more than one `Filter` can be used to: + +-* Prevent downstream ``Filter``s or the `Servlet` from being invoked. +-In this instance the `Filter` will typically write the `HttpServletResponse`. +-* Modify the `HttpServletRequest` or `HttpServletResponse` used by the downstream ``Filter``s and `Servlet` ++* Prevent downstream `Filter` instances or the `Servlet` from being invoked. ++In this case, the `Filter` typically writes the `HttpServletResponse`. ++* Modify the `HttpServletRequest` or `HttpServletResponse` used by the downstream `Filter` instances and the `Servlet`. + + The power of the `Filter` comes from the `FilterChain` that is passed into it. + +@@ -42,4 +42,4 @@ fun doFilter(request: ServletRequest, response: ServletResponse, chain: FilterCh + ---- + ==== + +-Since a `Filter` only impacts downstream ``Filter``s and the `Servlet`, the order each `Filter` is invoked is extremely important. ++Since a `Filter` impacts only downstream `Filter` instances and the `Servlet`, the order in which each `Filter` is invoked is extremely important. +diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/architecture/index.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/architecture/index.adoc +index 38b639f9b2..610c495376 100644 +--- a/docs/manual/src/docs/asciidoc/_includes/servlet/architecture/index.adoc ++++ b/docs/manual/src/docs/asciidoc/_includes/servlet/architecture/index.adoc +@@ -2,8 +2,8 @@ + = Servlet Security: The Big Picture + :figures: images/servlet/architecture + +-This section discusses Spring Security's high level architecture within Servlet based applications. +-We build on this high level understanding within <>, <>, <> sections of the reference. ++This section discusses Spring Security's high-level architecture within Servlet based applications. ++We build on this high-level understanding within the <>, <>, and <> sections of the reference. + // FIXME: Add links to other sections of architecture + + include::filters.adoc[leveloffset=+1] +diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/architecture/security-filter-chain.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/architecture/security-filter-chain.adoc +index 508e9e3d21..a970902c1a 100644 +--- a/docs/manual/src/docs/asciidoc/_includes/servlet/architecture/security-filter-chain.adoc ++++ b/docs/manual/src/docs/asciidoc/_includes/servlet/architecture/security-filter-chain.adoc +@@ -1,7 +1,9 @@ + [[servlet-securityfilterchain]] + = SecurityFilterChain + +-{security-api-url}org/springframework/security/web/SecurityFilterChain.html[`SecurityFilterChain`] is used by <> to determine which Spring Security ``Filter``s should be invoked for this request. ++{security-api-url}org/springframework/security/web/SecurityFilterChain.html[`SecurityFilterChain`] is used by <> to determine which Spring Security `Filter` instances should be invoked for the current request. ++ ++The following image shows the role of `SecurityFilterChain`. + + .SecurityFilterChain + [[servlet-securityfilterchain-figure]] +@@ -10,34 +12,36 @@ image::{figures}/securityfilterchain.png[] + The <> in `SecurityFilterChain` are typically Beans, but they are registered with `FilterChainProxy` instead of <>. + `FilterChainProxy` provides a number of advantages to registering directly with the Servlet container or <>. + First, it provides a starting point for all of Spring Security's Servlet support. +-For that reason, if you are attempting to troubleshoot Spring Security's Servlet support, adding a debug point in `FilterChainProxy` is a great place to start. ++For that reason, if you try to troubleshoot Spring Security's Servlet support, adding a debug point in `FilterChainProxy` is a great place to start. + +-Second, since `FilterChainProxy` is central to Spring Security usage it can perform tasks that are not viewed as optional. ++Second, since `FilterChainProxy` is central to Spring Security usage, it can perform tasks that are not viewed as optional. + // FIXME: Add a link to SecurityContext + For example, it clears out the `SecurityContext` to avoid memory leaks. + It also applies Spring Security's <> to protect applications against certain types of attacks. + + In addition, it provides more flexibility in determining when a `SecurityFilterChain` should be invoked. +-In a Servlet container, ``Filter``s are invoked based upon the URL alone. ++In a Servlet container, `Filter` instances are invoked based upon the URL alone. + // FIXME: Link to RequestMatcher +-However, `FilterChainProxy` can determine invocation based upon anything in the `HttpServletRequest` by leveraging the `RequestMatcher` interface. ++However, `FilterChainProxy` can determine invocation based upon anything in the `HttpServletRequest` by using the `RequestMatcher` interface. ++ ++In fact, you can use `FilterChainProxy` to determine which `SecurityFilterChain` should be used. ++This lets you provide a totally separate configuration for different _slices_ of your application. + +-In fact, `FilterChainProxy` can be used to determine which `SecurityFilterChain` should be used. +-This allows providing a totally separate configuration for different _slices_ of your application. ++The following image shows multiple `SecurityFilterChain` instances: + + .Multiple SecurityFilterChain + [[servlet-multi-securityfilterchain-figure]] + image::{figures}/multi-securityfilterchain.png[] + +-In the <> Figure `FilterChainProxy` decides which `SecurityFilterChain` should be used. +-Only the first `SecurityFilterChain` that matches will be invoked. +-If a URL of `/api/messages/` is requested, it will first match on ``SecurityFilterChain~0~``'s pattern of `+/api/**+`, so only `SecurityFilterChain~0~` will be invoked even though it also matches on ``SecurityFilterChain~n~``. +-If a URL of `/messages/` is requested, it will not match on ``SecurityFilterChain~0~``'s pattern of `+/api/**+`, so `FilterChainProxy` will continue trying each `SecurityFilterChain`. +-Assuming that no other, `SecurityFilterChain` instances match `SecurityFilterChain~n~` will be invoked. +-// FIXME add link to pattern matching +- +-Notice that `SecurityFilterChain~0~` has only three security ``Filter``s instances configured. +-However, `SecurityFilterChain~n~` has four security ``Filter``s configured. +-It is important to note that each `SecurityFilterChain` can be unique and configured in isolation. +-In fact, a `SecurityFilterChain` might have zero security ``Filter``s if the application wants Spring Security to ignore certain requests. ++In the <> figure, `FilterChainProxy` decides which `SecurityFilterChain` should be used. ++Only the first `SecurityFilterChain` that matches is invoked. ++If a URL of `/api/messages/` is requested, it first matches on the `SecurityFilterChain~0~` pattern of `+/api/**+`, so only `SecurityFilterChain~0~` is invoked, even though it also matches on ``SecurityFilterChain~n~``. ++If a URL of `/messages/` is requested, it does not match on the `SecurityFilterChain~0~` pattern of `+/api/**+`, so `FilterChainProxy` continues trying each `SecurityFilterChain`. ++Assuming that no other `SecurityFilterChain` instances match, `SecurityFilterChain~n~` is invoked. ++// FIXME: add link to pattern matching ++ ++Notice that `SecurityFilterChain~0~` has only three security `Filter` instances configured. ++However, `SecurityFilterChain~n~` has four security `Filter` instanes configured. ++It is important to note that each `SecurityFilterChain` can be unique and can be configured in isolation. ++In fact, a `SecurityFilterChain` might have zero security `Filter` instances if the application wants Spring Security to ignore certain requests. + // FIXME: add link to configuring multiple `SecurityFilterChain` instances +diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/architecture/security-filters.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/architecture/security-filters.adoc +index 408ec40637..9bc818d42f 100644 +--- a/docs/manual/src/docs/asciidoc/_includes/servlet/architecture/security-filters.adoc ++++ b/docs/manual/src/docs/asciidoc/_includes/servlet/architecture/security-filters.adoc +@@ -2,41 +2,41 @@ + = Security Filters + + The Security Filters are inserted into the <> with the <> API. +-The <>s matters. +-It is typically not necessary to know the ordering of Spring Security's ``Filter``s. +-However, there are times that it is beneficial to know the ordering ++The <> instances matters. ++It is typically not necessary to know the ordering of Spring Security's `Filter` instances. ++However, there are times that it is beneficial to know the ordering. + +-Below is a comprehensive list of Spring Security Filter ordering: ++The following is a comprehensive list of Spring Security Filter ordering: + +-* ChannelProcessingFilter +-* WebAsyncManagerIntegrationFilter +-* SecurityContextPersistenceFilter +-* HeaderWriterFilter +-* CorsFilter +-* CsrfFilter +-* LogoutFilter +-* OAuth2AuthorizationRequestRedirectFilter +-* Saml2WebSsoAuthenticationRequestFilter +-* X509AuthenticationFilter +-* AbstractPreAuthenticatedProcessingFilter +-* CasAuthenticationFilter +-* OAuth2LoginAuthenticationFilter +-* Saml2WebSsoAuthenticationFilter ++* `ChannelProcessingFilter` ++* `WebAsyncManagerIntegrationFilter` ++* `SecurityContextPersistenceFilter` ++* `HeaderWriterFilter` ++* `CorsFilter` ++* `CsrfFilter` ++* `LogoutFilter` ++* `OAuth2AuthorizationRequestRedirectFilter` ++* `Saml2WebSsoAuthenticationRequestFilter` ++* `X509AuthenticationFilter` ++* `AbstractPreAuthenticatedProcessingFilter` ++* `CasAuthenticationFilter` ++* `OAuth2LoginAuthenticationFilter` ++* `Saml2WebSsoAuthenticationFilter` + * <> +-* OpenIDAuthenticationFilter +-* DefaultLoginPageGeneratingFilter +-* DefaultLogoutPageGeneratingFilter +-* ConcurrentSessionFilter ++* `OpenIDAuthenticationFilter` ++* `DefaultLoginPageGeneratingFilter` ++* `DefaultLogoutPageGeneratingFilter` ++* `ConcurrentSessionFilter` + * <> +-* BearerTokenAuthenticationFilter ++* `BearerTokenAuthenticationFilter` + * <> +-* RequestCacheAwareFilter +-* SecurityContextHolderAwareRequestFilter +-* JaasApiIntegrationFilter +-* RememberMeAuthenticationFilter +-* AnonymousAuthenticationFilter +-* OAuth2AuthorizationCodeGrantFilter +-* SessionManagementFilter ++* `RequestCacheAwareFilter` ++* `SecurityContextHolderAwareRequestFilter` ++* `JaasApiIntegrationFilter` ++* `RememberMeAuthenticationFilter` ++* `AnonymousAuthenticationFilter` ++* `OAuth2AuthorizationCodeGrantFilter` ++* `SessionManagementFilter` + * <> + * <> +-* SwitchUserFilter ++* `SwitchUserFilter` +diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/anonymous.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/anonymous.adoc +index 9f2508f7aa..16306a3402 100644 +--- a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/anonymous.adoc ++++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/anonymous.adoc +@@ -1,38 +1,35 @@ + [[anonymous]] + == Anonymous Authentication + +- + [[anonymous-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. ++It is generally considered good security practice to adopt a "`deny-by-default`" stance, 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). +-In this case it is easiest to define access configuration attributes for these specific URLs rather than have for every secured resource. +-Put differently, sometimes it is nice to say `ROLE_SOMETHING` is required by default and only allow certain exceptions to this rule, such as for login, logout and home pages of an application. ++In that case, it is easiest to define access configuration attributes for these specific URLs rather than for every secured resource. ++Put differently, sometimes it is nice to say `ROLE_SOMETHING` is required by default and allow only certain exceptions to this rule, such as for login, logout, and home pages of an application. + You could also omit these pages from the filter chain entirely, thus bypassing the access control checks, but this may be undesirable for other reasons, particularly if the pages behave differently for authenticated users. + + This is what we mean by anonymous authentication. +-Note that there is no real conceptual difference between a user who is "anonymously authenticated" and an unauthenticated user. ++Note that there is no real conceptual difference between a user who is "`anonymously authenticated`" and an unauthenticated user. + Spring Security's anonymous authentication just gives you a more convenient way to configure your access-control attributes. +-Calls to servlet API calls such as `getCallerPrincipal`, for example, will still return null even though there is actually an anonymous authentication object in the `SecurityContextHolder`. ++Calls to servlet API calls, such as `getCallerPrincipal`, still return null, even though there is actually an anonymous authentication object in the `SecurityContextHolder`. + + There are other situations where anonymous authentication is useful, such as when an auditing interceptor queries the `SecurityContextHolder` to identify which principal was responsible for a given operation. +-Classes can be authored more robustly if they know the `SecurityContextHolder` always contains an `Authentication` object, and never `null`. +- ++Classes can be authored more robustly if they know the `SecurityContextHolder` always contains an `Authentication` object and never contains `null`. + + [[anonymous-config]] + === Configuration +-Anonymous authentication support is provided automatically when using the HTTP configuration Spring Security 3.0 and can be customized (or disabled) using the `` element. +-You don't need to configure the beans described here unless you are using traditional bean configuration. +- +-Three classes that together provide the anonymous authentication feature. +-`AnonymousAuthenticationToken` is an implementation of `Authentication`, and stores the `GrantedAuthority` s which apply to the anonymous principal. +-There is a corresponding `AnonymousAuthenticationProvider`, which is chained into the `ProviderManager` so that `AnonymousAuthenticationToken` s are accepted. +-Finally, there is an `AnonymousAuthenticationFilter`, which is chained after the normal authentication mechanisms and automatically adds an `AnonymousAuthenticationToken` to the `SecurityContextHolder` if there is no existing `Authentication` held there. +-The definition of the filter and authentication provider appears as follows: +- ++Anonymous authentication support is provided automatically when you use the HTTP configuration (introduced inSpring Security 3.0). ++You can customize (or disable) it by using the `` element. ++You need not configure the beans described here unless you are using traditional bean configuration. + ++Three classes work together to provide the anonymous authentication feature. ++`AnonymousAuthenticationToken` is an implementation of `Authentication` and stores the `GrantedAuthority` instancesthat apply to the anonymous principal. ++There is a corresponding `AnonymousAuthenticationProvider`, which is chained into the `ProviderManager` so that `AnonymousAuthenticationToken` instances are accepted. ++Finally, an `AnonymousAuthenticationFilter` is chained after the normal authentication mechanisms and automatically adds an `AnonymousAuthenticationToken` to the `SecurityContextHolder` if there is no existing `Authentication` held there. ++The filter and authentication provider is defined as follows: + ++==== + [source,xml] + ---- + +@@ -47,27 +44,24 @@ The definition of the filter and authentication provider appears as follows: + + + ---- ++==== + ++The `key` is shared between the filter and authentication provider so that tokens created by the former are accepted by the latter + +- +-The `key` is shared between the filter and authentication provider, so that tokens created by the former are accepted by the latter footnote:[ +-The use of the `key` property should not be regarded as providing any real security here. ++NOTE: The use of the `key` property should not be regarded as providing any real security here. + It is merely a book-keeping exercise. +-If you are sharing a `ProviderManager` which contains an `AnonymousAuthenticationProvider` in a scenario where it is possible for an authenticating client to construct the `Authentication` object (such as with RMI invocations), then a malicious client could submit an `AnonymousAuthenticationToken` which it had created itself (with chosen username and authority list). +-If the `key` is guessable or can be found out, then the token would be accepted by the anonymous provider. +-This isn't a problem with normal usage but if you are using RMI you would be best to use a customized `ProviderManager` which omits the anonymous provider rather than sharing the one you use for your HTTP authentication mechanisms. +-]. +-The `userAttribute` is expressed in the form of `usernameInTheAuthenticationToken,grantedAuthority[,grantedAuthority]`. +-This is the same syntax as used after the equals sign for the `userMap` property of `InMemoryDaoImpl`. +- +-As explained earlier, the benefit of anonymous authentication is that all URI patterns can have security applied to them. +-For example: ++If you share a `ProviderManager` that contains an `AnonymousAuthenticationProvider` in a scenario where it is possible for an authenticating client to construct the `Authentication` object (such as with RMI invocations), then a malicious client could submit an `AnonymousAuthenticationToken` that it had created itself (with the chosen username and authority list). ++If the `key` is guessable or can be found out, the token would be accepted by the anonymous provider. ++This is not a problem with normal usage. However, if you use RMI, you should use a customized `ProviderManager` that omits the anonymous provider rather than sharing the one you use for your HTTP authentication mechanisms. + ++The `userAttribute` is expressed in the form of `usernameInTheAuthenticationToken,grantedAuthority[,grantedAuthority]`. ++The same syntax is used after the equals sign for the `userMap` property of `InMemoryDaoImpl`. + ++As explained earlier, the benefit of anonymous authentication is that all URI patterns can have security applied to them, as the following example shows: + ++==== + [source,xml] + ---- +- + + +@@ -83,20 +77,18 @@ For example: + + + ---- +- +- +- ++==== + + [[anonymous-auth-trust-resolver]] + === 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. +-If an `AccessDeniedException` is thrown, and the authentication is of an anonymous type, instead of throwing a 403 (forbidden) response, the filter will instead commence the `AuthenticationEntryPoint` so the principal can authenticate properly. +-This is a necessary distinction, otherwise principals would always be deemed "authenticated" and never be given an opportunity to login via form, basic, digest or some other normal authentication mechanism. ++The `ExceptionTranslationFilter` uses this interface in processing `AccessDeniedException` instances. ++If an `AccessDeniedException` is thrown and the authentication is of an anonymous type, instead of throwing a 403 (forbidden) response, the filter, instead, commences the `AuthenticationEntryPoint` so that the principal can authenticate properly. ++This is a necessary distinction. Otherwise, principals would always be deemed "`authenticated`" and never be given an opportunity to login through form, basic, digest, or some other normal authentication mechanism. + +-You will often see the `ROLE_ANONYMOUS` attribute in the above interceptor configuration replaced with `IS_AUTHENTICATED_ANONYMOUSLY`, which is effectively the same thing when defining access controls. +-This is an example of the use of the `AuthenticatedVoter` which we will see in the <>. ++We often see the `ROLE_ANONYMOUS` attribute in the earlier interceptor configuration replaced with `IS_AUTHENTICATED_ANONYMOUSLY`, which is effectively the same thing when defining access controls. ++This is an example of the use of the `AuthenticatedVoter`, which we cover in the <>. + It uses an `AuthenticationTrustResolver` to process this particular configuration attribute and grant access to anonymous users. +-The `AuthenticatedVoter` approach is more powerful, since it allows you to differentiate between anonymous, remember-me and fully-authenticated users. +-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`. ++The `AuthenticatedVoter` approach is more powerful, since it lets you differentiate between anonymous, remember-me, and fully authenticated users. ++If you do not need this functionality, though, you can stick with `ROLE_ANONYMOUS`, which is processed by Spring Security's standard `RoleVoter`. +diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/architecture/abstract-authentication-processing-filter.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/architecture/abstract-authentication-processing-filter.adoc +index a3a8a48d18..c0801ee192 100644 +--- a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/architecture/abstract-authentication-processing-filter.adoc ++++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/architecture/abstract-authentication-processing-filter.adoc +@@ -4,7 +4,7 @@ + :icondir: images/icons + + {security-api-url}org/springframework/security/web/authentication/AbstractAuthenticationProcessingFilter.html[`AbstractAuthenticationProcessingFilter`] is used as a base `Filter` for authenticating a user's credentials. +-Before the credentials can be authenticated, Spring Security typically requests the credentials using <>. ++Before the credentials can be authenticated, Spring Security typically requests the credentials by using <>. + + Next, the `AbstractAuthenticationProcessingFilter` can authenticate any authentication requests that are submitted to it. + +@@ -16,26 +16,26 @@ For example, <> is passed into the <> to be authenticated. + +-image:{icondir}/number_3.png[] If authentication fails, then __Failure__ ++image:{icondir}/number_3.png[] If authentication fails, then __Failure__. + + * The <> is cleared out. + * `RememberMeServices.loginFail` is invoked. + If remember me is not configured, this is a no-op. +-// FIXME: link to rememberme ++See the {security-api-url}org/springframework/security/web/authentication/rememberme/package-frame.html[`rememberme`] package. + * `AuthenticationFailureHandler` is invoked. +-// FIXME: link to AuthenticationFailureHandler ++See the {security-api-url}org/springframework/security/web/authentication/AuthenticationFailureHandler.html[`AuthenticationFailureHandler`] interface. + + image:{icondir}/number_4.png[] If authentication is successful, then __Success__. + +-* `SessionAuthenticationStrategy` is notified of a new log in. +-// FIXME: Add link to SessionAuthenticationStrategy ++* `SessionAuthenticationStrategy` is notified of a new login. ++See the {security-api-url}org/springframework/security/web/authentication/session/SessionAuthenticationStrategy.html[`SessionAuthenticationStrategy`] interface. + * The <> is set on the <>. +-Later the `SecurityContextPersistenceFilter` saves the `SecurityContext` to the `HttpSession`. +-// FIXME: link securitycontextpersistencefilter ++Later, the `SecurityContextPersistenceFilter` saves the `SecurityContext` to the `HttpSession`. ++See the {security-api-url}org/springframework/security/web/context/SecurityContextPersistenceFilter.html[`SecurityContextPersistenceFilter`] class. + * `RememberMeServices.loginSuccess` is invoked. + If remember me is not configured, this is a no-op. +-// FIXME: link to rememberme ++See the {security-api-url}org/springframework/security/web/authentication/rememberme/package-frame.html[`rememberme`] package. + * `ApplicationEventPublisher` publishes an `InteractiveAuthenticationSuccessEvent`. + * `AuthenticationSuccessHandler` is invoked. + // FIXME: link to AuthenticationSuccessHandler +- ++See the {security-api-url}org/springframework/security/web/authentication/AuthenticationSuccessHandler.html[`AuthenticationSuccessHandler`] interface. +diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/architecture/authentication-entry-point.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/architecture/authentication-entry-point.adoc +index cdc00dddbc..0218b752bc 100644 +--- a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/architecture/authentication-entry-point.adoc ++++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/architecture/authentication-entry-point.adoc +@@ -4,11 +4,9 @@ + + {security-api-url}org/springframework/security/web/AuthenticationEntryPoint.html[`AuthenticationEntryPoint`] is used to send an HTTP response that requests credentials from a client. + +-Sometimes a client will proactively include credentials such as a username/password to request a resource. +-In these cases, Spring Security does not need to provide an HTTP response that requests credentials from the client since they are already included. ++Sometimes, a client proactively includes credentials (such as a username and password) to request a resource. ++In these cases, Spring Security does not need to provide an HTTP response that requests credentials from the client, since they are already included. + +-In other cases, a client will make an unauthenticated request to a resource that they are not authorized to access. ++In other cases, a client makes an unauthenticated request to a resource that they are not authorized to access. + In this case, an implementation of `AuthenticationEntryPoint` is used to request credentials from the client. +-The `AuthenticationEntryPoint` implementation might perform a <>, respond with an <> header, etc. +- +- ++The `AuthenticationEntryPoint` implementation might perform a <>, respond with an <> header, or take other action. +diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/architecture/authentication-manager.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/architecture/authentication-manager.adoc +index 5c85382b71..5993364378 100644 +--- a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/architecture/authentication-manager.adoc ++++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/architecture/authentication-manager.adoc +@@ -2,8 +2,8 @@ + = AuthenticationManager + + {security-api-url}org/springframework/security/authentication/AuthenticationManager.html[`AuthenticationManager`] is the API that defines how Spring Security's Filters perform <>. +-The <> that is returned is then set on the <> by the controller (i.e. <>) that invoked the `AuthenticationManager`. +-If you are not integrating with __Spring Security's ``Filters``s__ you can set the `SecurityContextHolder` directly and are not required to use an `AuthenticationManager`. ++The <> that is returned is then set on the <> by the controller (that is, by <>) that invoked the `AuthenticationManager`. ++If you are not integrating with Spring Security's `Filters` instances, you can set the `SecurityContextHolder` directly and are not required to use an `AuthenticationManager`. + + While the implementation of `AuthenticationManager` could be anything, the most common implementation is <>. + // FIXME: add configuration +diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/architecture/authentication-provider.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/architecture/authentication-provider.adoc +index c7cb0b7b6c..3932504e34 100644 +--- a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/architecture/authentication-provider.adoc ++++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/architecture/authentication-provider.adoc +@@ -1,6 +1,6 @@ + [[servlet-authentication-authenticationprovider]] + = AuthenticationProvider + +-Multiple {security-api-url}org/springframework/security/authentication/AuthenticationProvider.html[``AuthenticationProvider``s] can be injected into <>. ++You can inject multiple {security-api-url}org/springframework/security/authentication/AuthenticationProvider.html[`AuthenticationProvider`] instances into <>. + Each `AuthenticationProvider` performs a specific type of authentication. +-For example, <> supports username/password based authentication while `JwtAuthenticationProvider` supports authenticating a JWT token. ++For example, <> supports username/password-based authentication, while `JwtAuthenticationProvider` supports authenticating a JWT token. +diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/architecture/authentication.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/architecture/authentication.adoc +index 2e7319c4ae..170d180f06 100644 +--- a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/architecture/authentication.adoc ++++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/architecture/authentication.adoc +@@ -1,18 +1,18 @@ + [[servlet-authentication-authentication]] + = Authentication + +-The {security-api-url}org/springframework/security/core/Authentication.html[`Authentication`] serves two main purposes within Spring Security: ++The {security-api-url}org/springframework/security/core/Authentication.html[`Authentication`] interface serves two main purposes within Spring Security: + + * An input to <> to provide the credentials a user has provided to authenticate. + When used in this scenario, `isAuthenticated()` returns `false`. +-* Represents the currently authenticated user. +-The current `Authentication` can be obtained from the <>. ++* Represent the currently authenticated user. ++You can obtain the current `Authentication` from the <>. + + The `Authentication` contains: + +-* `principal` - identifies the user. ++* `principal`: Identifies the user. + When authenticating with a username/password this is often an instance of <>. +-* `credentials` - Often a password. +-In many cases this will be cleared after the user is authenticated to ensure it is not leaked. +-* `authorities` - the <> are high level permissions the user is granted. +-A few examples are roles or scopes. ++* `credentials`: Often a password. ++In many cases, this is cleared after the user is authenticated, to ensure that it is not leaked. ++* `authorities`: The <> instances are high-level permissions the user is granted. ++Two examples are roles and scopes. +diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/architecture/granted-authority.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/architecture/granted-authority.adoc +index 19b45cd049..98afa85f11 100644 +--- a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/architecture/granted-authority.adoc ++++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/architecture/granted-authority.adoc +@@ -1,16 +1,16 @@ + [[servlet-authentication-granted-authority]] + = GrantedAuthority +-{security-api-url}org/springframework/security/core/GrantedAuthority.html[``GrantedAuthority``s] are high level permissions the user is granted. A few examples are roles or scopes. ++{security-api-url}org/springframework/security/core/GrantedAuthority.html[`GrantedAuthority`] instances are high-level permissions that the user is granted. Two examples are roles and scopes. + +-``GrantedAuthority``s can be obtained from the <> method. ++You can obtain `GrantedAuthority` instances from the <> method. + This method provides a `Collection` of `GrantedAuthority` objects. + A `GrantedAuthority` is, not surprisingly, an authority that is granted to the principal. +-Such authorities are usually "roles", such as `ROLE_ADMINISTRATOR` or `ROLE_HR_SUPERVISOR`. +-These roles are later on configured for web authorization, method authorization and domain object authorization. +-Other parts of Spring Security are capable of interpreting these authorities, and expect them to be present. +-When using username/password based authentication ``GrantedAuthority``s are usually loaded by the <>. ++Such authorities are usually "`roles`", such as `ROLE_ADMINISTRATOR` or `ROLE_HR_SUPERVISOR`. ++These roles are later configured for web authorization, method authorization, and domain object authorization. ++Other parts of Spring Security interpret these authorities and expect them to be present. ++When using username/password based authentication `GrantedAuthority` instances are usually loaded by the <>. + +-Usually the `GrantedAuthority` objects are application-wide permissions. ++Usually, the `GrantedAuthority` objects are application-wide permissions. + They are not specific to a given domain object. +-Thus, you wouldn't likely have a `GrantedAuthority` to represent a permission to `Employee` object number 54, because if there are thousands of such authorities you would quickly run out of memory (or, at the very least, cause the application to take a long time to authenticate a user). +-Of course, Spring Security is expressly designed to handle this common requirement, but you'd instead use the project's domain object security capabilities for this purpose. ++Thus, you would not likely have a `GrantedAuthority` to represent a permission to `Employee` object number 54, because if there are thousands of such authorities you would quickly run out of memory (or, at the very least, cause the application to take a long time to authenticate a user). ++Of course, Spring Security is expressly designed to handle this common requirement, but you should instead use the project's domain object security capabilities for this purpose. +diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/architecture/provider-manager.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/architecture/provider-manager.adoc +index 4ed8cb4615..5dc80d7f60 100644 +--- a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/architecture/provider-manager.adoc ++++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/architecture/provider-manager.adoc +@@ -3,18 +3,18 @@ + :figures: images/servlet/authentication/architecture + + {security-api-url}org/springframework/security/authentication/ProviderManager.html[`ProviderManager`] is the most commonly used implementation of <>. +-`ProviderManager` delegates to a `List` of <>. +-// FIXME: link to AuthenticationProvider ++`ProviderManager` delegates to a `List` of <> instances. ++(See the Javadoc for the {security-api-url}org/springframework/security/authentication/AuthenticationProvider.html[`AuthenticationProvider`]. + Each `AuthenticationProvider` has an opportunity to indicate that authentication should be successful, fail, or indicate it cannot make a decision and allow a downstream `AuthenticationProvider` to decide. +-If none of the configured ``AuthenticationProvider``s can authenticate, then authentication will fail with a `ProviderNotFoundException` which is a special `AuthenticationException` that indicates the `ProviderManager` was not configured to support the type of `Authentication` that was passed into it. ++If none of the configured `AuthenticationProvider` instances can authenticate, authentication fails with a `ProviderNotFoundException`, which is a special `AuthenticationException` that indicates that the `ProviderManager` was not configured to support the type of `Authentication` that was passed into it. + + image::{figures}/providermanager.png[] + + In practice each `AuthenticationProvider` knows how to perform a specific type of authentication. +- For example, one `AuthenticationProvider` might be able to validate a username/password, while another might be able to authenticate a SAML assertion. +-This allows each `AuthenticationProvider` to do a very specific type of authentication, while supporting multiple types of authentication and only exposing a single `AuthenticationManager` bean. ++For example, one `AuthenticationProvider` might be able to validate a username/password, while another might be able to authenticate a SAML assertion. ++This lets each `AuthenticationProvider` do a very specific type of authentication while supporting multiple types of authentication and expose only a single `AuthenticationManager` bean. + +-`ProviderManager` also allows configuring an optional parent `AuthenticationManager` which is consulted in the event that no `AuthenticationProvider` can perform authentication. ++`ProviderManager` also allows configuring an optional parent `AuthenticationManager`, which is consulted in the event that no `AuthenticationProvider` can perform authentication. + The parent can be any type of `AuthenticationManager`, but it is often an instance of `ProviderManager`. + + image::{figures}/providermanager-parent.png[] +@@ -25,12 +25,12 @@ This is somewhat common in scenarios where there are multiple <>. + Spring Security does not care how the `SecurityContextHolder` is populated. +-If it contains a value, then it is used as the currently authenticated user. ++If it contains a value, it is used as the currently authenticated user. + +-The simplest way to indicate a user is authenticated is to set the `SecurityContextHolder` directly. ++The simplest way to indicate a user is authenticated is to set the `SecurityContextHolder` directly: + + .Setting `SecurityContextHolder` + ==== +@@ -36,18 +36,18 @@ context.authentication = authentication + + SecurityContextHolder.setContext(context) // <3> + ---- +-==== + + <1> We start by creating an empty `SecurityContext`. +-It is important to create a new `SecurityContext` instance instead of using `SecurityContextHolder.getContext().setAuthentication(authentication)` to avoid race conditions across multiple threads. +-<2> Next we create a new <> object. ++You should create a new `SecurityContext` instance instead of using `SecurityContextHolder.getContext().setAuthentication(authentication)` to avoid race conditions across multiple threads. ++<2> Next, we create a new <> object. + Spring Security does not care what type of `Authentication` implementation is set on the `SecurityContext`. +-Here we use `TestingAuthenticationToken` because it is very simple. ++Here, we use `TestingAuthenticationToken`, because it is very simple. + A more common production scenario is `UsernamePasswordAuthenticationToken(userDetails, password, authorities)`. + <3> Finally, we set the `SecurityContext` on the `SecurityContextHolder`. +-Spring Security will use this information for <>. ++Spring Security uses this information for <>. ++==== + +-If you wish to obtain information about the authenticated principal, you can do so by accessing the `SecurityContextHolder`. ++To obtain information about the authenticated principal, access the `SecurityContextHolder`. + + .Access Currently Authenticated User + ==== +@@ -72,18 +72,18 @@ val authorities = authentication.authorities + ---- + ==== + +-// FIXME: add links to HttpServletRequest.getRemoteUser() and @CurrentSecurityContext @AuthenticationPrincipal ++// FIXME: Add links to and relevant description of HttpServletRequest.getRemoteUser() and @CurrentSecurityContext @AuthenticationPrincipal + +-By default the `SecurityContextHolder` uses a `ThreadLocal` to store these details, which means that the `SecurityContext` is always available to methods in the same thread, even if the `SecurityContext` is not explicitly passed around as an argument to those methods. +-Using a `ThreadLocal` in this way is quite safe if care is taken to clear the thread after the present principal's request is processed. ++By default, `SecurityContextHolder` uses a `ThreadLocal` to store these details, which means that the `SecurityContext` is always available to methods in the same thread, even if the `SecurityContext` is not explicitly passed around as an argument to those methods. ++Using a `ThreadLocal` in this way is quite safe if you take care to clear the thread after the present principal's request is processed. + Spring Security's <> ensures that the `SecurityContext` is always cleared. + +-Some applications aren't entirely suitable for using a `ThreadLocal`, because of the specific way they work with threads. ++Some applications are not entirely suitable for using a `ThreadLocal`, because of the specific way they work with threads. + For example, a Swing client might want all threads in a Java Virtual Machine to use the same security context. +-`SecurityContextHolder` can be configured with a strategy on startup to specify how you would like the context to be stored. +-For a standalone application you would use the `SecurityContextHolder.MODE_GLOBAL` strategy. ++You can configure `SecurityContextHolder` with a strategy on startup to specify how you would like the context to be stored. ++For a standalone application, you would use the `SecurityContextHolder.MODE_GLOBAL` strategy. + Other applications might want to have threads spawned by the secure thread also assume the same security identity. +-This is achieved by using `SecurityContextHolder.MODE_INHERITABLETHREADLOCAL`. ++You can achieve this by using `SecurityContextHolder.MODE_INHERITABLETHREADLOCAL`. + You can change the mode from the default `SecurityContextHolder.MODE_THREADLOCAL` in two ways. +-The first is to set a system property, the second is to call a static method on `SecurityContextHolder`. +-Most applications won't need to change from the default, but if you do, take a look at the JavaDoc for `SecurityContextHolder` to learn more. ++The first is to set a system property. The second is to call a static method on `SecurityContextHolder`. ++Most applications need not change from the default. However, if you do, take a look at the JavaDoc for `SecurityContextHolder` to learn more. +diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/cas.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/cas.adoc +index 31436ad1f2..310044eca6 100644 +--- a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/cas.adoc ++++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/cas.adoc +@@ -2,106 +2,108 @@ + == CAS Authentication + + [[cas-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. ++Unlike other initiatives, JA-SIG's Central Authentication Service is open source, widely used, simple to understand, and platform-independent. It also supports proxy capabilities. ++Spring Security fully supports CAS and provides an easy migration path from single-application deployments of Spring Security to multiple-application deployments secured by an enterprise-wide CAS server. + + 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. ++You also need to visit this site to download the CAS Server files. + + [[cas-how-it-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. ++While 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 (and later) supports CAS 3 (and later). ++At the time of writing, the CAS server is at version 6.3.3. + +-Somewhere in your enterprise you will need to setup a CAS server. +-The CAS server is simply a standard WAR file, so there isn't anything difficult about setting up your server. +-Inside the WAR file you will customise the login and other single sign on pages displayed to users. ++NOTE: This section was written about CAS version 3.4, but the material is still current. + +-When deploying a CAS 3.4 server, you will also need to specify an `AuthenticationHandler` in the `deployerConfigContext.xml` included with CAS. +-The `AuthenticationHandler` has a simple method that returns a boolean as to whether a given set of Credentials is valid. +-Your `AuthenticationHandler` implementation will need to link into some type of backend authentication repository, such as an LDAP server or database. +-CAS itself includes numerous `AuthenticationHandler` s out of the box to assist with this. +-When you download and deploy the server war file, it is set up to successfully authenticate users who enter a password matching their username, which is useful for testing. ++Somewhere in your enterprise, you need to setup a CAS server. ++The CAS server runs from a standard WAR file. ++Inside the WAR file, you need to customize the login and other single-sign-on pages displayed to users. + +-Apart from the CAS server itself, the other key players are of course the secure web applications deployed throughout your enterprise. +-These web applications are known as "services". +-There are three types of services. +-Those that authenticate service tickets, those that can obtain proxy tickets, and those that authenticate proxy tickets. +-Authenticating a proxy ticket differs because the list of proxies must be validated and often times a proxy ticket can be reused. ++When deploying a CAS 3.4 server, you also need to specify an `AuthenticationHandler` in the `deployerConfigContext.xml` included with CAS. ++The `AuthenticationHandler` has a simple method that returns a boolean as to whether a given set of credentials is valid. ++Your `AuthenticationHandler` implementation needs to link into some type of backend authentication repository, such as an LDAP server or database. ++CAS itself includes numerous `AuthenticationHandler` implementations to assist with this. ++When you download and deploy the server war file, it is set up to successfully authenticate users who enter a password that matches their username, which is useful for testing. + ++Apart from the CAS server itself, the other key players are the secure web applications deployed throughout your enterprise. ++These web applications are known as "`services`". ++There are three types of services: ++ ++* Services that authenticate service tickets ++* Services that can obtain proxy tickets ++* Services that authenticate proxy tickets. ++ ++Authenticating a proxy ticket differs because the list of proxies must be validated and because, oftentimes, a proxy ticket can be reused. + + [[cas-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 basic interaction between a web browser, a CAS server, and a Spring Security-secured service is as follows: + +-* The web user is browsing the service's public pages. ++. The web user browses the service's public pages. + CAS or Spring Security is not involved. +-* The user eventually requests a page that is either secure or one of the beans it uses is secure. +-Spring Security's `ExceptionTranslationFilter` will detect the `AccessDeniedException` or `AuthenticationException`. +-* Because the user's `Authentication` object (or lack thereof) caused an `AuthenticationException`, the `ExceptionTranslationFilter` will call the configured `AuthenticationEntryPoint`. +-If using CAS, this will be the `CasAuthenticationEntryPoint` class. +-* The `CasAuthenticationEntryPoint` will redirect the user's browser to the CAS server. +-It will also indicate a `service` parameter, which is the callback URL for the Spring Security service (your application). ++. The user eventually requests a page that is either secure or that uses a secure bean. ++Spring Security's `ExceptionTranslationFilter` detects the `AccessDeniedException` or `AuthenticationException`. ++. Because the user's `Authentication` object (or lack thereof) caused an `AuthenticationException`, the `ExceptionTranslationFilter` calls the configured `AuthenticationEntryPoint`. ++If using CAS, this is the `CasAuthenticationEntryPoint` class. ++. The `CasAuthenticationEntryPoint` redirects the user's browser to the CAS server. ++It also indicates a `service` parameter, which is the callback URL for the Spring Security service (your application). + For example, the URL to which the browser is redirected might be https://my.company.com/cas/login?service=https%3A%2F%2Fserver3.company.com%2Fwebapp%2Flogin/cas. +-* After the user's browser redirects to CAS, they will be prompted for their username and password. +-If the user presents a session cookie which indicates they've previously logged on, they will not be prompted to login again (there is an exception to this procedure, which we'll cover later). +-CAS will use the `PasswordHandler` (or `AuthenticationHandler` if using CAS 3.0) discussed above to decide whether the username and password is valid. +-* Upon successful login, CAS will redirect the user's browser back to the original service. +-It will also include a `ticket` parameter, which is an opaque string representing the "service ticket". +-Continuing our earlier example, the URL the browser is redirected to might be https://server3.company.com/webapp/login/cas?ticket=ST-0-ER94xMJmn6pha35CQRoZ. +-* Back in the service web application, the `CasAuthenticationFilter` is always listening for requests to `/login/cas` (this is configurable, but we'll use the defaults in this introduction). +-The processing filter will construct a `UsernamePasswordAuthenticationToken` representing the service ticket. +-The principal will be equal to `CasAuthenticationFilter.CAS_STATEFUL_IDENTIFIER`, whilst the credentials will be the service ticket opaque value. +-This authentication request will then be handed to the configured `AuthenticationManager`. +-* The `AuthenticationManager` implementation will be the `ProviderManager`, which is in turn configured with the `CasAuthenticationProvider`. +-The `CasAuthenticationProvider` only responds to `UsernamePasswordAuthenticationToken` s containing the CAS-specific principal (such as `CasAuthenticationFilter.CAS_STATEFUL_IDENTIFIER`) and `CasAuthenticationToken` s (discussed later). +-* `CasAuthenticationProvider` will validate the service ticket using a `TicketValidator` implementation. +-This will typically be a `Cas20ServiceTicketValidator` which is one of the classes included in the CAS client library. +-In the event the application needs to validate proxy tickets, the `Cas20ProxyTicketValidator` is used. +-The `TicketValidator` makes an HTTPS request to the CAS server in order to validate the service ticket. +-It may also include a proxy callback URL, which is included in this example: https://my.company.com/cas/proxyValidate?service=https%3A%2F%2Fserver3.company.com%2Fwebapp%2Flogin/cas&ticket=ST-0-ER94xMJmn6pha35CQRoZ&pgtUrl=https://server3.company.com/webapp/login/cas/proxyreceptor. +-* Back on the CAS server, the validation request will be received. +-If the presented service ticket matches the service URL the ticket was issued to, CAS will provide an affirmative response in XML indicating the username. +-If any proxy was involved in the authentication (discussed below), the list of proxies is also included in the XML response. +-* [OPTIONAL] If the request to the CAS validation service included the proxy callback URL (in the `pgtUrl` parameter), CAS will include a `pgtIou` string in the XML response. ++. After the user's browser redirects to CAS, they are prompted for their username and password. ++If the user presents a session cookie that indicates that they have previously logged on, they are not prompted to login again (there is an exception to this procedure, which we cover later). ++CAS uses the `PasswordHandler` (or `AuthenticationHandler` if using CAS 3.0) discussed earler to decide whether the username and password are valid. ++. Upon successful login, CAS redirects the user's browser back to the original service. ++It also includes a `ticket` parameter, which is an opaque string that represents the "`service ticket`". ++Continuing our earlier example, the URL to which the browser is redirected might be https://server3.company.com/webapp/login/cas?ticket=ST-0-ER94xMJmn6pha35CQRoZ. ++. Back in the service web application, the `CasAuthenticationFilter` is always listening for requests to `/login/cas` (this is configurable, but we use the defaults in this introduction). ++The processing filter constructs a `UsernamePasswordAuthenticationToken` that represents the service ticket. ++The principal is equal to `CasAuthenticationFilter.CAS_STATEFUL_IDENTIFIER`, while the credentials are the service ticket opaque value. ++This authentication request is then handed to the configured `AuthenticationManager`. ++. The `AuthenticationManager` implementation is the `ProviderManager`, which is in turn configured with the `CasAuthenticationProvider`. ++The `CasAuthenticationProvider` only responds to `UsernamePasswordAuthenticationToken` instances that contain the CAS-specific principal (such as `CasAuthenticationFilter.CAS_STATEFUL_IDENTIFIER`) and `CasAuthenticationToken` instances (discussed later). ++. `CasAuthenticationProvider` will validate the service ticket using a `TicketValidator` implementation. ++This is typically a `Cas20ServiceTicketValidator`, which is one of the classes included in the CAS client library. ++If the application needs to validate proxy tickets, the `Cas20ProxyTicketValidator` is used. ++The `TicketValidator` makes an HTTPS request to the CAS server to validate the service ticket. ++It can also include a proxy callback URL, which is included in this example: https://my.company.com/cas/proxyValidate?service=https%3A%2F%2Fserver3.company.com%2Fwebapp%2Flogin/cas&ticket=ST-0-ER94xMJmn6pha35CQRoZ&pgtUrl=https://server3.company.com/webapp/login/cas/proxyreceptor. ++. Back on the CAS server, the validation request is received. ++If the presented service ticket matches the service URL to which the ticket was issued, CAS provides an affirmative response in XML that indicates the username. ++If any proxy was involved in the authentication (discussed later), the list of proxies is also included in the XML response. ++. [OPTIONAL] If the request to the CAS validation service included the proxy callback URL (in the `pgtUrl` parameter), CAS includes a `pgtIou` string in the XML response. + This `pgtIou` represents a proxy-granting ticket IOU. +-The CAS server will then create its own HTTPS connection back to the `pgtUrl`. ++The CAS server thens create its own HTTPS connection back to the `pgtUrl`. + This is to mutually authenticate the CAS server and the claimed service URL. +-The HTTPS connection will be used to send a proxy granting ticket to the original web application. +-For example, https://server3.company.com/webapp/login/cas/proxyreceptor?pgtIou=PGTIOU-0-R0zlgrl4pdAQwBvJWO3vnNpevwqStbSGcq3vKB2SqSFFRnjPHt&pgtId=PGT-1-si9YkkHLrtACBo64rmsi3v2nf7cpCResXg5MpESZFArbaZiOKH. +-* The `Cas20TicketValidator` will parse the XML received from the CAS server. +-It will return to the `CasAuthenticationProvider` a `TicketResponse`, which includes the username (mandatory), proxy list (if any were involved), and proxy-granting ticket IOU (if the proxy callback was requested). +-* Next `CasAuthenticationProvider` will call a configured `CasProxyDecider`. ++The HTTPS connection is used to send a proxy granting ticket to the original web application -- ++for example, https://server3.company.com/webapp/login/cas/proxyreceptor?pgtIou=PGTIOU-0-R0zlgrl4pdAQwBvJWO3vnNpevwqStbSGcq3vKB2SqSFFRnjPHt&pgtId=PGT-1-si9YkkHLrtACBo64rmsi3v2nf7cpCResXg5MpESZFArbaZiOKH. ++. The `Cas20TicketValidator` parses the XML received from the CAS server. ++It returns to the `CasAuthenticationProvider` a `TicketResponse`, which includes the username (mandatory), proxy list (if any were involved), and proxy-granting ticket IOU (if the proxy callback was requested). ++. Next `CasAuthenticationProvider` calls a configured `CasProxyDecider`. + The `CasProxyDecider` indicates whether the proxy list in the `TicketResponse` is acceptable to the service. +-Several implementations are provided with Spring Security: `RejectProxyTickets`, `AcceptAnyCasProxy` and `NamedCasProxyDecider`. +-These names are largely self-explanatory, except `NamedCasProxyDecider` which allows a `List` of trusted proxies to be provided. +-* `CasAuthenticationProvider` will next request a `AuthenticationUserDetailsService` to load the `GrantedAuthority` objects that apply to the user contained in the `Assertion`. +-* If there were no problems, `CasAuthenticationProvider` constructs a `CasAuthenticationToken` including the details contained in the `TicketResponse` and the ``GrantedAuthority``s. +-* Control then returns to `CasAuthenticationFilter`, which places the created `CasAuthenticationToken` in the security context. +-* The user's browser is redirected to the original page that caused the `AuthenticationException` (or a custom destination depending on the configuration). ++Spring Security provides three implementations: `RejectProxyTickets`, `AcceptAnyCasProxy`, and `NamedCasProxyDecider`. ++These names are largely self-explanatory, except `NamedCasProxyDecider`, which allows a `List` of trusted proxies to be provided. ++. `CasAuthenticationProvider` next requests a `AuthenticationUserDetailsService` to load the `GrantedAuthority` objects that apply to the user contained in the `Assertion`. ++. If there were no problems, `CasAuthenticationProvider` constructs a `CasAuthenticationToken`, including the details contained in the `TicketResponse` and the `GrantedAuthority` instances. ++. Control then returns to `CasAuthenticationFilter`, which places the created `CasAuthenticationToken` in the security context. ++. The user's browser is redirected to the original page that caused the `AuthenticationException` (or a custom destination depending on the configuration). + +-It's good that you're still here! +-Let's now look at how this is configured ++Next, we discuss how to configure the components that are involved in that long interaction. + + [[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. ++Spring Security makes the web application side of CAS easy. ++We assume you already know the basics of using Spring Security, so these are not covered again later. ++We also assume a namespace-based configuration is being used and add in the CAS beans as required. + Each section builds upon the previous section. +-A full CAS sample application can be found in the Spring Security <>. +- ++You can find a full CAS sample application in the Spring Security <>. + + [[cas-st]] + ==== 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. +-This represents your CAS service: ++This section describes how to set up Spring Security to authenticate Service Tickets. ++Oftentimes, this is all a web application requires. ++You need to add a `ServiceProperties` bean to your application context to represent your CAS service: + ++==== + [source,xml] + ---- + + + ---- ++==== + +-The `service` must equal a URL that will be monitored by the `CasAuthenticationFilter`. +-The `sendRenew` defaults to false, but should be set to true if your application is particularly sensitive. +-What this parameter does is tell the CAS login service that a single sign on login is unacceptable. +-Instead, the user will need to re-enter their username and password in order to gain access to the service. ++The `service` must equal a URL that is monitored by the `CasAuthenticationFilter`. ++`sendRenew` defaults to `false` but should be set to `true` if your application is particularly sensitive. ++This parameter tells the CAS login service that a single-sign-on login is unacceptable. ++Instead, the user needs to re-enter their username and password to gain access to the service. + +-The following beans should be configured to commence the CAS authentication process (assuming you're using a namespace configuration): ++The following beans should be configured to commence the CAS authentication process (assuming you use a namespace configuration): + ++==== + [source,xml] + ---- + +@@ -137,17 +141,19 @@ The following beans should be configured to commence the CAS authentication proc + + + ---- ++==== + + For CAS to operate, the `ExceptionTranslationFilter` must have its `authenticationEntryPoint` property set to the `CasAuthenticationEntryPoint` bean. +-This can easily be done using <> as is done in the example above. +-The `CasAuthenticationEntryPoint` must refer to the `ServiceProperties` bean (discussed above), which provides the URL to the enterprise's CAS login server. +-This is where the user's browser will be redirected. ++You can do so by using <>, as in the preceding example. ++The `CasAuthenticationEntryPoint` must refer to the `ServiceProperties` bean (discussed earlier), which provides the URL to the enterprise's CAS login server. ++This is where the user's browser is redirected. + + The `CasAuthenticationFilter` has very similar properties to the `UsernamePasswordAuthenticationFilter` (used for form-based logins). + You can use these properties to customize things like behavior for authentication success and failure. + +-Next you need to add a `CasAuthenticationProvider` and its collaborators: ++Next, you need to add a `CasAuthenticationProvider` and its collaborators: + ++==== + [source,xml,attrs="-attributes"] + ---- + +@@ -180,24 +186,25 @@ Normally passwords should be hashed using BCrypt --> + ... + + ---- ++==== + + The `CasAuthenticationProvider` uses a `UserDetailsService` instance to load the authorities for a user, once they have been authenticated by CAS. +-We've shown a simple in-memory setup here. ++We have shown a simple in-memory setup here. + Note that the `CasAuthenticationProvider` does not actually use the password for authentication, but it does use the authorities. + + The beans are all reasonably self-explanatory if you refer back to the <> section. + + This completes the most basic configuration for CAS. +-If you haven't made any mistakes, your web application should happily work within the framework of CAS single sign on. +-No other parts of Spring Security need to be concerned about the fact CAS handled authentication. +-In the following sections we will discuss some (optional) more advanced configurations. +- ++If you have not made any mistakes, your web application should happily work within the framework of CAS single sign on. ++No other parts of Spring Security need to be concerned about the fact that CAS handled authentication. ++In the following sections, we discuss some (optional) more advanced configurations. + + [[cas-singlelogout]] + ==== 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 ++The following updates to the Spring Security configuration handle Single Logout: + ++==== + [source,xml] + ---- + +@@ -221,26 +228,26 @@ Below are updates to the Spring Security configuration that handle Single Logout + + + ---- ++==== + +-The `logout` element logs the user out of the local application, but does not end the session with the CAS server or any other applications that have been logged into. +-The `requestSingleLogoutFilter` filter will allow the URL of `/spring_security_cas_logout` to be requested to redirect the application to the configured CAS Server logout URL. +-Then the CAS Server will send a Single Logout request to all the services that were signed into. ++The `logout` element logs the user out of the local application but does not end the session with the CAS server or any other applications that have been logged into. ++The `requestSingleLogoutFilter` filter lets the URL of `/spring_security_cas_logout` be requested to redirect the application to the configured CAS Server logout URL. ++Then the CAS Server sends a Single Logout request to all the services that were signed into. + The `singleLogoutFilter` handles the Single Logout request by looking up the `HttpSession` in a static `Map` and then invalidating it. + + It might be confusing why both the `logout` element and the `singleLogoutFilter` are needed. +-It is considered best practice to logout locally first since the `SingleSignOutFilter` just stores the `HttpSession` in a static `Map` in order to call invalidate on it. ++It is considered best practice to logout locally first, since the `SingleSignOutFilter` just stores the `HttpSession` in a static `Map` in order to invalidate it. + With the configuration above, the flow of logout would be: + +-* The user requests `/logout` which would log the user out of the local application and send the user to the logout success page. +-* The logout success page, `/cas-logout.jsp`, should instruct the user to click a link pointing to `/logout/cas` in order to logout out of all applications. ++* The user requests `/logout`, which would log the user out of the local application and send the user to the logout success page. ++* The logout success page, `/cas-logout.jsp`, should instruct the user to click a link that points to `/logout/cas`, to logout out of all applications. + * When the user clicks the link, the user is redirected to the CAS single logout URL (https://localhost:9443/cas/logout). + * On the CAS Server side, the CAS single logout URL then submits single logout requests to all the CAS Services. + On the CAS Service side, JASIG's `SingleSignOutFilter` processes the logout request by invalidating the original session. + ++The next step is to add the following to your `web.xml` file: + +- +-The next step is to add the following to your web.xml +- ++==== + [source,xml] + ---- + +@@ -263,45 +270,49 @@ The next step is to add the following to your web.xml + + + ---- ++==== + +-When using the SingleSignOutFilter you might encounter some encoding issues. +-Therefore it is recommended to add the `CharacterEncodingFilter` to ensure that the character encoding is correct when using the `SingleSignOutFilter`. +-Again, refer to JASIG's documentation for details. ++When using the `SingleSignOutFilter`, you might encounter some encoding issues. ++Therefore, we recommend adding the `CharacterEncodingFilter` to ensure that the character encoding is correct when using the `SingleSignOutFilter`. ++Again, see JASIG's documentation for details. + The `SingleSignOutHttpSessionListener` ensures that when an `HttpSession` expires, the mapping used for single logout is removed. + + + [[cas-pt-client]] + ==== 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. ++This section describes how to authenticate to a service by using CAS. ++In other words, this section discusses how to set up 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 +-In order to authenticate to a stateless service, the application needs to obtain a proxy granting ticket (PGT). ++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. + + The first step is to include a `ProxyGrantingTicketStorage` in your Spring Security configuration. +-This is used to store PGT's that are obtained by the `CasAuthenticationFilter` so that they can be used to obtain proxy tickets. +-An example configuration is shown below ++This is used to store PGTs that are obtained by the `CasAuthenticationFilter` so that they can be used to obtain proxy tickets. ++The following example shows a typical configuration: + ++==== + [source,xml] + ---- + + + ---- ++==== + + The next step is to update the `CasAuthenticationProvider` to be able to obtain proxy tickets. +-To do this replace the `Cas20ServiceTicketValidator` with a `Cas20ProxyTicketValidator`. +-The `proxyCallbackUrl` should be set to a URL that the application will receive PGT's at. +-Last, the configuration should also reference the `ProxyGrantingTicketStorage` so it can use a PGT to obtain proxy tickets. +-You can find an example of the configuration changes that should be made below. ++To do so, replace the `Cas20ServiceTicketValidator` with a `Cas20ProxyTicketValidator`. ++The `proxyCallbackUrl` should be set to a URL that at which the application receives PGTs. ++Finally, the configuration should also reference the `ProxyGrantingTicketStorage` so that it can use a PGT to obtain proxy tickets. ++The following example shows the configuration changes that should be made: + ++==== + [source,xml] + ---- + + + ---- ++==== + +-The last step is to update the `CasAuthenticationFilter` to accept PGT and to store them in the `ProxyGrantingTicketStorage`. +-It is important the `proxyReceptorUrl` matches the `proxyCallbackUrl` of the `Cas20ProxyTicketValidator`. +-An example configuration is shown below. ++The last step is to update the `CasAuthenticationFilter` to accept PGTs and to store them in the `ProxyGrantingTicketStorage`. ++The `proxyReceptorUrl` should match the `proxyCallbackUrl` of the `Cas20ProxyTicketValidator`. ++The following example shows a typical configuration: + ++==== + [source,xml] + ---- +- + + ... + + + +- + ---- ++==== + + [[cas-pt-client-sample]] +-===== 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. ++===== Calling a Stateless Service by 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 <> contains a working example in the `ProxyTicketSampleServlet`. +-Example code can be found below: ++The following listing shows an example: + ++==== + [source,java] + ---- + protected void doGet(HttpServletRequest request, HttpServletResponse response) +@@ -357,27 +370,29 @@ String proxyResponse = CommonUtils.getResponseFromServer(serviceUrl, "UTF-8"); + ... + } + ---- ++==== + + [[cas-pt]] + ==== 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`. ++A stateful client is considered to be any client that submits to the `filterProcessUrl` of the `CasAuthenticationFilter`. ++A stateless client is any client that presents an authentication request to `CasAuthenticationFilter` on a URL other than the `filterProcessUrl`. + +-Because remoting protocols have no way of presenting themselves within the context of an `HttpSession`, it isn't possible to rely on the default practice of storing the security context in the session between requests. +-Furthermore, because the CAS server invalidates a ticket after it has been validated by the `TicketValidator`, presenting the same proxy ticket on subsequent requests will not work. ++Because remoting protocols have no way of presenting themselves within the context of an `HttpSession`, it is not possible to rely on the default practice of storing the security context in the session between requests. ++Furthermore, because the CAS server invalidates a ticket after it has been validated by the `TicketValidator`, presenting the same proxy ticket on subsequent requests does not work. + + One obvious option is to not use CAS at all for remoting protocol clients. + However, this would eliminate many of the desirable features of CAS. + As a middle-ground, the `CasAuthenticationProvider` uses a `StatelessTicketCache`. +-This is used solely for stateless clients which use a principal equal to `CasAuthenticationFilter.CAS_STATELESS_IDENTIFIER`. +-What happens is the `CasAuthenticationProvider` will store the resulting `CasAuthenticationToken` in the `StatelessTicketCache`, keyed on the proxy ticket. +-Accordingly, remoting protocol clients can present the same proxy ticket and the `CasAuthenticationProvider` will not need to contact the CAS server for validation (aside from the first request). +-Once authenticated, the proxy ticket could be used for URLs other than the original target service. ++This is used solely for stateless clients that use a principal equal to `CasAuthenticationFilter.CAS_STATELESS_IDENTIFIER`. ++The `CasAuthenticationProvider` stores the resulting `CasAuthenticationToken` in the `StatelessTicketCache`, keyed on the proxy ticket. ++Accordingly, remoting protocol clients can present the same proxy ticket, and the `CasAuthenticationProvider` does not need to contact the CAS server for validation (aside from the first request). ++Once authenticated, the proxy ticket can be used for URLs other than the original target service. + + This section builds upon the previous sections to accommodate proxy ticket authentication. +-The first step is to specify to authenticate all artifacts as shown below. ++The first step is to specify to authenticate all artifacts: + ++==== + [source,xml] + ---- + + + ---- ++==== + + The next step is to specify `serviceProperties` and the `authenticationDetailsSource` for the `CasAuthenticationFilter`. +-The `serviceProperties` property instructs the `CasAuthenticationFilter` to attempt to authenticate all artifacts instead of only ones present on the `filterProcessUrl`. ++The `serviceProperties` property instructs the `CasAuthenticationFilter` to try to authenticate all artifacts instead of only ones present on the `filterProcessUrl`. + The `ServiceAuthenticationDetailsSource` creates a `ServiceAuthenticationDetails` that ensures the current URL, based upon the `HttpServletRequest`, is used as the service URL when validating the ticket. +-The method for generating the service URL can be customized by injecting a custom `AuthenticationDetailsSource` that returns a custom `ServiceAuthenticationDetails`. ++You can customize the method for generating the service URL by injecting a custom `AuthenticationDetailsSource` that returns a custom `ServiceAuthenticationDetails`. + ++==== + [source,xml] + ---- + + + ---- ++==== + +-You will also need to update the `CasAuthenticationProvider` to handle proxy tickets. +-To do this replace the `Cas20ServiceTicketValidator` with a `Cas20ProxyTicketValidator`. +-You will need to configure the `statelessTicketCache` and which proxies you want to accept. +-You can find an example of the updates required to accept all proxies below. ++You also need to update the `CasAuthenticationProvider` to handle proxy tickets. ++To do so, replace the `Cas20ServiceTicketValidator` with a `Cas20ProxyTicketValidator`. ++You need to configure the `statelessTicketCache` and which proxies you want to accept. ++The following example shows the updates required to accept all proxies: + ++==== + [source,xml] + ---- + +@@ -441,3 +460,4 @@ You can find an example of the updates required to accept all proxies below. + + + ---- ++==== +diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/events.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/events.adoc +index 254df9a669..a97b2b17af 100644 +--- a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/events.adoc ++++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/events.adoc +@@ -1,10 +1,10 @@ + [[servlet-events]] + == Authentication Events + +-For each authentication that succeeds or fails, a `AuthenticationSuccessEvent` or `AuthenticationFailureEvent` is fired, respectively. ++For each authentication that succeeds or fails, a `AuthenticationSuccessEvent` or `AuthenticationFailureEvent`, respectively, is fired. + + To listen for these events, you must first publish an `AuthenticationEventPublisher`. +-Spring Security's `DefaultAuthenticationEventPublisher` will probably do fine: ++Spring Security's `DefaultAuthenticationEventPublisher` works fine for this purpose: + + ==== + .Java +@@ -28,7 +28,7 @@ fun authenticationEventPublisher + ---- + ==== + +-Then, you can use Spring's `@EventListener` support: ++Then you can use Spring's `@EventListener` support: + + ==== + .Java +@@ -70,7 +70,7 @@ While similar to `AuthenticationSuccessHandler` and `AuthenticationFailureHandle + + === Adding Exception Mappings + +-`DefaultAuthenticationEventPublisher` by default will publish an `AuthenticationFailureEvent` for the following events: ++By default, `DefaultAuthenticationEventPublisher` publishes an `AuthenticationFailureEvent` for the following events: + + |============ + | Exception | Event +@@ -85,9 +85,9 @@ While similar to `AuthenticationSuccessHandler` and `AuthenticationFailureHandle + | `InvalidBearerTokenException` | `AuthenticationFailureBadCredentialsEvent` + |============ + +-The publisher does an exact `Exception` match, which means that sub-classes of these exceptions won't also produce events. ++The publisher does an exact `Exception` match, which means that sub-classes of these exceptions do not also produce events. + +-To that end, you may want to supply additional mappings to the publisher via the `setAdditionalExceptionMappings` method: ++To that end, you may want to supply additional mappings to the publisher through the `setAdditionalExceptionMappings` method: + + ==== + .Java +@@ -123,7 +123,7 @@ fun authenticationEventPublisher + + === Default Event + +-And, you can supply a catch-all event to fire in the case of any `AuthenticationException`: ++You can also supply a catch-all event to fire in the case of any `AuthenticationException`: + + ==== + .Java +diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/index.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/index.adoc +index 9536e950e6..0d0507f8cb 100644 +--- a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/index.adoc ++++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/index.adoc +@@ -7,34 +7,34 @@ This section discusses: + [[servlet-authentication-architecture]] + *Architecture Components* + +-This section describes the main architectural components of Spring Security's used in Servlet authentication. +-If you need concrete flows that explain how these pieces fit together, look at the <> specific sections. +- +-* <> - The `SecurityContextHolder` is where Spring Security stores the details of who is <>. +-* <> - is obtained from the `SecurityContextHolder` and contains the `Authentication` of the currently authenticated user. +-* <> - Can be the input to `AuthenticationManager` to provide the credentials a user has provided to authenticate or the current user from the `SecurityContext`. +-* <> - An authority that is granted to the principal on the `Authentication` (i.e. roles, scopes, etc.) +-* <> - the API that defines how Spring Security's Filters perform <>. +-* <> - the most common implementation of `AuthenticationManager`. +-* <> - used by `ProviderManager` to perform a specific type of authentication. +-* <> - used for requesting credentials from a client (i.e. redirecting to a log in page, sending a `WWW-Authenticate` response, etc.) +-* <> - a base `Filter` used for authentication. +-This also gives a good idea of the high level flow of authentication and how pieces work together. ++This section describes the main architectural components of Spring Security that are used in Servlet authentication. ++If you need concrete flows that explain how these pieces fit together, see the <> specific sections. ++ ++* <>: The `SecurityContextHolder` is where Spring Security stores the details of who is <>. ++* <>: Is obtained from the `SecurityContextHolder` and contains the `Authentication` of the currently authenticated user. ++* <>: Can be the input to `AuthenticationManager` to provide the credentials a user has provided to authenticate or the current user from the `SecurityContext`. ++* <>: An authority that is granted to the principal on the `Authentication` (roles, scopes, and so on) ++* <>: The API that defines how Spring Security's Filters perform <>. ++* <>: The most common implementation of `AuthenticationManager`. ++* <>: Used by `ProviderManager` to perform a specific type of authentication. ++* <>: Used for requesting credentials from a client (redirecting to a log in page, sending a `WWW-Authenticate` response, and so on) ++* <>: A base `Filter` used for authentication. ++This also gives a good idea of the high-level flow of authentication and how the pieces work together. + + [[servlet-authentication-mechanisms]] + *Authentication Mechanisms* + + // FIXME: brief description + +-* <> - how to authenticate with a username/password +-* <> - OAuth 2.0 Log In with OpenID Connect and non-standard OAuth 2.0 Login (i.e. GitHub) +-* <> - SAML 2.0 Log In +-* <> - Central Authentication Server (CAS) Support +-* <> - How to remember a user past session expiration +-* <> - Authenticate with JAAS +-* <> - OpenID Authentication (not to be confused with OpenID Connect) +-* <> - Authenticate with an external mechanism such as https://www.siteminder.com/[SiteMinder] or Java EE security but still use Spring Security for authorization and protection against common exploits. +-* <> - X509 Authentication ++* <>: How to authenticate with a username and password. ++* <>: OAuth 2.0 Log In with OpenID Connect and non-standard OAuth 2.0 Login (i.e. GitHub). ++* <>: SAML 2.0 Log In. ++* <>: Central Authentication Server (CAS) support. ++* <>: How to remember the past session expiration of a user. ++* <>: Authenticate with JAAS. ++* <>: OpenID Authentication (not to be confused with OpenID Connect). ++* <>: Authenticate with an external mechanism such as https://www.siteminder.com/[SiteMinder] or Java EE security but still use Spring Security for authorization and protection against common exploits. ++* <>: X509 Authentication. + + // FIXME: Add other mechanisms + +diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/jaas.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/jaas.adoc +index 3a1864ca89..98020d9406 100644 +--- a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/jaas.adoc ++++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/jaas.adoc +@@ -1,80 +1,71 @@ + [[servlet-jaas]] + == Java Authentication and Authorization Service (JAAS) Provider + +- +-=== 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. +- ++Spring Security provides a package to delegate authentication requests to the Java Authentication and Authorization Service (JAAS). ++This section discusses that package. + + [[jaas-abstractjaasauthenticationprovider]] + === AbstractJaasAuthenticationProvider +-The `AbstractJaasAuthenticationProvider` is the basis for the provided JAAS `AuthenticationProvider` implementations. ++The `AbstractJaasAuthenticationProvider` class 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. +- ++The `AbstractJaasAuthenticationProvider` has a number of dependencies that can be injected into it, as discussed in the remainder of this section. + + [[jaas-callbackhandler]] + ==== JAAS CallbackHandler +-Most JAAS `LoginModule` s require a callback of some sort. ++Most JAAS `LoginModule` instances require a callback of some sort. + These callbacks are usually used to obtain the username and password from the user. + +-In a Spring Security deployment, Spring Security is responsible for this user interaction (via the authentication mechanism). +-Thus, by the time the authentication request is delegated through to JAAS, Spring Security's authentication mechanism will already have fully-populated an `Authentication` object containing all the information required by the JAAS `LoginModule`. +- +-Therefore, the JAAS package for Spring Security provides two default callback handlers, `JaasNameCallbackHandler` and `JaasPasswordCallbackHandler`. +-Each of these callback handlers implement `JaasAuthenticationCallbackHandler`. +-In most cases these callback handlers can simply be used without understanding the internal mechanics. ++In a Spring Security deployment, Spring Security is responsible for this user interaction (through the authentication mechanism). ++Thus, by the time the authentication request is delegated through to JAAS, Spring Security's authentication mechanism has already fully populated an `Authentication` object that contains all the information required by the JAAS `LoginModule`. + +-For those needing full control over the callback behavior, internally `AbstractJaasAuthenticationProvider` wraps these `JaasAuthenticationCallbackHandler` s with an `InternalCallbackHandler`. +-The `InternalCallbackHandler` is the class that actually implements JAAS normal `CallbackHandler` interface. +-Any time that the JAAS `LoginModule` is used, it is passed a list of application context configured `InternalCallbackHandler` s. +-If the `LoginModule` requests a callback against the `InternalCallbackHandler` s, the callback is in-turn passed to the `JaasAuthenticationCallbackHandler` s being wrapped. ++Therefore, the JAAS package for Spring Security provides two default callback handlers: `JaasNameCallbackHandler` and `JaasPasswordCallbackHandler`. ++Each of these callback handlers implements `JaasAuthenticationCallbackHandler`. ++In most cases, these callback handlers can be used without understanding the internal mechanics. + ++For those needing full control over the callback behavior, `AbstractJaasAuthenticationProvider` internally wraps these `JaasAuthenticationCallbackHandler` instances with an `InternalCallbackHandler`. ++The `InternalCallbackHandler` is the class that actually implements the JAAS normal `CallbackHandler` interface. ++Any time that the JAAS `LoginModule` is used, it is passed a list of application contexts configured `InternalCallbackHandler` instances. ++If the `LoginModule` requests a callback against the `InternalCallbackHandler` instances, the callback is, in turn, passed to the `JaasAuthenticationCallbackHandler` instances being wrapped. + + [[jaas-authoritygranter]] + ==== JAAS AuthorityGranter + JAAS works with principals. +-Even "roles" are represented as principals in JAAS. ++Even "`roles`" are represented as principals in JAAS. + Spring Security, on the other hand, works with `Authentication` objects. +-Each `Authentication` object contains a single principal, and multiple `GrantedAuthority` s. ++Each `Authentication` object contains a single principal and multiple `GrantedAuthority` instances. + To facilitate mapping between these different concepts, Spring Security's JAAS package includes an `AuthorityGranter` interface. + +-An `AuthorityGranter` is responsible for inspecting a JAAS principal and returning a set of `String` s, representing the authorities assigned to the principal. +-For each returned authority string, the `AbstractJaasAuthenticationProvider` creates a `JaasGrantedAuthority` (which implements Spring Security's `GrantedAuthority` interface) containing the authority string and the JAAS principal that the `AuthorityGranter` was passed. +-The `AbstractJaasAuthenticationProvider` obtains the JAAS principals by firstly successfully authenticating the user's credentials using the JAAS `LoginModule`, and then accessing the `LoginContext` it returns. ++An `AuthorityGranter` is responsible for inspecting a JAAS principal and returning a set of `String` objects that represent the authorities assigned to the principal. ++For each returned authority string, the `AbstractJaasAuthenticationProvider` creates a `JaasGrantedAuthority` (which implements Spring Security's `GrantedAuthority` interface) that contains the authority string and the JAAS principal that the `AuthorityGranter` was passed. ++The `AbstractJaasAuthenticationProvider` obtains the JAAS principals by first successfully authenticating the user's credentials by using the JAAS `LoginModule` and then accessing the `LoginContext` it returns. + A call to `LoginContext.getSubject().getPrincipals()` is made, with each resulting principal passed to each `AuthorityGranter` defined against the `AbstractJaasAuthenticationProvider.setAuthorityGranters(List)` property. + +-Spring Security does not include any production `AuthorityGranter` s given that every JAAS principal has an implementation-specific meaning. ++Spring Security does not include any production `AuthorityGranter` instances, given that every JAAS principal has an implementation-specific meaning. + However, there is a `TestAuthorityGranter` in the unit tests that demonstrates a simple `AuthorityGranter` implementation. + +- + [[jaas-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. +- ++The `DefaultJaasAuthenticationProvider` lets a JAAS `Configuration` object be injected into it as a dependency. ++It then creates a `LoginContext` by using the injected JAAS `Configuration`. ++This means that `DefaultJaasAuthenticationProvider` is not bound to any particular implementation of `Configuration`, as `JaasAuthenticationProvider` is. + + [[jaas-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`. +-For details, refer to the class level javadoc of `InMemoryConfiguration`. +- ++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` instances. ++`InMemoryConfiguration` also supports a default `Array` of `AppConfigurationEntry` objects that is used if no mapping is found within the provided `Map`. ++For details, see the {security-api-url}org/springframework/security/authentication/jaas/memory/InMemoryConfiguration.html[Javadoc of `InMemoryConfiguration`]. + + [[jaas-djap-config]] + ==== 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. ++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 dependent on the default `Configuration` implementation. + +-An example configuration of `DefaultJaasAuthenticationProvider` using `InMemoryConfiguration` is provided below. ++The next example provides a configuration of `DefaultJaasAuthenticationProvider` that uses `InMemoryConfiguration`. + Note that custom implementations of `Configuration` can easily be injected into `DefaultJaasAuthenticationProvider` as well. + +- ++==== + [source,xml] + ---- +- + + +@@ -110,32 +101,32 @@ class="org.springframework.security.authentication.jaas.DefaultJaasAuthenticatio + + + +- + ---- +- +- ++==== + + [[jaas-jaasauthenticationprovider]] + === JaasAuthenticationProvider +-The `JaasAuthenticationProvider` assumes the default `Configuration` is an instance of https://download.oracle.com/javase/1.4.2/docs/guide/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` assumes that the default `Configuration` is an instance of https://download.oracle.com/javase/1.4.2/docs/guide/security/jaas/spec/com/sun/security/auth/login/ConfigFile.html[`ConfigFile`]. ++This assumption is made in order to try to update the `Configuration`. + The `JaasAuthenticationProvider` then uses the default `Configuration` to create the `LoginContext`. + +-Let's assume we have a JAAS login configuration file, `/WEB-INF/login.conf`, with the following contents: ++Assume that we have a JAAS login configuration file, `/WEB-INF/login.conf`, with the following contents: + ++==== + [source,txt] + ---- + JAASTest { + sample.SampleLoginModule required; + }; + ---- ++==== + +-Like all Spring Security beans, the `JaasAuthenticationProvider` is configured via the application context. ++Like all Spring Security beans, the `JaasAuthenticationProvider` is configured through the application context. + The following definitions would correspond to the above JAAS login configuration file: + ++==== + [source,xml] + ---- +- + + +@@ -155,16 +146,19 @@ class="org.springframework.security.authentication.jaas.JaasAuthenticationProvid + + + ---- ++==== + + [[jaas-apiprovision]] + === Running as a Subject +-If configured, the `JaasApiIntegrationFilter` will attempt to run as the `Subject` on the `JaasAuthenticationToken`. ++If configured, the `JaasApiIntegrationFilter` tries to run as the `Subject` on the `JaasAuthenticationToken`. + This means that the `Subject` can be accessed using: + ++==== + [source,java] + ---- + Subject subject = Subject.getSubject(AccessController.getContext()); + ---- ++==== + +-This integration can easily be configured using the <> attribute. ++You can configure this integration by using the <> attribute. + This feature is useful when integrating with legacy or external API's that rely on the JAAS Subject being populated. +diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/logout.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/logout.adoc +index c824ffe0ad..1b5a3f1893 100644 +--- a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/logout.adoc ++++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/logout.adoc +@@ -1,16 +1,18 @@ + [[jc-logout]] + == Handling Logouts + ++This section covers how to customize the handling of logouts. ++ + [[logout-java-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: ++The default is that accessing the URL `/logout` logs the user out by: + + - Invalidating the HTTP Session + - Cleaning up any RememberMe authentication that was configured + - Clearing the `SecurityContextHolder` +-- Redirect to `/login?logout` ++- Redirecting to `/login?logout` + + Similar to configuring login capabilities, however, you also have various options to further customize your logout requirements: + +@@ -53,33 +55,30 @@ override fun configure(http: HttpSecurity) { + + <1> Provides logout support. + This is automatically applied when using `WebSecurityConfigurerAdapter`. +-<2> The URL that triggers log out to occur (default is `/logout`). +-If CSRF protection is enabled (default), then the request must also be a POST. +-For more information, please consult the {security-api-url}org/springframework/security/config/annotation/web/configurers/LogoutConfigurer.html#logoutUrl-java.lang.String-[JavaDoc]. +-<3> The URL to redirect to after logout has occurred. ++<2> The URL that triggers log out to occur (the default is `/logout`). ++If CSRF protection is enabled (the default), the request must also be a POST. ++For more information, see {security-api-url}org/springframework/security/config/annotation/web/configurers/LogoutConfigurer.html#logoutUrl-java.lang.String-[`logoutUrl(java.lang.String logoutUrl)`]. ++<3> The URL to which to redirect after logout has occurred. + The default is `/login?logout`. +-For more information, please consult the {security-api-url}org/springframework/security/config/annotation/web/configurers/LogoutConfigurer.html#logoutSuccessUrl-java.lang.String-[JavaDoc]. ++For more information, see {security-api-url}org/springframework/security/config/annotation/web/configurers/LogoutConfigurer.html#logoutSuccessUrl-java.lang.String-[`logoutSuccessUrl(java.lang.String logoutSuccessUrl)`]. + <4> Let's you specify a custom `LogoutSuccessHandler`. + If this is specified, `logoutSuccessUrl()` is ignored. +-For more information, please consult the {security-api-url}org/springframework/security/config/annotation/web/configurers/LogoutConfigurer.html#logoutSuccessHandler-org.springframework.security.web.authentication.logout.LogoutSuccessHandler-[JavaDoc]. ++For more information, see {security-api-url}org/springframework/security/config/annotation/web/configurers/LogoutConfigurer.html#logoutSuccessHandler-org.springframework.security.web.authentication.logout.LogoutSuccessHandler-[`LogoutSuccessHandler`]. + <5> Specify whether to invalidate the `HttpSession` at the time of logout. + This is *true* by default. + Configures the `SecurityContextLogoutHandler` under the covers. +-For more information, please consult the {security-api-url}org/springframework/security/config/annotation/web/configurers/LogoutConfigurer.html#invalidateHttpSession-boolean-[JavaDoc]. ++For more information, see {security-api-url}org/springframework/security/config/annotation/web/configurers/LogoutConfigurer.html#invalidateHttpSession-boolean-[`invalidateHttpSession(boolean invalidateHttpSession)`]. + <6> Adds a `LogoutHandler`. +-`SecurityContextLogoutHandler` is added as the last `LogoutHandler` by default. +-<7> Allows specifying the names of cookies to be removed on logout success. ++By default, `SecurityContextLogoutHandler` is added as the last `LogoutHandler`. ++<7> Lets specifying the names of cookies be removed on logout success. + This is a shortcut for adding a `CookieClearingLogoutHandler` explicitly. + +-[NOTE] +-==== +-Logouts can of course also be configured using the XML Namespace notation. +-Please see the documentation for the <> in the Spring Security XML Namespace section for further details. +-==== ++NOTE: Logouts can also be configured by using the XML Namespace notation. ++See the documentation for the <> in the Spring Security XML Namespace section for further details. + +-Generally, in order to customize logout functionality, you can add ++Generally, to customize logout functionality, you can add + `{security-api-url}org/springframework/security/web/authentication/logout/LogoutHandler.html[LogoutHandler]` +-and/or ++or + `{security-api-url}org/springframework/security/web/authentication/logout/LogoutSuccessHandler.html[LogoutSuccessHandler]` + implementations. + For many common scenarios, these handlers are applied under the +@@ -88,8 +87,8 @@ covers when using the fluent API. + [[ns-logout]] + === 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. ++The default logout URL is `/logout`, but you can set it to something else by setting the `logout-url` attribute. ++You can find more information on other available attributes in the namespace appendix. + + [[jc-logout-handler]] + === LogoutHandler +@@ -97,9 +96,9 @@ More information on other available attributes may be found in the namespace app + Generally, `{security-api-url}org/springframework/security/web/authentication/logout/LogoutHandler.html[LogoutHandler]` + implementations indicate classes that are able to participate in logout handling. + They are expected to be invoked to perform necessary clean-up. +-As such they should ++As a result, they should + not throw exceptions. +-Various implementations are provided: ++Spring Security provides various implementations: + + - {security-api-url}org/springframework/security/web/authentication/rememberme/PersistentTokenBasedRememberMeServices.html[PersistentTokenBasedRememberMeServices] + - {security-api-url}org/springframework/security/web/authentication/rememberme/TokenBasedRememberMeServices.html[TokenBasedRememberMeServices] +@@ -108,41 +107,41 @@ Various implementations are provided: + - {security-api-url}org/springframework/security/web/authentication/logout/SecurityContextLogoutHandler.html[SecurityContextLogoutHandler] + - {security-api-url}org/springframework/security/web/authentication/logout/HeaderWriterLogoutHandler.html[HeaderWriterLogoutHandler] + +-Please see <> for details. ++See <> for details. + + Instead of providing `LogoutHandler` implementations directly, the fluent API also provides shortcuts that provide the respective `LogoutHandler` implementations under the covers. +-E.g. `deleteCookies()` allows specifying the names of one or more cookies to be removed on logout success. ++For example, `deleteCookies()` lets you specify the names of one or more cookies to be removed on logout success. + This is a shortcut compared to adding a `CookieClearingLogoutHandler`. + + [[jc-logout-success-handler]] + === LogoutSuccessHandler + +-The `LogoutSuccessHandler` is called after a successful logout by the `LogoutFilter`, to handle e.g. ++The `LogoutSuccessHandler` is called after a successful logout by the `LogoutFilter`, to handle (for example) + redirection or forwarding to the appropriate destination. + Note that the interface is almost the same as the `LogoutHandler` but may raise an exception. + +-The following implementations are provided: ++Spring Security provides the following implementations: + + - {security-api-url}org/springframework/security/web/authentication/logout/SimpleUrlLogoutSuccessHandler.html[SimpleUrlLogoutSuccessHandler] + - HttpStatusReturningLogoutSuccessHandler + +-As mentioned above, you don't need to specify the `SimpleUrlLogoutSuccessHandler` directly. ++As mentioned earlier, you need not specify the `SimpleUrlLogoutSuccessHandler` directly. + Instead, the fluent API provides a shortcut by setting the `logoutSuccessUrl()`. +-This will setup the `SimpleUrlLogoutSuccessHandler` under the covers. +-The provided URL will be redirected to after a logout has occurred. ++This sets up the `SimpleUrlLogoutSuccessHandler` under the covers. ++The provided URL is redirected to after a logout has occurred. + The default is `/login?logout`. + + The `HttpStatusReturningLogoutSuccessHandler` can be interesting in REST API type scenarios. +-Instead of redirecting to a URL upon the successful logout, this `LogoutSuccessHandler` allows you to provide a plain HTTP status code to be returned. +-If not configured a status code 200 will be returned by default. ++Instead of redirecting to a URL upon the successful logout, this `LogoutSuccessHandler` lets you provide a plain HTTP status code to be returned. ++If not configured, a status code 200 is returned by default. + + [[jc-logout-references]] + === Further Logout-Related References + + - <> + - <> +-- <> ++- <> + - <> + - <> in section CSRF Caveats +-- Section <> (CAS protocol) ++- <> (CAS protocol) + - Documentation for the <> in the Spring Security XML Namespace section +diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/openid.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/openid.adoc +index 01362127ff..c615550bcf 100644 +--- a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/openid.adoc ++++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/openid.adoc +@@ -1,11 +1,11 @@ + [[servlet-openid]] + == 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. ++NOTE: The OpenID 1.0 and 2.0 protocols have been deprecated. You should migrate to OpenID Connect, which is supported by `spring-security-oauth2`. + +-The namespace supports https://openid.net/[OpenID] login either instead of, or in addition to normal form-based login, with a simple change: ++The namespace supports https://openid.net/[OpenID] login either instead of or in addition to normal form-based login, with a simple change: + ++==== + [source,xml] + ---- + +@@ -13,24 +13,27 @@ The namespace supports https://openid.net/[OpenID] login either instead of, or i + + + ---- ++==== + + You should then register yourself with an OpenID provider (such as myopenid.com), and add the user information to your in-memory ``: + ++==== + [source,xml] + ---- + + ---- ++==== + +-You should be able to login using the `myopenid.com` site to authenticate. +-It is also possible to select a specific `UserDetailsService` bean for use OpenID by setting the `user-service-ref` attribute on the `openid-login` element. +-Note that we have omitted the password attribute from the above user configuration, since this set of user data is only being used to load the authorities for the user. +-A random password will be generated internally, preventing you from accidentally using this user data as an authentication source elsewhere in your configuration. +- ++You should be able to login by using the `myopenid.com` site to authenticate. ++You can also select a specific `UserDetailsService` bean for use with OpenID by setting the `user-service-ref` attribute on the `openid-login` element. ++Note that we have omitted the password attribute from the above user configuration, since this set of user data is being used only to load the authorities for the user. ++A random password is generated internally, preventing you from accidentally using this user data as an authentication source elsewhere in your configuration. + + === 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: ++Spring Security includes support for OpenID https://openid.net/specs/openid-attribute-exchange-1_0.html[attribute exchange]. ++As an example, the following configuration tries to retrieve the email and full name from the OpenID provider for use by the application: + ++==== + [source,xml] + ---- + +@@ -40,21 +43,24 @@ As an example, the following configuration would attempt to retrieve the email a + + + ---- ++==== + +-The "type" of each OpenID attribute is a URI, determined by a particular schema, in this case https://axschema.org/[https://axschema.org/]. +-If an attribute must be retrieved for successful authentication, the `required` attribute can be set. +-The exact schema and attributes supported will depend on your OpenID provider. +-The attribute values are returned as part of the authentication process and can be accessed afterwards using the following code: ++The "`type`" of each OpenID attribute is a URI, determined by a particular schema -- in this case, https://axschema.org/[https://axschema.org/]. ++If an attribute must be retrieved for successful authentication, you can set the `required` attribute. ++The exact schema and attributes supported depend on your OpenID provider. ++The attribute values are returned as part of the authentication process and can be accessed afterwards by using the following code: + ++==== + [source,java] + ---- + OpenIDAuthenticationToken token = + (OpenIDAuthenticationToken)SecurityContextHolder.getContext().getAuthentication(); + List attributes = token.getAttributes(); + ---- ++==== + + We can obtain the `OpenIDAuthenticationToken` from the <>. + The `OpenIDAttribute` contains the attribute type and the retrieved value (or values in the case of multi-valued attributes). +-You can supply multiple `attribute-exchange` elements, using an `identifier-matcher` attribute on each. +-This contains a regular expression which will be matched against the OpenID identifier supplied by the user. +-See the OpenID sample application in the codebase for an example configuration, providing different attribute lists for the Google, Yahoo and MyOpenID providers. ++You can supply multiple `attribute-exchange` elements by using an `identifier-matcher` attribute on each element. ++This contains a regular expression that is matched against the OpenID identifier supplied by the user. ++See the {gh-samples-url}/boot/oauth2login[OpenID sample application] in the codebase for an example configuration, providing different attribute lists for the Google, Yahoo and MyOpenID providers. +diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/preauth.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/preauth.adoc +index c50de6379f..ae6a079912 100644 +--- a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/preauth.adoc ++++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/preauth.adoc +@@ -1,33 +1,29 @@ + [[servlet-preauth]] + == 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. +-When using pre-authentication, Spring Security has to ++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 runs. ++When using pre-authentication, Spring Security has to: + + * Identify the user making the request. +- + * Obtain the authorities for the user. + +- +-The details will depend on the external authentication mechanism. ++The details depend on the external authentication mechanism. + A user might be identified by their certificate information in the case of X.509, or by an HTTP request header in the case of Siteminder. +-If relying on container authentication, the user will be identified by calling the `getUserPrincipal()` method on the incoming HTTP request. +-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`. +- ++If relying on container authentication, the user is identified by calling the `getUserPrincipal()` method on the incoming HTTP request. ++In some cases, the external mechanism may supply role and authority information for the user. However, in other cases, you must obtain the authorities from a separate source, such as a `UserDetailsService`. + + === 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 <>, as it already has a namespace configuration option which is simpler to use and get started with. +-If you need to use explicit bean configuration or are planning on writing your own implementation then an understanding of how the provided implementations work will be useful. +-You will find classes under the `org.springframework.security.web.authentication.preauth`. +-We just provide an outline here so you should consult the Javadoc and source where appropriate. +- ++Because most pre-authentication mechanisms follow the same pattern, Spring Security has a set of classes that provide an internal framework for implementing pre-authenticated authentication providers. ++This removes duplication and lets new implementations be added in a structured fashion, without having to write everything from scratch. ++You need not know about these classes if you want to use something like <>, as it already has a namespace configuration option which is simpler to use and get started with. ++If you need to use explicit bean configuration or are planning on writing your own implementation, you need an understanding of how the provided implementations work. ++You can find the classes under the `org.springframework.security.web.authentication.preauth`. ++We provide only an outline here, so you should consult the Javadoc and source where appropriate. + + ==== 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: ++This class checks the current contents of the security context and, if it is empty, tries to extract user information from the HTTP request and submit it to the `AuthenticationManager`. ++Subclasses override the following methods to obtain this information. + + .Override AbstractPreAuthenticatedProcessingFilter + ==== +@@ -49,24 +45,24 @@ protected abstract fun getPreAuthenticatedCredentials(request: HttpServletReques + ==== + + +-After calling these, the filter will create a `PreAuthenticatedAuthenticationToken` containing the returned data and submit it for authentication. +-By "authentication" here, we really just mean further processing to perhaps load the user's authorities, but the standard Spring Security authentication architecture is followed. ++After calling these, the filter creates a `PreAuthenticatedAuthenticationToken` that contains the returned data and submits it for authentication. ++By "`authentication`" here, we really just mean further processing to perhaps load the user's authorities, but the standard Spring Security authentication architecture is followed. + +-Like other Spring Security authentication filters, the pre-authentication filter has an `authenticationDetailsSource` property which by default will create a `WebAuthenticationDetails` object to store additional information such as the session-identifier and originating IP address in the `details` property of the `Authentication` object. ++As other Spring Security authentication filters, the pre-authentication filter has an `authenticationDetailsSource` property, which, by default, creates a `WebAuthenticationDetails` object to store additional information, such as the session identifier and the originating IP address in the `details` property of the `Authentication` object. + In cases where user role information can be obtained from the pre-authentication mechanism, the data is also stored in this property, with the details implementing the `GrantedAuthoritiesContainer` interface. + This enables the authentication provider to read the authorities which were externally allocated to the user. +-We'll look at a concrete example next. ++We look at a concrete example next. + + + [[j2ee-preauth-details]] + ===== 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". ++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 `` information in a `web.xml` file. + The pre-authentication sample application uses the latter approach. + +-There is an additional stage where the roles (or attributes) are mapped to Spring Security `GrantedAuthority` objects using a configured `Attributes2GrantedAuthoritiesMapper`. +-The default will just add the usual `ROLE_` prefix to the names, but it gives you full control over the behaviour. ++There is an additional stage where the roles (or attributes) are mapped to Spring Security `GrantedAuthority` objects by using a configured `Attributes2GrantedAuthoritiesMapper`. ++The default just adds the usual `ROLE_` prefix to the names, but it gives you full control over the behavior. + + + ==== PreAuthenticatedAuthenticationProvider +@@ -74,45 +70,43 @@ The pre-authenticated provider has little more to do than load the `UserDetails` + 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: + ++==== + [source,java] + ---- + public interface AuthenticationUserDetailsService { + UserDetails loadUserDetails(Authentication token) throws UsernameNotFoundException; + } + ---- ++==== + +-This interface may have also other uses but with pre-authentication it allows access to the authorities which were packaged in the `Authentication` object, as we saw in the previous section. ++This interface may also have other uses, but, with pre-authentication, it allows access to the authorities that were packaged in the `Authentication` object, as we saw in the previous section. + The `PreAuthenticatedGrantedAuthoritiesUserDetailsService` class does this. +-Alternatively, it may delegate to a standard `UserDetailsService` via the `UserDetailsByNameServiceWrapper` implementation. ++Alternatively, it may delegate to a standard `UserDetailsService` through the `UserDetailsByNameServiceWrapper` implementation. + + ==== Http403ForbiddenEntryPoint +-The <> 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. ++The <> is responsible for kick-starting the authentication process for an unauthenticated user (when they try to access a protected resource). However, in the pre-authenticated case, this does not apply. ++You would only configure the `ExceptionTranslationFilter` with an instance of this class if you do not use pre-authentication in combination with other authentication mechanisms. ++It is 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 + X.509 authentication is covered in its <>. +-Here we'll look at some classes which provide support for other pre-authenticated scenarios. +- ++Here, we look at some classes which provide support for other pre-authenticated scenarios. + + ==== 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. +-It defaults to using the name `SM_USER` as the header name. ++This mechanism is supported by the `RequestHeaderAuthenticationFilter` class, which only extracts the username from the header. ++It defaults to using a name of `SM_USER` as the header name. + See the Javadoc for more details. + +-[TIP] +-==== +-Note that when using a system like this, the framework performs no authentication checks at all and it is __extremely__ important that the external system is configured properly and protects all access to the application. +-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. +-==== ++TIP: When using a system like this, the framework performs no authentication checks at all, and it is _extremely_ important that the external system is configured properly and protects all access to the application. ++If an attacker is able to forge the headers in their original request without this being detected, they could potentially choose any username they wished. + + ===== Siteminder Example Configuration +-A typical configuration using this filter would look like this: ++The following example shows a typical configuration that uses this filter: + ++==== + [source,xml] + ---- + +@@ -138,14 +132,14 @@ A typical configuration using this filter would look like this: + + + ---- ++==== + +-We've assumed here that the <> is being used for configuration. +-It's also assumed that you have added a `UserDetailsService` (called "userDetailsService") to your configuration to load the user's roles. +- ++We have assumed here that the <> is being used for configuration. ++It is also assumed that you have added a `UserDetailsService` (called `userDetailsService`) to your configuration to load the user's roles. + + ==== 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 <>. ++The `J2eePreAuthenticatedProcessingFilter` class extracts 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 earlier in <>. + +-There is a sample application in the codebase which uses this approach, so get hold of the code from github and have a look at the application context file if you are interested. ++There is a sample application that uses this approach in the codebase, so get hold of the code from Github and have a look at the application context file if you are interested. + The code is in the `samples/xml/preauth` directory. +diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/rememberme.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/rememberme.adoc +index 25f6fd791d..541d86535f 100644 +--- a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/rememberme.adoc ++++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/rememberme.adoc +@@ -1,23 +1,22 @@ + [[servlet-rememberme]] + == Remember-Me Authentication + +- + [[remember-me-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. ++Spring Security provides the necessary hooks for these operations to take place and has two concrete remember-me implementations. + One uses hashing to preserve the security of cookie-based tokens and the other uses a database or other persistent storage mechanism to store the generated tokens. + + Note that both implementations require a `UserDetailsService`. +-If you are using an authentication provider which doesn't use a `UserDetailsService` (for example, the LDAP provider) then it won't work unless you also have a `UserDetailsService` bean in your application context. ++If you use an authentication provider that does not use a `UserDetailsService` (for example, the LDAP provider), it does not work unless you also have a `UserDetailsService` bean in your application context. + + + [[remember-me-hash-token]] + === 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: ++In essence, a cookie is sent to the browser upon successful interactive authentication, with the cookie being composed as follows: + ++==== + [source,txt] + ---- + base64(username + ":" + expirationTime + ":" + +@@ -28,16 +27,18 @@ password: That matches the one in the retrieved UserDetails + expirationTime: The date and time when the remember-me token expires, expressed in milliseconds + key: A private key to prevent modification of the remember-me token + ---- ++==== + +-As such the remember-me token is valid only for the period specified, and provided that the username, password and key does not change. +-Notably, this has a potential security issue in that a captured remember-me token will be usable from any user agent until such time as the token expires. +-This is the same issue as with digest authentication. +-If a principal is aware a token has been captured, they can easily change their password and immediately invalidate all remember-me tokens on issue. +-If more significant security is needed you should use the approach described in the next section. +-Alternatively remember-me services should simply not be used at all. ++The remember-me token is valid only for the period specified and only if the username, password, and key do not change. ++Notably, this has a potential security issue, in that a captured remember-me token is usable from any user agent until such time as the token expires. ++This is the same issue as with <>. ++If a principal is aware that a token has been captured, they can easily change their password and immediately invalidate all remember-me tokens on issue. ++If more significant security is needed, you should use the approach described in the next section. ++Alternatively, remember-me services should not be used at all. + +-If you are familiar with the topics discussed in the chapter on <>, you can enable remember-me authentication just by adding the `` element: ++If you are familiar with the topics discussed in the chapter on <>, you can enable remember-me authentication by adding the `` element: + ++==== + [source,xml] + ---- + +@@ -45,16 +46,18 @@ If you are familiar with the topics discussed in the chapter on < + + ---- ++==== + +-The `UserDetailsService` will normally be selected automatically. ++The `UserDetailsService` is normally 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 +-This approach is based on the article 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: ++This approach is based on the article titled http://jaspan.com/improved_persistent_login_cookie_best_practice[http://jaspan.com/improved_persistent_login_cookie_best_practice], with some minor modifications. (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, supply a datasource reference: + ++==== + [source,xml] + ---- + +@@ -62,9 +65,11 @@ To use the this approach with namespace configuration, you would supply a dataso + + + ---- ++==== + +-The database should contain a `persistent_logins` table, created using the following SQL (or equivalent): ++The database should contain a `persistent_logins` table, created by using the following SQL (or equivalent): + ++==== + [source,ddl] + ---- + create table persistent_logins (username varchar(64) not null, +@@ -72,14 +77,16 @@ create table persistent_logins (username varchar(64) not null, + token varchar(64) not null, + last_used timestamp not null) + ---- ++==== + + [[remember-me-impls]] + === Remember-Me Interfaces and Implementations +-Remember-me is used with `UsernamePasswordAuthenticationFilter`, and is implemented via hooks in the `AbstractAuthenticationProcessingFilter` superclass. ++Remember-me is used with `UsernamePasswordAuthenticationFilter` and is implemented through hooks in the `AbstractAuthenticationProcessingFilter` superclass. + It is also used within `BasicAuthenticationFilter`. +-The hooks will invoke a concrete `RememberMeServices` at the appropriate times. +-The interface looks like this: ++The hooks invoke a concrete `RememberMeServices` at the appropriate times. ++The following listing shows the interface: + ++==== + [source,java] + ---- + Authentication autoLogin(HttpServletRequest request, HttpServletResponse response); +@@ -89,24 +96,27 @@ void loginFail(HttpServletRequest request, HttpServletResponse response); + void loginSuccess(HttpServletRequest request, HttpServletResponse response, + Authentication successfulAuthentication); + ---- ++==== + +-Please refer to the Javadoc for a fuller discussion on what the methods do, although note at this stage that `AbstractAuthenticationProcessingFilter` only calls the `loginFail()` and `loginSuccess()` methods. ++See the Javadoc for {security-api-url}org/springframework/security/web/authentication/RememberMeServices.html[`RememberMeServices`] for a fuller discussion on what the methods do, although note that, at this stage, `AbstractAuthenticationProcessingFilter` calls only the `loginFail()` and `loginSuccess()` methods. + The `autoLogin()` method is called by `RememberMeAuthenticationFilter` whenever the `SecurityContextHolder` does not contain an `Authentication`. +-This interface therefore provides the underlying remember-me implementation with sufficient notification of authentication-related events, and delegates to the implementation whenever a candidate web request might contain a cookie and wish to be remembered. ++This interface, therefore, provides the underlying remember-me implementation with sufficient notification of authentication-related events and delegates to the implementation whenever a candidate web request might contain a cookie and wish to be remembered. + 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. ++ ++We have seen earlier that Spring Security provides two implementations. ++We look at each of these in turn. + + ==== TokenBasedRememberMeServices + This implementation supports the simpler approach described in <>. + `TokenBasedRememberMeServices` generates a `RememberMeAuthenticationToken`, which is processed by `RememberMeAuthenticationProvider`. + A `key` is shared between this authentication provider and the `TokenBasedRememberMeServices`. +-In addition, `TokenBasedRememberMeServices` requires A UserDetailsService from which it can retrieve the username and password for signature comparison purposes, and generate the `RememberMeAuthenticationToken` to contain the correct `GrantedAuthority` s. ++In addition, `TokenBasedRememberMeServices` requires a `UserDetailsService`, from which it can retrieve the username and password for signature comparison purposes and generate the `RememberMeAuthenticationToken` to contain the correct `GrantedAuthority` instances. + Some sort of logout command should be provided by the application that invalidates the cookie if the user requests this. +-`TokenBasedRememberMeServices` also implements Spring Security's `LogoutHandler` interface so can be used with `LogoutFilter` to have the cookie cleared automatically. ++`TokenBasedRememberMeServices` also implements Spring Security's `LogoutHandler` interface so that it can be used with `LogoutFilter` to have the cookie cleared automatically. + +-The beans required in an application context to enable remember-me services are as follows: ++The following beans are required in an application context to enable remember-me services: + ++==== + [source,xml] + ---- + + + ---- ++==== + +-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`). ++Remember 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 +-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. ++You can use this class 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. + +-* `InMemoryTokenRepositoryImpl` which is intended for testing only. +-* `JdbcTokenRepositoryImpl` which stores the tokens in a database. ++* `InMemoryTokenRepositoryImpl`, which is intended for testing only. ++* `JdbcTokenRepositoryImpl`, which stores the tokens in a database. + +-The database schema is described above in <>. ++See <> for the database schema. +diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/runas.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/runas.adoc +index 8eb5de89ec..4cc1495782 100644 +--- a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/runas.adoc ++++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/runas.adoc +@@ -2,19 +2,19 @@ + == Run-As Authentication Replacement + + [[runas-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`. ++The `RunAsManager` indicates the replacement `Authentication` object, if any, that should be used during the `SecurityInterceptorCallback`. + +-By temporarily replacing the `Authentication` object during the secure object callback phase, the secured invocation will be able to call other objects which require different authentication and authorization credentials. +-It will also be able to perform any internal security checks for specific `GrantedAuthority` objects. ++By temporarily replacing the `Authentication` object during the secure object callback phase, the secured invocation can call other objects that require different authentication and authorization credentials. ++It can also perform any internal security checks for specific `GrantedAuthority` objects. + 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 +-A `RunAsManager` interface is provided by Spring Security: ++Spring Security provices a `RunAsManager` interface: + ++==== + [source,java] + ---- + Authentication buildRunAs(Authentication authentication, Object object, +@@ -24,31 +24,30 @@ boolean supports(ConfigAttribute attribute); + + boolean supports(Class clazz); + ---- +- +- ++==== + + The first method returns the `Authentication` object that should replace the existing `Authentication` object for the duration of the method invocation. + If the method returns `null`, it indicates no replacement should be made. + The second method is used by the `AbstractSecurityInterceptor` as part of its startup validation of configuration attributes. +-The `supports(Class)` method is called by a security interceptor implementation to ensure the configured `RunAsManager` supports the type of secure object that the security interceptor will present. ++The `supports(Class)` method is called by a security interceptor implementation to ensure that the configured `RunAsManager` supports the type of secure object that the security interceptor presents. + +-One concrete implementation of a `RunAsManager` is provided with Spring Security. ++Spring Security provides one concrete implementation of `RunAsManager`. + The `RunAsManagerImpl` class returns a replacement `RunAsUserToken` if any `ConfigAttribute` starts with `RUN_AS_`. +-If any such `ConfigAttribute` is found, the replacement `RunAsUserToken` will contain the same principal, credentials and granted authorities as the original `Authentication` object, along with a new `SimpleGrantedAuthority` for each `RUN_AS_` `ConfigAttribute`. +-Each new `SimpleGrantedAuthority` will be prefixed with `ROLE_`, followed by the `RUN_AS` `ConfigAttribute`. +-For example, a `RUN_AS_SERVER` will result in the replacement `RunAsUserToken` containing a `ROLE_RUN_AS_SERVER` granted authority. ++If any such `ConfigAttribute` is found, the replacement `RunAsUserToken` contains the same principal, credentials, and granted authorities as the original `Authentication` object, along with a new `SimpleGrantedAuthority` for each `RUN_AS_` `ConfigAttribute`. ++Each new `SimpleGrantedAuthority` is prefixed with `ROLE_`, followed by the `RUN_AS` `ConfigAttribute`. ++For example, a `RUN_AS_SERVER` results in the replacement `RunAsUserToken` containing a `ROLE_RUN_AS_SERVER` granted authority. + +-The replacement `RunAsUserToken` is just like any other `Authentication` object. +-It needs to be authenticated by the `AuthenticationManager`, probably via delegation to a suitable `AuthenticationProvider`. ++The replacement `RunAsUserToken` is like any other `Authentication` object. ++It needs to be authenticated by the `AuthenticationManager`, probably through delegation to a suitable `AuthenticationProvider`. + The `RunAsImplAuthenticationProvider` performs such authentication. +-It simply accepts as valid any `RunAsUserToken` presented. ++It accepts as valid any `RunAsUserToken` presented. + + To ensure malicious code does not create a `RunAsUserToken` and present it for guaranteed acceptance by the `RunAsImplAuthenticationProvider`, the hash of a key is stored in all generated tokens. + The `RunAsManagerImpl` and `RunAsImplAuthenticationProvider` is created in the bean context with the same key: + ++==== + [source,xml] + ---- +- + + +@@ -59,8 +58,7 @@ The `RunAsManagerImpl` and `RunAsImplAuthenticationProvider` is created in the b + + + ---- ++==== + +- +- +-By using the same key, each `RunAsUserToken` can be validated it was created by an approved `RunAsManagerImpl`. +-The `RunAsUserToken` is immutable after creation for security reasons ++By using the same key, each `RunAsUserToken` can be validated because it was created by an approved `RunAsManagerImpl`. ++The `RunAsUserToken` is immutable after creation, for security reasons. +diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/session-management.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/session-management.adoc +index 2250445a73..0916bd138f 100644 +--- a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/session-management.adoc ++++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/session-management.adoc +@@ -1,12 +1,13 @@ + [[session-mgmt]] + == 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. ++HTTP session-related functionality is handled by a combination of the {security-api-url}org/springframework/security/authentication/AuthenticationProvider.html[`SessionManagementFilter`] and the {security-api-url}org/springframework/security/web/authentication/session/SessionAuthenticationStrategy.html[`SessionAuthenticationStrategy`] interface, to which the filter delegates. ++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 + 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: ++To do so, configure the `session-management` element: + ++==== + [source,xml] + ---- + +@@ -14,25 +15,29 @@ This is achieved through the `session-management` element: + + + ---- ++==== + +-Note that if you use this mechanism to detect session timeouts, it may falsely report an error if the user logs out and then logs back in without closing the browser. +-This is because the session cookie is not cleared when you invalidate the session and will be resubmitted even if the user has logged out. +-You may be able to explicitly delete the JSESSIONID cookie on logging out, for example by using the following syntax in the logout handler: ++Note that, if you use this mechanism to detect session timeouts, it may falsely report an error if the user logs out and then logs back in without closing the browser. ++This is because the session cookie is not cleared when you invalidate the session and is resubmitted even if the user has logged out. ++You may be able to explicitly delete the `JSESSIONID` cookie on logging out -- for example, by using the following syntax in the logout handler: + ++==== + [source,xml] + ---- + + + + ---- ++==== + +-Unfortunately this can't be guaranteed to work with every servlet container, so you will need to test it in your environment ++Unfortunately, this cannot be guaranteed to work with every servlet container, so you need to test it in your environment. + + [NOTE] +-==== +-If you are running your application behind a proxy, you may also be able to remove the session cookie by configuring the proxy server. +-For example, using Apache HTTPD's mod_headers, the following directive would delete the `JSESSIONID` cookie by expiring it in the response to a logout request (assuming the application is deployed under the path `/tutorial`): ++===== ++If you run your application behind a proxy, you may also be able to remove the session cookie by configuring the proxy server. ++For example, by using Apache HTTPD's `mod_headers`, the following directive deletes the `JSESSIONID` cookie by expiring it in the response to a logout request (assuming the application is deployed under the `/tutorial` path): + ++==== + [source,xml] + ---- + +@@ -40,13 +45,15 @@ Header always set Set-Cookie "JSESSIONID=;Path=/tutorial;Expires=Thu, 01 Jan 197 + + ---- + ==== ++===== + + + [[ns-concurrent-sessions]] + === 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 `web.xml` file to keep Spring Security updated about session lifecycle events: ++If you wish to place constraints on a single user's ability to log in to your application, Spring Security supports this with the following simple additions. ++First, you need to add the following listener to your `web.xml` file to keep Spring Security updated about session lifecycle events: + ++==== + [source,xml] + ---- + +@@ -55,9 +62,11 @@ First you need to add the following listener to your `web.xml` file to keep Spri + + + ---- ++==== + + Then add the following lines to your application context: + ++==== + [source,xml] + ---- + +@@ -67,10 +76,12 @@ Then add the following lines to your application context: + + + ---- ++==== + +-This will prevent a user from logging in multiple times - a second login will cause the first to be invalidated. +-Often you would prefer to prevent a second login, in which case you can use ++These changes prevent a user from logging in multiple times. A second login causes the first to be invalidated. ++Often, you would prefer to prevent a second login. In that case, you can use: + ++==== + [source,xml] + ---- + +@@ -80,61 +91,61 @@ Often you would prefer to prevent a second login, in which case you can use + + + ---- ++==== + +-The second login will then be rejected. +-By "rejected", we mean that the user will be sent to the `authentication-failure-url` if form-based login is being used. +-If the second authentication takes place through another non-interactive mechanism, such as "remember-me", an "unauthorized" (401) error will be sent to the client. +-If instead you want to use an error page, you can add the attribute `session-authentication-error-url` to the `session-management` element. ++The second login is then rejected. ++By "`rejected`", we mean that the user is sent to the `authentication-failure-url` if form-based login is being used. ++If the second authentication takes place through another non-interactive mechanism, such as "`remember-me`", an "`unauthorized`" (401) error is sent to the client. ++If, instead, you want to use an error page, you can add the `session-authentication-error-url` attribute to the `session-management` element. + +-If you are using a customized authentication filter for form-based login, then you have to configure concurrent session control support explicitly. +-More details can be found in the <>. ++If you use a customized authentication filter for form-based login, you have to configure concurrent session control support explicitly. ++You can find more details in the <>. + + [[ns-session-fixation]] + === 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 ``, which has four options ++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 and 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 automatically protects against this by creating a new session or otherwise changing the session ID when a user logs in. ++If you do not require this protection or it conflicts with some other requirement, you can control the behavior setting the `session-fixation-protection` attribute on ``, which has four options + +-* `none` - Don't do anything. +-The original session will be retained. ++* `none`: Do nothing. ++The original session is retained. + +-* `newSession` - Create a new "clean" session, without copying the existing session data (Spring Security-related attributes will still be copied). ++* `newSession`: Create a new, "`clean`" session, without copying the existing session data (Spring Security-related attributes are still copied). + +-* `migrateSession` - Create a new session and copy all existing session attributes to the new session. ++* `migrateSession`: Create a new session and copy all existing session attributes to the new session. + This is the default in Servlet 3.0 or older containers. + +-* `changeSessionId` - Do not create a new session. ++* `changeSessionId`: Do not create a new session. + Instead, use the session fixation protection provided by the Servlet container (`HttpServletRequest#changeSessionId()`). +-This option is only available in Servlet 3.1 (Java EE 7) and newer containers. +-Specifying it in older containers will result in an exception. +-This is the default in Servlet 3.1 and newer containers. +- ++This option is available only in Servlet 3.1 (Java EE 7) and newer containers, where it is the default. ++Specifying it in older containers results in an exception. + + When session fixation protection occurs, it results in a `SessionFixationProtectionEvent` being published in the application context. +-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. ++If you use `changeSessionId`, this protection will _also_ result in any `javax.servlet.http.HttpSessionIdListener` instances being notified, so use caution if your code listens for both events. + See the <> chapter for additional information. + + === 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. ++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 ++ ++NOTE: Authentication by mechanisms that perform a redirect after authenticating (such as form-login) are not detected by `SessionManagementFilter`, as the filter is not invoked during the authenticating request. + Session-management functionality has to be handled separately in these cases. +-]. ++ + If the repository contains a security context, the filter does nothing. +-If it doesn't, and the thread-local `SecurityContext` contains a (non-anonymous) `Authentication` object, the filter assumes they have been authenticated by a previous filter in the stack. +-It will then invoke the configured `SessionAuthenticationStrategy`. ++If it does not and the thread-local `SecurityContext` contains a (non-anonymous) `Authentication` object, the filter assumes they have been authenticated by a previous filter in the stack. ++It then invokes the configured `SessionAuthenticationStrategy`. + +-If the user is not currently authenticated, the filter will check whether an invalid session ID has been requested (because of a timeout, for example) and will invoke the configured `InvalidSessionStrategy`, if one is set. +-The most common behaviour is just to redirect to a fixed URL and this is encapsulated in the standard implementation `SimpleRedirectInvalidSessionStrategy`. +-The latter is also used when configuring an invalid session URL through the namespace,<>. ++If the user is not currently authenticated, the filter checks whether an invalid session ID has been requested (because of a timeout, for example) and invokes the configured `InvalidSessionStrategy`, if one is set. ++The most common behavior is to redirect to a fixed URL, and this is encapsulated in the standard implementation (`SimpleRedirectInvalidSessionStrategy`). ++The latter is also used when configuring an invalid session URL through the namespace, <>. + + + === 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: ++`SessionAuthenticationStrategy` is used by both `SessionManagementFilter` and `AbstractAuthenticationProcessingFilter`, so, if you are using a customized form-login class, for example, you need to inject it into both of these. ++In this case, a typical configuration that combines the namespace and custom beans might look like this: + ++==== + [source,xml] + ---- +- + + + +@@ -148,56 +159,53 @@ In this case, a typical configuration, combining the namespace and custom beans + + +- + ---- ++==== + +-Note that the use of the default, `SessionFixationProtectionStrategy` may cause issues if you are storing beans in the session which implement `HttpSessionBindingListener`, including Spring session-scoped beans. +-See the Javadoc for this class for more information. ++Note that the use of the default, `SessionFixationProtectionStrategy`, may cause issues if you are storing beans in the session that implement `HttpSessionBindingListener`, including Spring session-scoped beans. ++See the Javadoc for this Java class for more information. + + [[concurrent-sessions]] + === 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. ++Spring Security can 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, while 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. + You can either expire their previous login or you can report an error when they try to log in again, preventing the second login. +-Note that if you are using the second approach, a user who has not explicitly logged out (but who has just closed their browser, for example) will not be able to log in again until their original session expires. ++Note that, if you use the second approach, a user who has not explicitly logged out (but who has just closed their browser, for example) cannot log in again until their original session expires. + ++//FIXME: Add a link to the namespace chapter. + Concurrency control is supported by the namespace, so please check the earlier namespace chapter for the simplest configuration. +-Sometimes you need to customize things though. ++Sometimes, though, you need to customize things. + + The implementation uses a specialized version of `SessionAuthenticationStrategy`, called `ConcurrentSessionControlAuthenticationStrategy`. +-[NOTE] +-==== + +-Previously the concurrent authentication check was made by the `ProviderManager`, which could be injected with a `ConcurrentSessionController`. ++NOTE: Previously, the concurrent authentication check was made by the `ProviderManager`, which could be injected with a `ConcurrentSessionController`. + The latter would check if the user was attempting to exceed the number of permitted sessions. + However, this approach required that an HTTP session be created in advance, which is undesirable. +-In Spring Security 3, the user is first authenticated by the `AuthenticationManager` and once they are successfully authenticated, a session is created and the check is made whether they are allowed to have another session open. +- +-==== ++In Spring Security 3 and later, the user is first authenticated by the `AuthenticationManager` and once they are successfully authenticated, a session is created and the check is made whether they are allowed to have another session open. + ++To use concurrent session support, you need to add the following to `web.xml`: + +-To use concurrent session support, you'll need to add the following to `web.xml`: +- ++==== + [source,xml] + ---- +- + + + org.springframework.security.web.session.HttpSessionEventPublisher + + + ---- ++==== + ++In addition, you need to add the `ConcurrentSessionFilter` to your `FilterChainProxy`. ++The `ConcurrentSessionFilter` requires two constructor arguments: ++* `sessionRegistry`, which generally points to an instance of `SessionRegistryImpl` ++* `sessionInformationExpiredStrategy`, which defines the strategy to apply when a session has expired ++The following sample configuration uses the namespace to create the `FilterChainProxy` and other default beans: + +- +-In addition, you will need to add the `ConcurrentSessionFilter` to your `FilterChainProxy`. +-The `ConcurrentSessionFilter` requires two constructor arguments, `sessionRegistry`, which generally points to an instance of `SessionRegistryImpl`, and `sessionInformationExpiredStrategy`, which defines the strategy to apply when a session has expired. +-A configuration using the namespace to create the `FilterChainProxy` and other default beans might look like this: +- ++==== + [source,xml] + ---- +- + + + +@@ -241,25 +249,22 @@ class="org.springframework.security.web.session.ConcurrentSessionFilter"> + + +- + ---- +- +- ++==== + + Adding the listener to `web.xml` causes an `ApplicationEvent` to be published to the Spring `ApplicationContext` every time a `HttpSession` commences or ends. +-This is critical, as it allows the `SessionRegistryImpl` to be notified when a session ends. +-Without it, a user will never be able to log back in again once they have exceeded their session allowance, even if they log out of another session or it times out. +- ++This is critical, as it lets the `SessionRegistryImpl` be notified when a session ends. ++Without it, a user can never log back in again once they have exceeded their session allowance, even if they log out of another session or it times out. + + [[list-authenticated-principals]] + ==== 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. ++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` that you can use directly within your application. So, even if you do not 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 use the namespace, you can set an alias for the internally-created `SessionRegistry` by using the `session-registry-alias` attribute, providing a reference that you can inject into your own beans. + + The `getAllPrincipals()` method supplies you with a list of the currently authenticated users. + You can list a user's sessions by calling the `getAllSessions(Object principal, boolean includeExpiredSessions)` method, which returns a list of `SessionInformation` objects. + You can also expire a user's session by calling `expireNow()` on a `SessionInformation` instance. +-When the user returns to the application, they will be prevented from proceeding. ++When the user returns to the application, they are prevented from proceeding. + You may find these methods useful in an administration application, for example. +-Have a look at the Javadoc for more information. ++See the Javadoc for more information about the {security-api-url}org/springframework/security/core/session/SessionRegistry.html[`SessionRegistry`] interface. +diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/basic.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/basic.adoc +index aa2ff02f29..02a746d3b4 100644 +--- a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/basic.adoc ++++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/basic.adoc +@@ -1,60 +1,61 @@ + [[servlet-authentication-basic]] + = Basic Authentication + +-This section provides details on how Spring Security provides support for https://tools.ietf.org/html/rfc7617[Basic HTTP Authentication] for servlet based applications. ++This section provides details on how Spring Security provides support for https://tools.ietf.org/html/rfc7617[Basic HTTP Authentication] for servlet-based applications. + // FIXME: describe authenticationentrypoint, authenticationfailurehandler, authenticationsuccesshandler + +-Let's take a look at how HTTP Basic Authentication works within Spring Security. +-First, we see the https://tools.ietf.org/html/rfc7235#section-4.1[WWW-Authenticate] header is sent back to an unauthenticated client. ++This section describes how HTTP Basic Authentication works within Spring Security. ++First, we see the https://tools.ietf.org/html/rfc7235#section-4.1[WWW-Authenticate] header is sent back to an unauthenticated client: + + .Sending WWW-Authenticate Header + image::{figures}/basicauthenticationentrypoint.png[] + +-The figure builds off our <> diagram. ++The preceding figure builds off our <> diagram. + + 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 <> indicates that the unauthenticated request is __Denied__ by throwing an `AccessDeniedException`. + + image:{icondir}/number_3.png[] Since the user is not authenticated, <> initiates __Start Authentication__. +-The configured <> is an instance of {security-api-url}org/springframework/security/web/authentication/www/BasicAuthenticationEntryPoint.html[`BasicAuthenticationEntryPoint`] which sends a WWW-Authenticate header. ++The configured <> is an instance of {security-api-url}org/springframework/security/web/authentication/www/BasicAuthenticationEntryPoint.html[`BasicAuthenticationEntryPoint`], which sends a WWW-Authenticate header. + The `RequestCache` is typically a `NullRequestCache` that does not save the request since the client is capable of replaying the requests it originally requested. + +-When a client receives the WWW-Authenticate header it knows it should retry with a username and password. +-Below is the flow for the username and password being processed. ++When a client receives the `WWW-Authenticate` header, it knows it should retry with a username and password. ++The following image shows the flow for the username and password being processed: + + [[servlet-authentication-basicauthenticationfilter]] + .Authenticating Username and Password + image::{figures}/basicauthenticationfilter.png[] + +-The figure builds off our <> diagram. ++The preceding figure builds off our <> diagram. + +- +-image:{icondir}/number_1.png[] When the user submits their username and password, the `BasicAuthenticationFilter` creates a `UsernamePasswordAuthenticationToken` which is a type of <> by extracting the username and password from the `HttpServletRequest`. ++image:{icondir}/number_1.png[] When the user submits their username and password, the `BasicAuthenticationFilter` creates a `UsernamePasswordAuthenticationToken`, which is a type of <> by extracting the username and password from the `HttpServletRequest`. + + image:{icondir}/number_2.png[] Next, the `UsernamePasswordAuthenticationToken` is passed into the `AuthenticationManager` to be authenticated. + The details of what `AuthenticationManager` look like depend on how the <>. + +-image:{icondir}/number_3.png[] If authentication fails, then __Failure__ ++image:{icondir}/number_3.png[] If authentication fails, then __Failure__. + +-* The <> is cleared out. +-* `RememberMeServices.loginFail` is invoked. ++. The <> is cleared out. ++. `RememberMeServices.loginFail` is invoked. + If remember me is not configured, this is a no-op. +-// FIXME: link to rememberme +-* `AuthenticationEntryPoint` is invoked to trigger the WWW-Authenticate to be sent again. ++See the {security-api-url}org/springframework/security/web/authentication/RememberMeServices.html[`RememberMeServices`] interface in the Javadoc. ++. `AuthenticationEntryPoint` is invoked to trigger the WWW-Authenticate to be sent again. ++See the {security-api-url}org/springframework/security/web/AuthenticationEntryPoint.html[`AuthenticationEntryPoint`] interface in the Javadoc. + + image:{icondir}/number_4.png[] If authentication is successful, then __Success__. + +-* The <> is set on the <>. +-* `RememberMeServices.loginSuccess` is invoked. ++. The <> is set on the <>. ++. `RememberMeServices.loginSuccess` is invoked. + If remember me is not configured, this is a no-op. +-// FIXME: link to rememberme +-* The `BasicAuthenticationFilter` invokes `FilterChain.doFilter(request,response)` to continue with the rest of the application logic. ++See the {security-api-url}org/springframework/security/web/authentication/RememberMeServices.html[`RememberMeServices`] interface in the Javadoc. ++. The `BasicAuthenticationFilter` invokes `FilterChain.doFilter(request,response)` to continue with the rest of the application logic. ++See the {security-api-url}org/springframework/security/web/authentication/www/BasicAuthenticationFilter.html[`BasicAuthenticationFilter`] Class in the Javadoc + +-Spring Security's HTTP Basic Authentication support in is enabled by default. ++By default, Spring Security's HTTP Basic Authentication support is enabled. + However, as soon as any servlet based configuration is provided, HTTP Basic must be explicitly provided. + +-A minimal, explicit configuration can be found below: ++The following example shows a minimal, explicit configuration: + + .Explicit HTTP Basic Configuration + ==== +diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/dao-authentication-provider.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/dao-authentication-provider.adoc +index 3818a019ac..3daf2cb6ac 100644 +--- a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/dao-authentication-provider.adoc ++++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/dao-authentication-provider.adoc +@@ -1,21 +1,21 @@ + [[servlet-authentication-daoauthenticationprovider]] + = DaoAuthenticationProvider + +-{security-api-url}org/springframework/security/authentication/dao/DaoAuthenticationProvider.html[`DaoAuthenticationProvider`] is an <> implementation that leverages a <> and <> to authenticate a username and password. ++{security-api-url}org/springframework/security/authentication/dao/DaoAuthenticationProvider.html[`DaoAuthenticationProvider`] is an <> implementation that uses a <> and <> to authenticate a username and password. + +-Let's take a look at how `DaoAuthenticationProvider` works within Spring Security. +-The figure explains details of how the <> in figures from <> works. ++This section examines how `DaoAuthenticationProvider` works within Spring Security. ++The following figure explains the workings of the <> in figures from the <> section. + + .`DaoAuthenticationProvider` Usage + image::{figures}/daoauthenticationprovider.png[] + +-image:{icondir}/number_1.png[] The authentication `Filter` from <> passes a `UsernamePasswordAuthenticationToken` to the `AuthenticationManager` which is implemented by <>. ++image:{icondir}/number_1.png[] The authentication `Filter` from the <> section passes a `UsernamePasswordAuthenticationToken` to the `AuthenticationManager`, which is implemented by <>. + + image:{icondir}/number_2.png[] The `ProviderManager` is configured to use an <> of type `DaoAuthenticationProvider`. + + image:{icondir}/number_3.png[] `DaoAuthenticationProvider` looks up the `UserDetails` from the `UserDetailsService`. + +-image:{icondir}/number_4.png[] `DaoAuthenticationProvider` then uses the <> to validate the password on the `UserDetails` returned in the previous step. ++image:{icondir}/number_4.png[] `DaoAuthenticationProvider` uses the <> to validate the password on the `UserDetails` returned in the previous step. + + image:{icondir}/number_5.png[] When authentication is successful, the <> that is returned is of type `UsernamePasswordAuthenticationToken` and has a principal that is the `UserDetails` returned by the configured `UserDetailsService`. +-Ultimately, the returned `UsernamePasswordAuthenticationToken` will be set on the <> by the authentication `Filter`. ++Ultimately, the returned `UsernamePasswordAuthenticationToken` is set on the <> by the authentication `Filter`. +diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/digest.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/digest.adoc +index 603db7d93d..565503a29f 100644 +--- a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/digest.adoc ++++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/digest.adoc +@@ -1,26 +1,23 @@ + [[servlet-authentication-digest]] + = Digest Authentication + +-This section provides details on how Spring Security provides support for https://tools.ietf.org/html/rfc2617[Digest Authentication] which is provided `DigestAuthenticationFilter`. ++This section provides details on how Spring Security provides support for https://tools.ietf.org/html/rfc2617[Digest Authentication], which is provided `DigestAuthenticationFilter`. + +-[WARNING] +-==== +-You should not use Digest Authentication in modern applications because it is not considered secure. +-The most obvious problem is that you must store your passwords in plaintext, encrypted, or an MD5 format. ++WARNING: You should not use Digest Authentication in modern applications, because it is not considered to be secure. ++The most obvious problem is that you must store your passwords in plaintext or an encrypted or MD5 format. + All of these storage formats are considered insecure. +-Instead, you should store credentials using a one way adaptive password hash (i.e. bCrypt, PBKDF2, SCrypt, etc) which is not supported by Digest Authentication. +-==== ++Instead, you should store credentials by using a one way adaptive password hash (bCrypt, PBKDF2, SCrypt, and others), which is not supported by Digest Authentication. + +-Digest Authentication attempts to solve many of the weaknesses of <>, specifically by ensuring credentials are never sent in clear text across the wire. ++Digest Authentication tries to solve many of the weaknesses of <>, specifically by ensuring credentials are never sent in clear text across the wire. + Many https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Digest#Browser_compatibility[browsers support Digest Authentication]. + + The standard governing HTTP Digest Authentication is defined by https://tools.ietf.org/html/rfc2617[RFC 2617], which updates an earlier version of the Digest Authentication standard prescribed by https://tools.ietf.org/html/rfc2069[RFC 2069]. + Most user agents implement RFC 2617. + Spring Security's Digest Authentication support is compatible with the "`auth`" quality of protection (`qop`) prescribed by RFC 2617, which also provides backward compatibility with RFC 2069. +-Digest Authentication was seen as a more attractive option if you need to use unencrypted HTTP (i.e. no TLS/HTTPS) and wish to maximise security of the authentication process. ++Digest Authentication was seen as a more attractive option if you need to use unencrypted HTTP (no TLS or HTTPS) and wish to maximize security of the authentication process. + However, everyone should use <>. + +-Central to Digest Authentication is a "nonce". ++Central to Digest Authentication is a "`nonce`". + This is a value the server generates. + Spring Security's nonce adopts the following format: + +@@ -34,7 +31,8 @@ key: A private key to prevent modification of the nonce token + ---- + ==== + +-You will need to ensure you <> insecure plain text <> using NoOpPasswordEncoder`. ++You need to ensure that you <> insecure plain text <> by using `NoOpPasswordEncoder`. ++(See the {security-api-url}org/springframework/security/crypto/password/NoOpPasswordEncoder.html[`NoOpPasswordEncoder`] class in the Javadoc.) + The following provides an example of configuring Digest Authentication with Java Configuration: + + .Digest Authentication +diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/form.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/form.adoc +index 27343234e5..85f7601fcd 100644 +--- a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/form.adoc ++++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/form.adoc +@@ -1,71 +1,70 @@ + [[servlet-authentication-form]] + = Form Login + +-Spring Security provides support for username and password being provided through an html form. ++Spring Security provides support for username and password being provided through an HTML form. + This section provides details on how form based authentication works within Spring Security. + // FIXME: describe authenticationentrypoint, authenticationfailurehandler, authenticationsuccesshandler + +-Let's take a look at how form based log in works within Spring Security. +-First, we see how the user is redirected to the log in form. ++This section examines how form-based login works within Spring Security. ++First, we see how the user is redirected to the log in form: + + .Redirecting to the Log In Page + image::{figures}/loginurlauthenticationentrypoint.png[] + +-The figure builds off our <> diagram. ++The preceding figure builds off our <> diagram. + +-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_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 <> indicates that the unauthenticated request is __Denied__ by throwing an `AccessDeniedException`. + +-image:{icondir}/number_3.png[] Since the user is not authenticated, <> initiates __Start Authentication__ and sends a redirect to the log in page with the configured <>. +-In most cases the `AuthenticationEntryPoint` is an instance of {security-api-url}org/springframework/security/web/authentication/LoginUrlAuthenticationEntryPoint.html[`LoginUrlAuthenticationEntryPoint`]. ++image:{icondir}/number_3.png[] Since the user is not authenticated, <> initiates __Start Authentication__ and sends a redirect to the login page with the configured <>. ++In most cases, the `AuthenticationEntryPoint` is an instance of {security-api-url}org/springframework/security/web/authentication/LoginUrlAuthenticationEntryPoint.html[`LoginUrlAuthenticationEntryPoint`]. + +-image:{icondir}/number_4.png[] The browser will then request the log in page that it was redirected to. ++image:{icondir}/number_4.png[] The browser requests the login page to which it was redirected. + +-image:{icondir}/number_5.png[] Something within the application, must <>. ++image:{icondir}/number_5.png[] Something within the application must <>. + + [[servlet-authentication-usernamepasswordauthenticationfilter]] + When the username and password are submitted, the `UsernamePasswordAuthenticationFilter` authenticates the username and password. +-The `UsernamePasswordAuthenticationFilter` extends <>, so this diagram should look pretty similar. ++The `UsernamePasswordAuthenticationFilter` extends <>, so the following diagram should look pretty similar: + + .Authenticating Username and Password + image::{figures}/usernamepasswordauthenticationfilter.png[] + + The figure builds off our <> diagram. + ++image:{icondir}/number_1.png[] When the user submits their username and password, the `UsernamePasswordAuthenticationFilter` creates a `UsernamePasswordAuthenticationToken`, which is a type of <>, by extracting the username and password from the `HttpServletRequest` instance. + +-image:{icondir}/number_1.png[] When the user submits their username and password, the `UsernamePasswordAuthenticationFilter` creates a `UsernamePasswordAuthenticationToken` which is a type of <> by extracting the username and password from the `HttpServletRequest`. +- +-image:{icondir}/number_2.png[] Next, the `UsernamePasswordAuthenticationToken` is passed into the `AuthenticationManager` to be authenticated. ++image:{icondir}/number_2.png[] Next, the `UsernamePasswordAuthenticationToken` is passed into the `AuthenticationManager` instance to be authenticated. + The details of what `AuthenticationManager` look like depend on how the <>. + +-image:{icondir}/number_3.png[] If authentication fails, then __Failure__ ++image:{icondir}/number_3.png[] If authentication fails, then __Failure__. + +-* The <> is cleared out. +-* `RememberMeServices.loginFail` is invoked. ++. The <> is cleared out. ++. `RememberMeServices.loginFail` is invoked. + If remember me is not configured, this is a no-op. +-// FIXME: link to rememberme +-* `AuthenticationFailureHandler` is invoked. +-// FIXME: link to AuthenticationFailureHandler ++See the {security-api-url}org/springframework/security/web/authentication/RememberMeServices.html[`RememberMeServices`] interface in the Javadoc. ++. `AuthenticationFailureHandler` is invoked. ++See the {security-api-url}springframework/security/web/authentication/AuthenticationFailureHandler.html[`AuthenticationFailureHandler`] class in the Javadoc + + image:{icondir}/number_4.png[] If authentication is successful, then __Success__. + +-* `SessionAuthenticationStrategy` is notified of a new log in. +-// FIXME: Add link to SessionAuthenticationStrategy +-* The <> is set on the <>. +-// FIXME: link securitycontextpersistencefilter +-* `RememberMeServices.loginSuccess` is invoked. ++. `SessionAuthenticationStrategy` is notified of a new log in. ++See the {security-api-url}springframework/security/web/authentication/session/SessionAuthenticationStrategy.html[`SessionAuthenticationStrategy`] interface in the Javadoc. ++. The <> is set on the <>. ++See the {security-api-url}springframework/security/web/context/SecurityContextPersistenceFilter.html[`SecurityContextPersistenceFilter`] class in the Javadoc. ++. `RememberMeServices.loginSuccess` is invoked. + If remember me is not configured, this is a no-op. +-// FIXME: link to rememberme +-* `ApplicationEventPublisher` publishes an `InteractiveAuthenticationSuccessEvent`. +-* The `AuthenticationSuccessHandler` is invoked. Typically this is a `SimpleUrlAuthenticationSuccessHandler` which will redirect to a request saved by <> when we redirect to the log in page. ++See the {security-api-url}springframework/security/web/authentication/RememberMeServices.html[`RememberMeServices`] interface in the Javadoc. ++. `ApplicationEventPublisher` publishes an `InteractiveAuthenticationSuccessEvent`. ++. The `AuthenticationSuccessHandler` is invoked. Typically, this is a `SimpleUrlAuthenticationSuccessHandler`, which redirects to a request saved by <> when we redirect to the login page. + + [[servlet-authentication-form-min]] +-Spring Security form log in is enabled by default. +-However, as soon as any servlet based configuration is provided, form based log in must be explicitly provided. +-A minimal, explicit Java configuration can be found below: ++By default, Spring Security form login is enabled. ++However, as soon as any servlet-based configuration is provided, form based login must be explicitly provided. ++The following example shows a minimal, explicit Java configuration: + +-.Form Log In ++.Form LogIn + ==== + .Java + [source,java,role="primary"] +@@ -98,11 +97,11 @@ fun configure(http: HttpSecurity) { + ---- + ==== + +-In this configuration Spring Security will render a default log in page. +-Most production applications will require a custom log in form. ++In the preceding configuration, Spring Security renders a default login page. ++Most production applications require a custom login form. + + [[servlet-authentication-form-custom]] +-The configuration below demonstrates how to provide a custom log in form. ++The following configuration demonstrates how to provide a custom login form. + + .Custom Log In Form Configuration + ==== +@@ -147,9 +146,9 @@ fun configure(http: HttpSecurity) { + [[servlet-authentication-form-custom-html]] + When the login page is specified in the Spring Security configuration, you are responsible for rendering the page. + // FIXME: default login page rendered by Spring Security +-Below is a https://www.thymeleaf.org/[Thymeleaf] template that produces an HTML login form that complies with a login page of `/login`.: ++The following https://www.thymeleaf.org/[Thymeleaf] template produces an HTML login form that complies with a login page of `/login`.: + +-.Log In Form ++.Login Form + ==== + .src/main/resources/templates/login.html + [source,xml] +@@ -181,19 +180,19 @@ Below is a https://www.thymeleaf.org/[Thymeleaf] template that produces an HTML + + There are a few key points about the default HTML form: + +-* The form should perform a `post` to `/login` +-* The form will need to include a <> which is <> by Thymeleaf. +-* The form should specify the username in a parameter named `username` +-* The form should specify the password in a parameter named `password` +-* If the HTTP parameter error is found, it indicates the user failed to provide a valid username / password +-* If the HTTP parameter logout is found, it indicates the user has logged out successfully ++* The form should perform a `post` to `/login`. ++* The form needs to include a <>, which is <> by Thymeleaf. ++* The form should specify the username in a parameter named `username`. ++* The form should specify the password in a parameter named `password`. ++* If the HTTP parameter named `error` is found, it indicates the user failed to provide a valid username or password. ++* If the HTTP parameter named `logout` is found, it indicates the user has logged out successfully. + +-Many users will not need much more than to customize the log in page. +-However, if needed everything above can be customized with additional configuration. ++Many users do not need much more than to customize the log in page. ++However, if needed, you can customize everything shown earlier with additional configuration. + + [[servlet-authentication-form-custom-controller]] +-If you are using Spring MVC, you will need a controller that maps `GET /login` to the login template we created. +-A minimal sample `LoginController` can be see below: ++If you use Spring MVC, you need a controller that maps `GET /login` to the login template we created. ++The following example shows a minimal `LoginController`: + + .LoginController + ==== +diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/in-memory.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/in-memory.adoc +index a364cee0e1..5b2a37a49f 100644 +--- a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/in-memory.adoc ++++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/in-memory.adoc +@@ -3,9 +3,9 @@ + + Spring Security's `InMemoryUserDetailsManager` implements <> to provide support for username/password based authentication that is retrieved in memory. + `InMemoryUserDetailsManager` provides management of `UserDetails` by implementing the `UserDetailsManager` interface. +-`UserDetails` based authentication is used by Spring Security when it is configured to <> for authentication. ++`UserDetails`-based authentication is used by Spring Security when it is configured to <> for authentication. + +-In this sample we use <> to encode the password of `password` and get the encoded password of `+{bcrypt}$2a$10$GRLdNijSQMUvl/au9ofL.eDwmoohzzS7.rmNSJZ.0FxO/BTk76klW+`. ++In the following sample, we use <> to encode a password value of `password` and get the encoded password of `+{bcrypt}$2a$10$GRLdNijSQMUvl/au9ofL.eDwmoohzzS7.rmNSJZ.0FxO/BTk76klW+`: + + .InMemoryUserDetailsManager Java Configuration + ==== +@@ -61,12 +61,11 @@ fun users(): UserDetailsService { + ---- + ==== + +-The samples above store the passwords in a secure format, but leave a lot to be desired in terms of getting started experience. ++The preceding samples store the passwords in a secure format but leave a lot to be desired in terms of a getting started experience. + +- +-In the sample below we leverage <> to ensure that the password stored in memory is protected. ++In the following sample, we use <> to ensure that the password stored in memory is protected. + However, it does not protect against obtaining the password by decompiling the source code. +-For this reason, `User.withDefaultPasswordEncoder` should only be used for "getting started" and is not intended for production. ++For this reason, `User.withDefaultPasswordEncoder` should only be used for "`getting started`" and is not intended for production. + + .InMemoryUserDetailsManager with User.withDefaultPasswordEncoder + ==== +@@ -113,8 +112,8 @@ fun users(): UserDetailsService { + ---- + ==== + +-There is no simple way to use `User.withDefaultPasswordEncoder` with XML based configuration. +-For demos or just getting started, you can choose to prefix the password with `+{noop}+` to indicate <>. ++There is no simple way to use `User.withDefaultPasswordEncoder` with XML-based configuration. ++For demos or just getting started, you can choose to prefix the password with `+{noop}+` to indicate <>: + + . `+{noop}+` XML Configuration + ==== +diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/index.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/index.adoc +index 415d828118..13fc12aed9 100644 +--- a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/index.adoc ++++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/index.adoc +@@ -4,21 +4,21 @@ + :icondir: images/icons + + One of the most common ways to authenticate a user is by validating a username and password. +-As such, Spring Security provides comprehensive support for authenticating with a username and password. ++Spring Security provides comprehensive support for authenticating with a username and password. + + [[servlet-authentication-unpwd-input]] +-*Reading the Username & Password* ++== Reading the Username & Password + +-Spring Security provides the following built in mechanisms for reading a username and password from the `HttpServletRequest`: ++Spring Security provides the following built-in mechanisms for reading a username and password from `HttpServletRequest`: + + * <> + * <> + * <> + + [[servlet-authentication-unpwd-storage]] +-*Storage Mechanisms* ++== Storage Mechanisms + +-Each of the supported mechanisms for reading a username and password can leverage any of the supported storage mechanisms: ++Each of the supported mechanisms for reading a username and password can use any of the supported storage mechanisms: + + * Simple Storage with <> + * Relational Databases with <> +diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/jdbc.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/jdbc.adoc +index 009e551512..740c8b4de7 100644 +--- a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/jdbc.adoc ++++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/jdbc.adoc +@@ -1,11 +1,11 @@ + [[servlet-authentication-jdbc]] + = JDBC Authentication + +-Spring Security's `JdbcDaoImpl` implements <> to provide support for username/password based authentication that is retrieved using JDBC. ++Spring Security's `JdbcDaoImpl` implements <> to provide support for username-and-password-based authentication that is retrieved by using JDBC. + `JdbcUserDetailsManager` extends `JdbcDaoImpl` to provide management of `UserDetails` through the `UserDetailsManager` interface. +-`UserDetails` based authentication is used by Spring Security when it is configured to <> for authentication. ++`UserDetails`-based authentication is used by Spring Security when it is configured to <> for authentication. + +-In the following sections we will discuss: ++In the following sections, we discuss: + + * The <> used by Spring Security JDBC Authentication + * <> +@@ -14,20 +14,16 @@ In the following sections we will discuss: + [[servlet-authentication-jdbc-schema]] + == Default Schema + +-Spring Security provides default queries for JDBC based authentication. ++Spring Security provides default queries for JDBC-based authentication. + This section provides the corresponding default schemas used with the default queries. +-You will need to adjust the schema to match any customizations to the queries and the database dialect you are using. ++You need to adjust the schema to match any customizations to the queries and the database dialect you use. + + [[servlet-authentication-jdbc-schema-user]] + === User Schema + + `JdbcDaoImpl` requires tables to load the password, account status (enabled or disabled) and a list of authorities (roles) for the user. +-The default schema required can be found below. + +-[NOTE] +-==== +-The default schema is also exposed as a classpath resource named `org/springframework/security/core/userdetails/jdbc/users.ddl`. +-==== ++NOTE: The default schema is also exposed as a classpath resource named `org/springframework/security/core/userdetails/jdbc/users.ddl`. + + .Default User Schema + ==== +@@ -48,8 +44,7 @@ create unique index ix_auth_username on authorities (username,authority); + ---- + ==== + +-Oracle is a popular database choice, but requires a slightly different schema. +-You can find the default Oracle Schema for users below. ++Oracle is a popular database choice but requires a slightly different schema: + + .Default User Schema for Oracle Databases + ==== +@@ -74,8 +69,7 @@ ALTER TABLE AUTHORITIES ADD CONSTRAINT AUTHORITIES_FK1 FOREIGN KEY (USERNAME) RE + [[servlet-authentication-jdbc-schema-group]] + === Group Schema + +-If your application is leveraging groups, you will need to provide the groups schema. +-The default schema for groups can be found below. ++If your application uses groups, you need to provide the groups schema: + + .Default Group Schema + ==== +@@ -105,7 +99,7 @@ create table group_members ( + == Setting up a DataSource + + Before we configure `JdbcUserDetailsManager`, we must create a `DataSource`. +-In our example, we will setup an https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/data-access.html#jdbc-embedded-database-support[embedded DataSource] that is initialized with the <>. ++In our example, we set up an https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/data-access.html#jdbc-embedded-database-support[embedded DataSource] that is initialized with the <>. + + .Embedded Data Source + ==== +@@ -142,12 +136,12 @@ fun dataSource(): DataSource { + ---- + ==== + +-In a production environment, you will want to ensure you setup a connection to an external database. ++In a production environment, you want to ensure that you set up a connection to an external database. + + [[servlet-authentication-jdbc-bean]] + == JdbcUserDetailsManager Bean + +-In this sample we use <> to encode the password of `password` and get the encoded password of `+{bcrypt}$2a$10$GRLdNijSQMUvl/au9ofL.eDwmoohzzS7.rmNSJZ.0FxO/BTk76klW+`. ++In this sample, we use <> to encode a password value of `password` and get the encoded password of `+{bcrypt}$2a$10$GRLdNijSQMUvl/au9ofL.eDwmoohzzS7.rmNSJZ.0FxO/BTk76klW+`. + See the <> section for more details about how to store passwords. + + .JdbcUserDetailsManager +@@ -171,7 +165,7 @@ UserDetailsManager users(DataSource dataSource) { + JdbcUserDetailsManager users = new JdbcUserDetailsManager(dataSource); + users.createUser(user); + users.createUser(admin); +- return users; ++ return users; + } + ---- + +diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/ldap.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/ldap.adoc +index 57f456deb8..f1c32667e2 100644 +--- a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/ldap.adoc ++++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/ldap.adoc +@@ -1,25 +1,25 @@ + [[servlet-authentication-ldap]] + = LDAP Authentication + +-LDAP is often used by organizations as a central repository for user information and as an authentication service. ++LDAP (Lightweight Directory Access Protocol) is often used by organizations as a central repository for user information and as an authentication service. + It can also be used to store the role information for application users. + +-Spring Security's LDAP based authentication is used by Spring Security when it is configured to <> for authentication. +-However, despite leveraging a username/password for authentication it does not integrate using `UserDetailsService` because in <> the LDAP server does not return the password so the application cannot perform validation of the password. ++Spring Security's LDAP-based authentication is used by Spring Security when it is configured to <> for authentication. ++However, despite using a username and password for authentication, it does not use `UserDetailsService`, because, in <>, the LDAP server does not return the password, so the application cannot perform validation of the password. + +-There are many different scenarios for how an LDAP server may be configured so Spring Security's LDAP provider is fully configurable. +-It uses separate strategy interfaces for authentication and role retrieval and provides default implementations which can be configured to handle a wide range of situations. ++There are many different scenarios for how an LDAP server can be configured, so Spring Security's LDAP provider is fully configurable. ++It uses separate strategy interfaces for authentication and role retrieval and provides default implementations, which can be configured to handle a wide range of situations. + + [[servlet-authentication-ldap-prerequisites]] + == Prerequisites + + You should be familiar with LDAP before trying to use it with Spring Security. +-The following link provides a good introduction to the concepts involved and a guide to setting up a directory using the free LDAP server OpenLDAP: https://www.zytrax.com/books/ldap/. +-Some familiarity with the JNDI APIs used to access LDAP from Java may also be useful. +-We don't use any third-party LDAP libraries (Mozilla, JLDAP etc.) in the LDAP provider, but extensive use is made of Spring LDAP, so some familiarity with that project may be useful if you plan on adding your own customizations. ++The following link provides a good introduction to the concepts involved and a guide to setting up a directory using the free LDAP server, OpenLDAP: https://www.zytrax.com/books/ldap/. ++Some familiarity with the JNDI APIs used to access LDAP from Java can also be useful. ++We do not use any third-party LDAP libraries (Mozilla, JLDAP, or others) in the LDAP provider, but extensive use is made of Spring LDAP, so some familiarity with that project may be useful if you plan on adding your own customizations. + +-When using LDAP authentication, it is important to ensure that you configure LDAP connection pooling properly. +-If you are unfamiliar with how to do this, you can refer to the https://docs.oracle.com/javase/jndi/tutorial/ldap/connect/config.html[Java LDAP documentation]. ++When using LDAP authentication, you should ensure that you properly configure LDAP connection pooling. ++If you are unfamiliar with how to do so, see the https://docs.oracle.com/javase/jndi/tutorial/ldap/connect/config.html[Java LDAP documentation]. + + + // FIXME: +@@ -35,16 +35,17 @@ If you are unfamiliar with how to do this, you can refer to the https://docs.ora + [[servlet-authentication-ldap-embedded]] + == Setting up an Embedded LDAP Server + +-The first thing you will need to do is to ensure that you have an LDAP Server to point your configuration to. +-For simplicity, it often best to start with an embedded LDAP Server. ++The first thing you need to do is to ensure that you have an LDAP Server to which to point your configuration. ++For simplicity, it is often best to start with an embedded LDAP Server. + Spring Security supports using either: + + * <> + * <> + +-In the samples below, we expose the following as `users.ldif` as a classpath resource to initialize the embedded LDAP server with the users `user` and `admin` both of which have a password of `password`. ++In the following samples, we expose `users.ldif` as a classpath resource to initialize the embedded LDAP server with two users, `user` and `admin`, both of which have a password of `password`: + + .users.ldif ++==== + [source,ldif] + ---- + dn: ou=groups,dc=springframework,dc=org +@@ -90,11 +91,12 @@ objectclass: groupOfNames + cn: admin + uniqueMember: uid=admin,ou=people,dc=springframework,dc=org + ---- ++==== + + [[servlet-authentication-ldap-unboundid]] + === Embedded UnboundID Server + +-If you wish to use https://ldap.com/unboundid-ldap-sdk-for-java/[UnboundID], then specify the following dependencies: ++If you wish to use https://ldap.com/unboundid-ldap-sdk-for-java/[UnboundID], specify the following dependencies: + + .UnboundID Dependencies + ==== +@@ -118,7 +120,7 @@ depenendencies { + ---- + ==== + +-You can then configure the Embedded LDAP Server ++You can then configure the Embedded LDAP Server: + + .Embedded LDAP Server Configuration + ==== +@@ -153,14 +155,11 @@ fun ldapContainer(): UnboundIdContainer { + [[servlet-authentication-ldap-apacheds]] + === Embedded ApacheDS Server + +-[NOTE] +-==== +-Spring Security uses ApacheDS 1.x which is no longer maintained. ++NOTE: Spring Security uses ApacheDS 1.x, which is no longer maintained. + Unfortunately, ApacheDS 2.x has only released milestone versions with no stable release. + Once a stable release of ApacheDS 2.x is available, we will consider updating. +-==== + +-If you wish to use https://directory.apache.org/apacheds/[Apache DS], then specify the following dependencies: ++If you wish to use https://directory.apache.org/apacheds/[Apache DS], specify the following dependencies: + + .ApacheDS Dependencies + ==== +@@ -191,7 +190,7 @@ depenendencies { + ---- + ==== + +-You can then configure the Embedded LDAP Server ++You can then configure the Embedded LDAP Server: + + .Embedded LDAP Server Configuration + ==== +@@ -226,8 +225,8 @@ fun ldapContainer(): ApacheDSContainer { + [[servlet-authentication-ldap-contextsource]] + == LDAP ContextSource + +-Once you have an LDAP Server to point your configuration to, you need configure Spring Security to point to an LDAP server that should be used to authenticate users. +-This is done by creating an LDAP `ContextSource`, which is the equivalent of a JDBC `DataSource`. ++Once you have an LDAP Server to which to point your configuration, you need to configure Spring Security to point to an LDAP server that should be used to authenticate users. ++To do so, create an LDAP `ContextSource` (which is the equivalent of a JDBC `DataSource`): + + .LDAP Context Source + ==== +@@ -258,15 +257,15 @@ fun contextSource(container: UnboundIdContainer): ContextSource { + [[servlet-authentication-ldap-authentication]] + == Authentication + +-Spring Security's LDAP support does not use the <> because LDAP bind authentication does not allow clients to read the password or even a hashed version of the password. +-This means there is no way a password to be read and then authenticated by Spring Security. ++Spring Security's LDAP support does not use the <> because LDAP bind authentication does not let clients read the password or even a hashed version of the password. ++This means there is no way for a password to be read and then authenticated by Spring Security. + +-For this reason, LDAP support is implemented using the `LdapAuthenticator` interface. +-The `LdapAuthenticator` is also responsible for retrieving any required user attributes. ++For this reason, LDAP support is implemented through the `LdapAuthenticator` interface. ++The `LdapAuthenticator` interface is also responsible for retrieving any required user attributes. + This is because the permissions on the attributes may depend on the type of authentication being used. +-For example, if binding as the user, it may be necessary to read them with the user's own permissions. ++For example, if binding as the user, it may be necessary to read the attributes with the user's own permissions. + +-There are two `LdapAuthenticator` implementations supplied with Spring Security: ++Spring Security supplies two `LdapAuthenticator` implementations: + + * <> + * <> +@@ -275,11 +274,10 @@ There are two `LdapAuthenticator` implementations supplied with Spring Security: + == Using Bind Authentication + + https://ldap.com/the-ldap-bind-operation/[Bind Authentication] is the most common mechanism for authenticating users with LDAP. +-In bind authentication the users credentials (i.e. username/password) are submitted to the LDAP server which authenticates them. +-The advantage to using bind authentication is that the user's secrets (i.e. password) do not need to be exposed to clients which helps to protect them from leaking. ++In bind authentication, the user's credentials (username and password) are submitted to the LDAP server, which authenticates them. ++The advantage to using bind authentication is that the user's secrets (the password) do not need to be exposed to clients, which helps to protect them from leaking. + +- +-An example of bind authentication configuration can be found below. ++The following example shows bind authentication configuration: + + .Bind Authentication + ==== +@@ -323,9 +321,9 @@ fun authenticationProvider(authenticator: LdapAuthenticator): LdapAuthentication + ---- + ==== + +-This simple example would obtain the DN for the user by substituting the user login name in the supplied pattern and attempting to bind as that user with the login password. ++The preceding simple example would obtain the DN for the user by substituting the user login name in the supplied pattern and attempting to bind as that user with the login password. + This is OK if all your users are stored under a single node in the directory. +-If instead you wished to configure an LDAP search filter to locate the user, you could use the following: ++If, instead, you wish to configure an LDAP search filter to locate the user, you could use the following: + + .Bind Authentication with Search Filter + ==== +@@ -377,15 +375,15 @@ fun authenticationProvider(authenticator: LdapAuthenticator): LdapAuthentication + ---- + ==== + +-If used with the `ContextSource` <>, this would perform a search under the DN `ou=people,dc=springframework,dc=org` using `+(uid={0})+` as a filter. +-Again the user login name is substituted for the parameter in the filter name, so it will search for an entry with the `uid` attribute equal to the user name. +-If a user search base isn't supplied, the search will be performed from the root. ++If used with the `ContextSource` <>, this would perform a search under the DN `ou=people,dc=springframework,dc=org` by using `+(uid={0})+` as a filter. ++Again, the user login name is substituted for the parameter in the filter name, so it searchs for an entry with the `uid` attribute equal to the user name. ++If a user search base is not supplied, the search is performed from the root. + + [[servlet-authentication-ldap-pwd]] + == Using Password Authentication + + Password comparison is when the password supplied by the user is compared with the one stored in the repository. +-This can either be done by retrieving the value of the password attribute and checking it locally or by performing an LDAP "compare" operation, where the supplied password is passed to the server for comparison and the real password value is never retrieved. ++This can either be done by retrieving the value of the password attribute and checking it locally or by performing an LDAP "`compare`" operation, where the supplied password is passed to the server for comparison and the real password value is never retrieved. + An LDAP compare cannot be done when the password is properly hashed with a random salt. + + .Minimal Password Compare Configuration +@@ -428,7 +426,7 @@ fun authenticationProvider(authenticator: LdapAuthenticator): LdapAuthentication + ---- + ==== + +-A more advanced configuration with some customizations can be found below. ++The following example shows a more advanced configuration with some customizations: + + .Password Compare Configuration + ==== +@@ -481,13 +479,14 @@ fun authenticationProvider(authenticator: LdapAuthenticator): LdapAuthentication + ---- + ==== + +-<1> Specify the password attribute as `pwd` +-<2> Use `BCryptPasswordEncoder` ++<1> Specify the password attribute as `pwd`. ++<2> Use `BCryptPasswordEncoder`. + + + == LdapAuthoritiesPopulator + +-Spring Security's `LdapAuthoritiesPopulator` is used to determine what authorites are returned for the user. ++Spring Security's `LdapAuthoritiesPopulator` is used to determine what authorities are returned for the user. ++The following example shows how configure `LdapAuthoritiesPopulator`: + + .LdapAuthoritiesPopulator Configuration + ==== +@@ -537,14 +536,17 @@ fun authenticationProvider(authenticator: LdapAuthenticator, authorities: LdapAu + + == Active Directory + +-Active Directory supports its own non-standard authentication options, and the normal usage pattern doesn't fit too cleanly with the standard `LdapAuthenticationProvider`. +-Typically authentication is performed using the domain username (in the form `user@domain`), rather than using an LDAP distinguished name. +-To make this easier, Spring Security has an authentication provider which is customized for a typical Active Directory setup. ++Active Directory supports its own non-standard authentication options, and the normal usage pattern does not fit too cleanly with the standard `LdapAuthenticationProvider`. ++Typically, authentication is performed by using the domain username (in the form of `user@domain`), rather than using an LDAP distinguished name. ++To make this easier, Spring Security has an authentication provider, which is customized for a typical Active Directory setup. + + Configuring `ActiveDirectoryLdapAuthenticationProvider` is quite straightforward. +-You just need to supply the domain name and an LDAP URL supplying the address of the server footnote:[It is also possible to obtain the server's IP address using a DNS lookup. +-This is not currently supported, but hopefully will be in a future version.]. +-An example configuration can be seen below: ++You need only supply the domain name and an LDAP URL that supplies the address of the server. ++ ++NOTE: It is also possible to obtain the server's IP address byusing a DNS lookup. ++This is not currently supported, but hopefully will be in a future version. ++ ++The following example configures Active Directory: + + .Example Active Directory Configuration + ==== +diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/password-encoder.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/password-encoder.adoc +index 73f9e1f2e1..70b7e79252 100644 +--- a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/password-encoder.adoc ++++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/password-encoder.adoc +@@ -1,5 +1,5 @@ + [[servlet-authentication-password-storage]] + = PasswordEncoder + +-Spring Security's servlet support storing passwords securely by integrating with <>. +-Customizing the `PasswordEncoder` implementation used by Spring Security can be done by <>. ++Spring Security's servlet support includes storing passwords securely by integrating with <>. ++You can customize the `PasswordEncoder` implementation used by Spring Security by <>. +diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/user-details-service.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/user-details-service.adoc +index 9147cedbd2..f630021ee5 100644 +--- a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/user-details-service.adoc ++++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/user-details-service.adoc +@@ -1,11 +1,11 @@ + [[servlet-authentication-userdetailsservice]] + = UserDetailsService + +-{security-api-url}org/springframework/security/core/userdetails/UserDetailsService.html[`UserDetailsService`] is used by <> for retrieving a username, password, and other attributes for authenticating with a username and password. ++{security-api-url}org/springframework/security/core/userdetails/UserDetailsService.html[`UserDetailsService`] is used by <> for retrieving a username, a password, and other attributes for authenticating with a username and password. + Spring Security provides <> and <> implementations of `UserDetailsService`. + + You can define custom authentication by exposing a custom `UserDetailsService` as a bean. +-For example, the following will customize authentication assuming that `CustomUserDetailsService` implements `UserDetailsService`: ++For example, the following listing customizes authentication, assuming that `CustomUserDetailsService` implements `UserDetailsService`: + + NOTE: This is only used if the `AuthenticationManagerBuilder` has not been populated and no `AuthenticationProviderBean` is defined. + +diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/x509.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/x509.adoc +index d84ae8560c..a3fbb9017e 100644 +--- a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/x509.adoc ++++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/x509.adoc +@@ -1,28 +1,27 @@ + [[servlet-x509]] + == X.509 Authentication + +- + [[x509-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. ++The browser automatically checks that the certificate presented by a server has been issued (digitally signed) by one of a list of trusted certificate authorities that it maintains. + +-You can also use SSL with "mutual authentication"; the server will then request a valid certificate from the client as part of the SSL handshake. +-The server will authenticate the client by checking that its certificate is signed by an acceptable authority. ++You can also use SSL with "`mutual authentication`". The server then requests a valid certificate from the client as part of the SSL handshake. ++The server authenticates the client by checking that its certificate is signed by an acceptable authority. + If a valid certificate has been provided, it can be obtained through the servlet API in an application. +-Spring Security X.509 module extracts the certificate using a filter. ++The Spring Security X.509 module extracts the certificate by using a filter. + It maps the certificate to an application user and loads that user's set of granted authorities for use with the standard Spring Security infrastructure. + + You should be familiar with using certificates and setting up client authentication for your servlet container before attempting to use it with Spring Security. + Most of the work is in creating and installing suitable certificates and keys. +-For example, if you're using Tomcat then read the instructions here https://tomcat.apache.org/tomcat-9.0-doc/ssl-howto.html[https://tomcat.apache.org/tomcat-9.0-doc/ssl-howto.html]. +-It's important that you get this working before trying it out with Spring Security ++For example, if you use Tomcat, you should read the https://tomcat.apache.org/tomcat-9.0-doc/ssl-howto.html[Tomcat SSL instructions]. ++You should get this working before trying it out with Spring Security. + + + === Adding X.509 Authentication to Your Web Application + Enabling X.509 client authentication is very straightforward. +-Just add the `` element to your http security namespace configuration. ++To do so, add the `` element to your http security namespace configuration: + ++==== + [source,xml] + ---- + +@@ -30,39 +29,40 @@ Just add the `` element to your http security namespace configuration. + ; + + ---- ++==== + + The element has two optional attributes: + + * `subject-principal-regex`. + The regular expression used to extract a username from the certificate's subject name. +-The default value is shown above. +-This is the username which will be passed to the `UserDetailsService` to load the authorities for the user. ++The default value is shown in the preceding listing. ++This is the username that is passed to the `UserDetailsService` to load the authorities for the user. + * `user-service-ref`. +-This is the bean Id of the `UserDetailsService` to be used with X.509. +-It isn't needed if there is only one defined in your application context. ++This is the bean ID of the `UserDetailsService` to be used with X.509. ++It is not needed if there is only one defined in your application context. + + The `subject-principal-regex` should contain a single group. +-For example the default expression "CN=(.*?)," matches the common name field. +-So if the subject name in the certificate is "CN=Jimi Hendrix, OU=...", this will give a user name of "Jimi Hendrix". ++For example, the default expression (`CN=(.*?)`) matches the common name field. ++So, if the subject name in the certificate is "CN=Jimi Hendrix, OU=...", this gives a user name of "Jimi Hendrix". + The matches are case insensitive. +-So "emailAddress=(+.*?+)," will match "EMAILADDRESS=jimi@hendrix.org,CN=..." giving a user name "jimi@hendrix.org". +-If the client presents a certificate and a valid username is successfully extracted, then there should be a valid `Authentication` object in the security context. +-If no certificate is found, or no corresponding user could be found then the security context will remain empty. +-This means that you can easily use X.509 authentication with other options such as a form-based login. ++So "emailAddress=(+.*?+)," matches "EMAILADDRESS=jimi@hendrix.org,CN=...", giving a user name "jimi@hendrix.org". ++If the client presents a certificate and a valid username is successfully extracted, there should be a valid `Authentication` object in the security context. ++If no certificate is found or no corresponding user could be found, the security context remains empty. ++This means that you can use X.509 authentication with other options, such as a form-based login. + + [[x509-ssl-config]] + === Setting up SSL in Tomcat + There are some pre-generated certificates in the `samples/certificate` directory in the Spring Security project. +-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. ++You can use these to enable SSL for testing if you do not want to generate your own. ++The `server.jks` file contains the server certificate, the private key, and the issuing authority certificate. + There are also some client certificate files for the users from the sample applications. + You can install these in your browser to enable SSL client authentication. + +-To run tomcat with SSL support, drop the `server.jks` file into the tomcat `conf` directory and add the following connector to the `server.xml` file ++To run tomcat with SSL support, drop the `server.jks` file into the tomcat `conf` directory and add the following connector to the `server.xml` file: + ++==== + [source,xml] + ---- +- + +- + ---- ++==== + +-`clientAuth` can also be set to `want` if you still want SSL connections to succeed even if the client doesn't provide a certificate. +-Clients which don't present a certificate won't be able to access any objects secured by Spring Security unless you use a non-X.509 authentication mechanism, such as form authentication. +- ++`clientAuth` can also be set to `want` if you still want SSL connections to succeed even if the client does not provide a certificate. ++Clients that do not present a certificate cannot access any objects secured by Spring Security unless you use a non-X.509 authentication mechanism, such as form authentication. +diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authorization/acls.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authorization/acls.adoc +index f87e83d4ee..f55f59ec1b 100644 +--- a/docs/manual/src/docs/asciidoc/_includes/servlet/authorization/acls.adoc ++++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authorization/acls.adoc +@@ -1,153 +1,146 @@ + [[domain-acls]] + == Domain Object Security (ACLs) + ++This section describes how Spring Security provides domain object security with Access Control Lists (ACLs). ++ + [[domain-acls-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`). ++Complex applications often need to define access permissions beyond a web request or method invocation level. ++Instead, security decisions need to comprise 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. + +-Imagine you're designing an application for a pet clinic. +-There will be two main groups of users of your Spring-based application: staff of the pet clinic, as well as the pet clinic's customers. +-The staff will have access to all of the data, whilst your customers will only be able to see their own customer records. +-To make it a little more interesting, your customers can allow other users to see their customer records, such as their "puppy preschool" mentor or president of their local "Pony Club". +-Using Spring Security as the foundation, you have several approaches that can be used: ++Imagine you are designing an application for a pet clinic. ++There are two main groups of users of your Spring-based application: staff of the pet clinic and the pet clinic's customers. ++The staff should have access to all of the data, while your customers should be able to see only their own customer records. ++To make it a little more interesting, your customers can let other users see their customer records, such as their "`puppy preschool`" mentor or the president of their local "`Pony Club`". ++When you use Spring Security as the foundation, you have several possible approaches: + + * Write your business methods to enforce the security. + You could consult a collection within the `Customer` domain object instance to determine which users have access. +-By using the `SecurityContextHolder.getContext().getAuthentication()`, you'll be able to access the `Authentication` object. +-* Write an `AccessDecisionVoter` to enforce the security from the `GrantedAuthority[]` s stored in the `Authentication` object. +-This would mean your `AuthenticationManager` would need to populate the `Authentication` with custom ``GrantedAuthority[]``s representing each of the `Customer` domain object instances the principal has access to. ++By using `SecurityContextHolder.getContext().getAuthentication()`, you can access the `Authentication` object. ++* Write an `AccessDecisionVoter` to enforce the security from the `GrantedAuthority[]` instances stored in the `Authentication` object. ++This means that your `AuthenticationManager` needs to populate the `Authentication` with custom `GrantedAuthority[]` objects to represent each of the `Customer` domain object instances to which the principal has access. + * Write an `AccessDecisionVoter` to enforce the security and open the target `Customer` domain object directly. +-This would mean your voter needs access to a DAO that allows it to retrieve the `Customer` object. +-It would then access the `Customer` object's collection of approved users and make the appropriate decision. +- ++This would mean your voter needs access to a DAO that lets it retrieve the `Customer` object. ++It can then access the `Customer` object's collection of approved users and make the appropriate decision. + + Each one of these approaches is perfectly legitimate. + However, the first couples your authorization checking to your business code. +-The main problems with this include the enhanced difficulty of unit testing and the fact it would be more difficult to reuse the `Customer` authorization logic elsewhere. +-Obtaining the `GrantedAuthority[]` s from the `Authentication` object is also fine, but will not scale to large numbers of `Customer` s. +-If a user might be able to access 5,000 `Customer` s (unlikely in this case, but imagine if it were a popular vet for a large Pony Club!) the amount of memory consumed and time required to construct the `Authentication` object would be undesirable. ++The main problems with this include the enhanced difficulty of unit testing and the fact that it would be more difficult to reuse the `Customer` authorization logic elsewhere. ++Obtaining the `GrantedAuthority[]` instances from the `Authentication` object is also fine but will not scale to large numbers of `Customer` objects. ++If a user can access 5,000 `Customer` objects (unlikely in this case, but imagine if it were a popular vet for a large Pony Club!) the amount of memory consumed and the time required to construct the `Authentication` object would be undesirable. + The final method, opening the `Customer` directly from external code, is probably the best of the three. +-It achieves separation of concerns, and doesn't misuse memory or CPU cycles, but it is still inefficient in that both the `AccessDecisionVoter` and the eventual business method itself will perform a call to the DAO responsible for retrieving the `Customer` object. ++It achieves separation of concerns and does not misuse memory or CPU cycles, but it is still inefficient in that both the `AccessDecisionVoter` and the eventual business method itself perform a call to the DAO responsible for retrieving the `Customer` object. + Two accesses per method invocation is clearly undesirable. +-In addition, with every approach listed you'll need to write your own access control list (ACL) persistence and business logic from scratch. +- +-Fortunately, there is another alternative, which we'll talk about below. ++In addition, with every approach listed, you need to write your own access control list (ACL) persistence and business logic from scratch. + ++Fortunately, there is another alternative, which we discuss later. + + [[domain-acls-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. ++You need to add this JAR to your classpath to use Spring Security's domain object instance security capabilities. + +-Spring Security's domain object instance security capabilities centre on the concept of an access control list (ACL). +-Every domain object instance in your system has its own ACL, and the ACL records details of who can and can't work with that domain object. +-With this in mind, Spring Security delivers three main ACL-related capabilities to your application: ++Spring Security's domain object instance security capabilities center on the concept of an access control list (ACL). ++Every domain object instance in your system has its own ACL, and the ACL records details of who can and cannot work with that domain object. ++With this in mind, Spring Security provides three main ACL-related capabilities to your application: + +-* A way of efficiently retrieving ACL entries for all of your domain objects (and modifying those ACLs) +-* A way of ensuring a given principal is permitted to work with your objects, before methods are called +-* A way of ensuring a given principal is permitted to work with your objects (or something they return), after methods are called ++* A way to efficiently retrieve ACL entries for all of your domain objects (and modifying those ACLs) ++* A way to ensure a given principal is permitted to work with your objects before methods are called ++* A way to ensure a given principal is permitted to work with your objects (or something they return) after methods are called + + As indicated by the first bullet point, one of the main capabilities of the Spring Security ACL module is providing a high-performance way of retrieving ACLs. +-This ACL repository capability is extremely important, because every domain object instance in your system might have several access control entries, and each ACL might inherit from other ACLs in a tree-like structure (this is supported out-of-the-box by Spring Security, and is very commonly used). ++This ACL repository capability is extremely important, because every domain object instance in your system might have several access control entries, and each ACL might inherit from other ACLs in a tree-like structure (this is supported by Spring Security, and it is very commonly used). + Spring Security's ACL capability has been carefully designed to provide high performance retrieval of ACLs, together with pluggable caching, deadlock-minimizing database updates, independence from ORM frameworks (we use JDBC directly), proper encapsulation, and transparent database updating. + +-Given databases are central to the operation of the ACL module, let's explore the four main tables used by default in the implementation. +-The tables are presented below in order of size in a typical Spring Security ACL deployment, with the table with the most rows listed last: +- ++Given that databases are central to the operation of the ACL module, we need explore the four main tables used by default in the implementation. ++The tables are presented in order of size in a typical Spring Security ACL deployment, with the table with the most rows listed last: + +- +-* ACL_SID allows us to uniquely identify any principal or authority in the system ("SID" stands for "security identity"). ++[[acl_tables]] ++* `ACL_SID` lets us uniquely identify any principal or authority in the system ("`SID`" stands for "`Security IDentity`"). + The only columns are the ID, a textual representation of the SID, and a flag to indicate whether the textual representation refers to a principal name or a `GrantedAuthority`. + Thus, there is a single row for each unique principal or `GrantedAuthority`. +-When used in the context of receiving a permission, a SID is generally called a "recipient". ++When used in the context of receiving a permission, an SID is generally called a "`recipient`". + +-* ACL_CLASS allows us to uniquely identify any domain object class in the system. ++* `ACL_CLASS` lets us uniquely identify any domain object class in the system. + The only columns are the ID and the Java class name. +-Thus, there is a single row for each unique Class we wish to store ACL permissions for. ++Thus, there is a single row for each unique Class for which we wish to store ACL permissions. + +-* ACL_OBJECT_IDENTITY stores information for each unique domain object instance in the system. +-Columns include the ID, a foreign key to the ACL_CLASS table, a unique identifier so we know which ACL_CLASS instance we're providing information for, the parent, a foreign key to the ACL_SID table to represent the owner of the domain object instance, and whether we allow ACL entries to inherit from any parent ACL. +-We have a single row for every domain object instance we're storing ACL permissions for. ++* `ACL_OBJECT_IDENTITY` stores information for each unique domain object instance in the system. ++Columns include the ID, a foreign key to the ACL_CLASS table, a unique identifier so we know the ACL_CLASS instance for which we provide information, the parent, a foreign key to the ACL_SID table to represent the owner of the domain object instance, and whether we allow ACL entries to inherit from any parent ACL. ++We have a single row for every domain object instance for which we store ACL permissions. + +-* Finally, ACL_ENTRY stores the individual permissions assigned to each recipient. +-Columns include a foreign key to the ACL_OBJECT_IDENTITY, the recipient (i.e. a foreign key to ACL_SID), whether we'll be auditing or not, and the integer bit mask that represents the actual permission being granted or denied. ++* Finally, `ACL_ENTRY` stores the individual permissions assigned to each recipient. ++Columns include a foreign key to the ACL_OBJECT_IDENTITY, the recipient (which is a foreign key to ACL_SID), whether we audit or not, and the integer bit mask that represents the actual permission being granted or denied. + We have a single row for every recipient that receives a permission to work with a domain object. + +- +- +- + As mentioned in the last paragraph, the ACL system uses integer bit masking. +-Don't worry, you need not be aware of the finer points of bit shifting to use the ACL system, but suffice to say that we have 32 bits we can switch on or off. +-Each of these bits represents a permission, and by default the permissions are read (bit 0), write (bit 1), create (bit 2), delete (bit 3) and administer (bit 4). +-It's easy to implement your own `Permission` instance if you wish to use other permissions, and the remainder of the ACL framework will operate without knowledge of your extensions. +- +-It is important to understand that the number of domain objects in your system has absolutely no bearing on the fact we've chosen to use integer bit masking. +-Whilst you have 32 bits available for permissions, you could have billions of domain object instances (which will mean billions of rows in ACL_OBJECT_IDENTITY and quite probably ACL_ENTRY). +-We make this point because we've found sometimes people mistakenly believe they need a bit for each potential domain object, which is not the case. ++However, you need not be aware of the finer points of bit shifting to use the ACL system. ++Suffice it to say that we have 32 bits we can switch on or off. ++Each of these bits represents a permission. By default, the permissions are read (bit 0), write (bit 1), create (bit 2), delete (bit 3), and administer (bit 4). ++You can implement your own `Permission` instance if you wish to use other permissions, and the remainder of the ACL framework operates without knowledge of your extensions. + +-Now that we've provided a basic overview of what the ACL system does, and what it looks like at a table structure, let's explore the key interfaces. +-The key interfaces are: ++You should understand that the number of domain objects in your system has absolutely no bearing on the fact that we have chosen to use integer bit masking. ++While you have 32 bits available for permissions, you could have billions of domain object instances (which means billions of rows in ACL_OBJECT_IDENTITY and, probably, ACL_ENTRY). ++We make this point because we have found that people sometimes mistakenly that believe they need a bit for each potential domain object, which is not the case. + ++Now that we have provided a basic overview of what the ACL system does, and what it looks like at a table-structure level, we need to explore the key interfaces: + +-* `Acl`: Every domain object has one and only one `Acl` object, which internally holds the `AccessControlEntry` s as well as knows the owner of the `Acl`. ++* `Acl`: Every domain object has one and only one `Acl` object, which internally holds the `AccessControlEntry` objects and knows the owner of the `Acl`. + An Acl does not refer directly to the domain object, but instead to an `ObjectIdentity`. +-The `Acl` is stored in the ACL_OBJECT_IDENTITY table. ++The `Acl` is stored in the `ACL_OBJECT_IDENTITY` table. + +-* `AccessControlEntry`: An `Acl` holds multiple `AccessControlEntry` s, which are often abbreviated as ACEs in the framework. +-Each ACE refers to a specific tuple of `Permission`, `Sid` and `Acl`. ++* `AccessControlEntry`: An `Acl` holds multiple `AccessControlEntry` objects, which are often abbreviated as ACEs in the framework. ++Each ACE refers to a specific tuple of `Permission`, `Sid`, and `Acl`. + An ACE can also be granting or non-granting and contain audit settings. +-The ACE is stored in the ACL_ENTRY table. ++The ACE is stored in the `ACL_ENTRY` table. + +-* `Permission`: A permission represents a particular immutable bit mask, and offers convenience functions for bit masking and outputting information. ++* `Permission`: A permission represents a particular immutable bit mask and offers convenience functions for bit masking and outputting information. + The basic permissions presented above (bits 0 through 4) are contained in the `BasePermission` class. + +-* `Sid`: The ACL module needs to refer to principals and `GrantedAuthority[]` s. +-A level of indirection is provided by the `Sid` interface, which is an abbreviation of "security identity". ++* `Sid`: The ACL module needs to refer to principals and `GrantedAuthority[]` instances. ++A level of indirection is provided by the `Sid` interface. ("`SID`" is an abbreviation of "`Security IDentity`".) + Common classes include `PrincipalSid` (to represent the principal inside an `Authentication` object) and `GrantedAuthoritySid`. +-The security identity information is stored in the ACL_SID table. ++The security identity information is stored in the `ACL_SID` table. + + * `ObjectIdentity`: Each domain object is represented internally within the ACL module by an `ObjectIdentity`. + The default implementation is called `ObjectIdentityImpl`. + + * `AclService`: Retrieves the `Acl` applicable for a given `ObjectIdentity`. + In the included implementation (`JdbcAclService`), retrieval operations are delegated to a `LookupStrategy`. +-The `LookupStrategy` provides a highly optimized strategy for retrieving ACL information, using batched retrievals (`BasicLookupStrategy`) and supporting custom implementations that leverage materialized views, hierarchical queries and similar performance-centric, non-ANSI SQL capabilities. +- +-* `MutableAclService`: Allows a modified `Acl` to be presented for persistence. +-It is not essential to use this interface if you do not wish. +- ++The `LookupStrategy` provides a highly optimized strategy for retrieving ACL information, using batched retrievals (`BasicLookupStrategy`) and supporting custom implementations that use materialized views, hierarchical queries, and similar performance-centric, non-ANSI SQL capabilities. + ++* `MutableAclService`: Lets a modified `Acl` be presented for persistence. ++Use of this interface is optional. + +-Please note that our out-of-the-box AclService and related database classes all use ANSI SQL. ++Note that our `AclService` and related database classes all use ANSI SQL. + This should therefore work with all major databases. +-At the time of writing, the system had been successfully tested using Hypersonic SQL, PostgreSQL, Microsoft SQL Server and Oracle. ++At the time of writing, the system had been successfully tested with Hypersonic SQL, PostgreSQL, Microsoft SQL Server, and Oracle. + + Two samples ship with Spring Security that demonstrate the ACL module. +-The first is the Contacts Sample, and the other is the Document Management System (DMS) Sample. +-We suggest taking a look over these for examples. ++The first is the https://github.com/spring-projects/spring-security/tree/master/samples/xml/contacts[Contacts sample], and the other is the https://github.com/spring-projects/spring-security/tree/master/samples/xml/dms[Document Management System (DMS) sample]. ++We suggest taking a look at these examples. + + + [[domain-acls-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. +-The latter provides high-performance ACL retrieval capabilities, and the former provides mutator capabilities. +-Refer to one of the samples that ship with Spring Security for an example configuration. +-You'll also need to populate the database with the four ACL-specific tables listed in the last section (refer to the ACL samples for the appropriate SQL statements). +- +-Once you've created the required schema and instantiated `JdbcMutableAclService`, you'll next need to ensure your domain model supports interoperability with the Spring Security ACL package. +-Hopefully `ObjectIdentityImpl` will prove sufficient, as it provides a large number of ways in which it can be used. +-Most people will have domain objects that contain a `public Serializable getId()` method. +-If the return type is long, or compatible with long (e.g. an int), you will find you need not give further consideration to `ObjectIdentity` issues. ++To get starting with Spring Security's ACL capability, you need to store your ACL information somewhere. ++This necessitates the instantiation of a `DataSource` in Spring. ++The `DataSource` is then injected into a `JdbcMutableAclService` and a `BasicLookupStrategy` instance. ++The former provides mutator capabilities, and the latter provides high-performance ACL retrieval capabilities. ++See one of the https://github.com/spring-projects/spring-security/tree/master/samples[samples] that ship with Spring Security for an example configuration. ++You also need to populate the database with the <> listed in the previous section (see the ACL samples for the appropriate SQL statements). ++ ++Once you have created the required schema and instantiated `JdbcMutableAclService`, you need to ensure your domain model supports interoperability with the Spring Security ACL package. ++Hopefully, `ObjectIdentityImpl` proves sufficient, as it provides a large number of ways in which it can be used. ++Most people have domain objects that contain a `public Serializable getId()` method. ++If the return type is `long` or compatible with `long` (such as an `int`), you may find that you need not give further consideration to `ObjectIdentity` issues. + Many parts of the ACL module rely on long identifiers. +-If you're not using long (or an int, byte etc), there is a very good chance you'll need to reimplement a number of classes. +-We do not intend to support non-long identifiers in Spring Security's ACL module, as longs are already compatible with all database sequences, the most common identifier data type, and are of sufficient length to accommodate all common usage scenarios. ++If you do not use `long` (or an `int`, `byte`, and so on), you probably need to reimplement a number of classes. ++We do not intend to support non-long identifiers in Spring Security's ACL module, as longs are already compatible with all database sequences, are the most common identifier data type, and are of sufficient length to accommodate all common usage scenarios. + +-The following fragment of code shows how to create an `Acl`, or modify an existing `Acl`: ++The following fragment of code shows how to create an `Acl` or modify an existing `Acl`: + ++==== + [source,java] + ---- + // Prepare the information we'd like in our access control entry (ACE) +@@ -167,27 +160,25 @@ acl = aclService.createAcl(oi); + acl.insertAce(acl.getEntries().length, p, sid, true); + aclService.updateAcl(acl); + ---- ++==== + +- +- +-In the example above, we're retrieving the ACL associated with the "Foo" domain object with identifier number 44. +-We're then adding an ACE so that a principal named "Samantha" can "administer" the object. +-The code fragment is relatively self-explanatory, except the insertAce method. +-The first argument to the insertAce method is determining at what position in the Acl the new entry will be inserted. +-In the example above, we're just putting the new ACE at the end of the existing ACEs. ++In the preceding example, we retrieve the ACL associated with the `Foo` domain object with identifier number 44. ++We then add an ACE so that a principal named "`Samantha`" can "`administer`" the object. ++The code fragment is relatively self-explanatory, except for the `insertAce` method. ++The first argument to the `insertAce` method determine position in the Acl at which the new entry is inserted. ++In the preceding example, we put the new ACE at the end of the existing ACEs. + The final argument is a Boolean indicating whether the ACE is granting or denying. +-Most of the time it will be granting (true), but if it is denying (false), the permissions are effectively being blocked. ++Most of the time it grants (`true`). However, if it denies (`false`), the permissions are effectively being blocked. + +-Spring Security does not provide any special integration to automatically create, update or delete ACLs as part of your DAO or repository operations. +-Instead, you will need to write code like shown above for your individual domain objects. +-It's worth considering using AOP on your services layer to automatically integrate the ACL information with your services layer operations. +-We've found this quite an effective approach in the past. ++Spring Security does not provide any special integration to automatically create, update, or delete ACLs as part of your DAO or repository operations. ++Instead, you need to write code similar to that shown in the preceding example for your individual domain objects. ++You should consider using AOP on your services layer to automatically integrate the ACL information with your services layer operations. ++We have found this approach to be effective. + +-Once you've used the above techniques to store some ACL information in the database, the next step is to actually use the ACL information as part of authorization decision logic. ++Once you have used the techniques described here to store some ACL information in the database, the next step is to actually use the ACL information as part of authorization decision logic. + You have a number of choices here. +-You could write your own `AccessDecisionVoter` or `AfterInvocationProvider` that respectively fires before or after a method invocation. ++You could write your own `AccessDecisionVoter` or `AfterInvocationProvider` that (respectively) fires before or after a method invocation. + Such classes would use `AclService` to retrieve the relevant ACL and then call `Acl.isGranted(Permission[] permission, Sid[] sids, boolean administrativeMode)` to decide whether permission is granted or denied. +-Alternately, you could use our `AclEntryVoter`, `AclEntryAfterInvocationProvider` or `AclEntryAfterInvocationCollectionFilteringProvider` classes. ++Alternately, you could use our `AclEntryVoter`, `AclEntryAfterInvocationProvider`, or `AclEntryAfterInvocationCollectionFilteringProvider` classes. + All of these classes provide a declarative-based approach to evaluating ACL information at runtime, freeing you from needing to write any code. +-Please refer to the sample applications to learn how to use these classes. +- ++See the https://github.com/spring-projects/spring-security/tree/master/samples[sample applications] to learn how to use these classes. +diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authorization/architecture.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authorization/architecture.adoc +index 15de8dbf70..7d44250a39 100644 +--- a/docs/manual/src/docs/asciidoc/_includes/servlet/authorization/architecture.adoc ++++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authorization/architecture.adoc +@@ -1,41 +1,41 @@ + // from the original documentation +- + [[authz-arch]] + = Authorization Architecture + ++This section describes the Spring Security architecture that applies to authorization. + + [[authz-authorities]] + == Authorities +-<>, discusses how all `Authentication` implementations store a list of `GrantedAuthority` objects. ++<> discusses how all `Authentication` implementations store a list of `GrantedAuthority` objects. + These represent the authorities that have been granted to the principal. +-the `GrantedAuthority` objects are inserted into the `Authentication` object by the `AuthenticationManager` and are later read by `AccessDecisionManager` s when making authorization decisions. ++The `GrantedAuthority` objects are inserted into the `Authentication` object by the `AuthenticationManager` and are later read by `AccessDecisionManager` instances when making authorization decisions. + +-`GrantedAuthority` is an interface with only one method: ++The `GrantedAuthority` interface has only one method: + ++==== + [source,java] + ---- +- + String getAuthority(); +- + ---- ++==== + +-This method allows +-`AccessDecisionManager` s to obtain a precise `String` representation of the `GrantedAuthority`. +-By returning a representation as a `String`, a `GrantedAuthority` can be easily "read" by most `AccessDecisionManager` s. +-If a `GrantedAuthority` cannot be precisely represented as a `String`, the `GrantedAuthority` is considered "complex" and `getAuthority()` must return `null`. ++This method lets an ++`AccessDecisionManager` instance to obtain a precise `String` representation of the `GrantedAuthority`. ++By returning a representation as a `String`, a `GrantedAuthority` can be easily "`read`" by most `AccessDecisionManager` implementations. ++If a `GrantedAuthority` cannot be precisely represented as a `String`, the `GrantedAuthority` is considered "`complex`" and `getAuthority()` must return `null`. + +-An example of a "complex" `GrantedAuthority` would be an implementation that stores a list of operations and authority thresholds that apply to different customer account numbers. +-Representing this complex `GrantedAuthority` as a `String` would be quite difficult, and as a result the `getAuthority()` method should return `null`. +-This will indicate to any `AccessDecisionManager` that it will need to specifically support the `GrantedAuthority` implementation in order to understand its contents. ++An example of a "`complex`" `GrantedAuthority` would be an implementation that stores a list of operations and authority thresholds that apply to different customer account numbers. ++Representing this complex `GrantedAuthority` as a `String` would be quite difficult. As a result, the `getAuthority()` method should return `null`. ++This indicates to any `AccessDecisionManager` that it needs to support the specific `GrantedAuthority` implementation to understand its contents. + +-Spring Security includes one concrete `GrantedAuthority` implementation, `SimpleGrantedAuthority`. +-This allows any user-specified `String` to be converted into a `GrantedAuthority`. +-All `AuthenticationProvider` s included with the security architecture use `SimpleGrantedAuthority` to populate the `Authentication` object. ++Spring Security includes one concrete `GrantedAuthority` implementation: `SimpleGrantedAuthority`. ++This implementation lets any user-specified `String` be converted into a `GrantedAuthority`. ++All `AuthenticationProvider` instances included with the security architecture use `SimpleGrantedAuthority` to populate the `Authentication` object. + + + [[authz-pre-invocation]] + == Pre-Invocation Handling +-Spring Security provides interceptors which control access to secure objects such as method invocations or web requests. ++Spring Security provides interceptors that control access to secure objects, such as method invocations or web requests. + A pre-invocation decision on whether the invocation is allowed to proceed is made by the `AccessDecisionManager`. + + +@@ -44,6 +44,7 @@ A pre-invocation decision on whether the invocation is allowed to proceed is mad + The `AccessDecisionManager` is called by the `AbstractSecurityInterceptor` and is responsible for making final access control decisions. + The `AccessDecisionManager` interface contains three methods: + ++==== + [source,java] + ---- + void decide(Authentication authentication, Object secureObject, +@@ -53,32 +54,34 @@ boolean supports(ConfigAttribute attribute); + + boolean supports(Class clazz); + ---- ++==== + +-The ``AccessDecisionManager``'s `decide` method is passed all the relevant information it needs in order to make an authorization decision. +-In particular, passing the secure `Object` enables those arguments contained in the actual secure object invocation to be inspected. +-For example, let's assume the secure object was a `MethodInvocation`. +-It would be easy to query the `MethodInvocation` for any `Customer` argument, and then implement some sort of security logic in the `AccessDecisionManager` to ensure the principal is permitted to operate on that customer. ++The `decide` method of the `AccessDecisionManager` is passed all the relevant information it needs to make an authorization decision. ++In particular, passing the secure `Object` lets those arguments contained in the actual secure object invocation be inspected. ++For example, assume the secure object is a `MethodInvocation`. ++You can query the `MethodInvocation` for any `Customer` argument and then implement some sort of security logic in the `AccessDecisionManager` to ensure the principal is permitted to operate on that customer. + Implementations are expected to throw an `AccessDeniedException` if access is denied. + + The `supports(ConfigAttribute)` method is called by the `AbstractSecurityInterceptor` at startup time to determine if the `AccessDecisionManager` can process the passed `ConfigAttribute`. +-The `supports(Class)` method is called by a security interceptor implementation to ensure the configured `AccessDecisionManager` supports the type of secure object that the security interceptor will present. ++The `supports(Class)` method is called by a security interceptor implementation to ensure the configured `AccessDecisionManager` supports the type of secure object that the security interceptor presents. + + [[authz-voting-based]] + === Voting-Based AccessDecisionManager Implementations +-Whilst users can implement their own `AccessDecisionManager` to control all aspects of authorization, Spring Security includes several `AccessDecisionManager` implementations that are based on voting. +-<> illustrates the relevant classes. ++While users can implement their own `AccessDecisionManager` to control all aspects of authorization, Spring Security includes several `AccessDecisionManager` implementations that are based on voting. ++<> describes the relevant classes. ++ ++The following image shows the `AccessDecisionManager` interface: + + [[authz-access-voting]] + .Voting Decision Manager + image::images/access-decision-voting.png[] + +- +- +-Using this approach, a series of `AccessDecisionVoter` implementations are polled on an authorization decision. ++By using this approach, a series of `AccessDecisionVoter` implementations are polled on an authorization decision. + The `AccessDecisionManager` then decides whether or not to throw an `AccessDeniedException` based on its assessment of the votes. + + The `AccessDecisionVoter` interface has three methods: + ++==== + [source,java] + ---- + int vote(Authentication authentication, Object object, Collection attrs); +@@ -87,87 +90,88 @@ boolean supports(ConfigAttribute attribute); + + boolean supports(Class clazz); + ---- ++==== + +-Concrete implementations return an `int`, with possible values being reflected in the `AccessDecisionVoter` static fields `ACCESS_ABSTAIN`, `ACCESS_DENIED` and `ACCESS_GRANTED`. +-A voting implementation will return `ACCESS_ABSTAIN` if it has no opinion on an authorization decision. ++Concrete implementations return an `int`, with possible values being reflected in the `AccessDecisionVoter` static fields named `ACCESS_ABSTAIN`, `ACCESS_DENIED` and `ACCESS_GRANTED`. ++A voting implementation returns `ACCESS_ABSTAIN` if it has no opinion on an authorization decision. + If it does have an opinion, it must return either `ACCESS_DENIED` or `ACCESS_GRANTED`. + +-There are three concrete `AccessDecisionManager` s provided with Spring Security that tally the votes. +-The `ConsensusBased` implementation will grant or deny access based on the consensus of non-abstain votes. ++There are three concrete `AccessDecisionManager` implementations provided with Spring Security to tally the votes. ++The `ConsensusBased` implementation grants or denies access based on the consensus of non-abstain votes. + Properties are provided to control behavior in the event of an equality of votes or if all votes are abstain. +-The `AffirmativeBased` implementation will grant access if one or more `ACCESS_GRANTED` votes were received (i.e. a deny vote will be ignored, provided there was at least one grant vote). ++The `AffirmativeBased` implementation grants access if one or more `ACCESS_GRANTED` votes were received (in other words, a deny vote will be ignored, provided there was at least one grant vote). + Like the `ConsensusBased` implementation, there is a parameter that controls the behavior if all voters abstain. + The `UnanimousBased` provider expects unanimous `ACCESS_GRANTED` votes in order to grant access, ignoring abstains. +-It will deny access if there is any `ACCESS_DENIED` vote. +-Like the other implementations, there is a parameter that controls the behaviour if all voters abstain. ++It denies access if there is any `ACCESS_DENIED` vote. ++Like the other implementations, there is a parameter that controls the behavior if all voters abstain. + +-It is possible to implement a custom `AccessDecisionManager` that tallies votes differently. +-For example, votes from a particular `AccessDecisionVoter` might receive additional weighting, whilst a deny vote from a particular voter may have a veto effect. ++You can implement a custom `AccessDecisionManager` that tallies votes differently. ++For example, votes from a particular `AccessDecisionVoter` might receive additional weighting, while a deny vote from a particular voter may have a veto effect. + + + [[authz-role-voter]] + ==== RoleVoter +-The most commonly used `AccessDecisionVoter` provided with Spring Security is the simple `RoleVoter`, which treats configuration attributes as simple role names and votes to grant access if the user has been assigned that role. ++The most commonly used `AccessDecisionVoter` provided with Spring Security is the `RoleVoter`, which treats configuration attributes as role names and votes to grant access if the user has been assigned that role. + +-It will vote if any `ConfigAttribute` begins with the prefix `ROLE_`. +-It will vote to grant access if there is a `GrantedAuthority` which returns a `String` representation (via the `getAuthority()` method) exactly equal to one or more `ConfigAttributes` starting with the prefix `ROLE_`. +-If there is no exact match of any `ConfigAttribute` starting with `ROLE_`, the `RoleVoter` will vote to deny access. +-If no `ConfigAttribute` begins with `ROLE_`, the voter will abstain. ++It votes if any `ConfigAttribute` begins with the `ROLE_` prefix. ++It votes to grant access if there is a `GrantedAuthority` that returns a `String` representation (from the `getAuthority()` method) exactly equal to one or more `ConfigAttributes` that start with the `ROLE_` prefix. ++If there is no exact match of any `ConfigAttribute` starting with `ROLE_`, `RoleVoter` votes to deny access. ++If no `ConfigAttribute` begins with `ROLE_`, the voter abstains. + + + [[authz-authenticated-voter]] + ==== AuthenticatedVoter +-Another voter which we've implicitly seen is the `AuthenticatedVoter`, which can be used to differentiate between anonymous, fully-authenticated and remember-me authenticated users. +-Many sites allow certain limited access under remember-me authentication, but require a user to confirm their identity by logging in for full access. +- +-When we've used the attribute `IS_AUTHENTICATED_ANONYMOUSLY` to grant anonymous access, this attribute was being processed by the `AuthenticatedVoter`. +-See the Javadoc for this class for more information. ++Another voter which we have implicitly seen is the `AuthenticatedVoter`, which can be used to differentiate between anonymous, fully-authenticated, and remember-me authenticated users. ++Many sites allow certain limited access under remember-me authentication but require a user to confirm their identity by logging in for full access. + ++When we have used the `IS_AUTHENTICATED_ANONYMOUSLY` attribute to grant anonymous access, this attribute was being processed by the `AuthenticatedVoter`. ++For more information, see ++{security-api-url}org/springframework/security/access/vote/AuthenticatedVoter.html[`AuthenticatedVoter`]. + + [[authz-custom-voter]] + ==== Custom Voters +-Obviously, you can also implement a custom `AccessDecisionVoter` and you can put just about any access-control logic you want in it. ++You can also implement a custom `AccessDecisionVoter` and put just about any access-control logic you want in it. + It might be specific to your application (business-logic related) or it might implement some security administration logic. +-For example, you'll find a https://spring.io/blog/2009/01/03/spring-security-customization-part-2-adjusting-secured-session-in-real-time[blog article] on the Spring web site which describes how to use a voter to deny access in real-time to users whose accounts have been suspended. ++For example, on the Spring web site, you can find a https://spring.io/blog/2009/01/03/spring-security-customization-part-2-adjusting-secured-session-in-real-time[blog article] that describes how to use a voter to deny access in real-time to users whose accounts have been suspended. + + + [[authz-after-invocation-handling]] + == After Invocation Handling +-Whilst the `AccessDecisionManager` is called by the `AbstractSecurityInterceptor` before proceeding with the secure object invocation, some applications need a way of modifying the object actually returned by the secure object invocation. +-Whilst you could easily implement your own AOP concern to achieve this, Spring Security provides a convenient hook that has several concrete implementations that integrate with its ACL capabilities. ++While the `AccessDecisionManager` is called by the `AbstractSecurityInterceptor` before proceeding with the secure object invocation, some applications need a way to modify the object actually returned by the secure object invocation. ++While you could implement your own AOP concern to achieve this, Spring Security provides a convenient hook that has several concrete implementations that integrate with its ACL capabilities. + +-<> illustrates Spring Security's `AfterInvocationManager` and its concrete implementations. ++<> describes Spring Security's `AfterInvocationManager` and its concrete implementations. ++The following image shows the `AfterInvocationManager`: + + [[authz-after-invocation]] + .After Invocation Implementation + image::images/after-invocation.png[] + +-Like many other parts of Spring Security, `AfterInvocationManager` has a single concrete implementation, `AfterInvocationProviderManager`, which polls a list of `AfterInvocationProvider` s. ++Like many other parts of Spring Security, `AfterInvocationManager` has a single concrete implementation, `AfterInvocationProviderManager`, which polls a list of `AfterInvocationProvider` instances. + Each `AfterInvocationProvider` is allowed to modify the return object or throw an `AccessDeniedException`. +-Indeed multiple providers can modify the object, as the result of the previous provider is passed to the next in the list. ++Indeed, multiple providers can modify the object, as the result of the previous provider is passed to the next in the list. + +-Please be aware that if you're using `AfterInvocationManager`, you will still need configuration attributes that allow the ``MethodSecurityInterceptor``'s `AccessDecisionManager` to allow an operation. +-If you're using the typical Spring Security included `AccessDecisionManager` implementations, having no configuration attributes defined for a particular secure method invocation will cause each `AccessDecisionVoter` to abstain from voting. +-In turn, if the `AccessDecisionManager` property "`allowIfAllAbstainDecisions`" is `false`, an `AccessDeniedException` will be thrown. +-You may avoid this potential issue by either (i) setting "`allowIfAllAbstainDecisions`" to `true` (although this is generally not recommended) or (ii) simply ensure that there is at least one configuration attribute that an `AccessDecisionVoter` will vote to grant access for. ++Note that, if you use `AfterInvocationManager`, you still need configuration attributes to let the `AccessDecisionManager` of the `MethodSecurityInterceptor` allow an operation. ++If you use the typical Spring Security `AccessDecisionManager` implementations, having no configuration attributes defined for a particular secure method invocation causes each `AccessDecisionVoter` to abstain from voting. ++In turn, if the `allowIfAllAbstainDecisions` property of `AccessDecisionManager` is `false`, an `AccessDeniedException` is thrown. ++You may avoid this potential issue by either (i) setting `allowIfAllAbstainDecisions` to `true` (although this is generally not recommended) or (ii) ensuring that there is at least one configuration attribute for which an `AccessDecisionVoter` votes to grant access. + This latter (recommended) approach is usually achieved through a `ROLE_USER` or `ROLE_AUTHENTICATED` configuration attribute. + + + [[authz-hierarchical-roles]] + == Hierarchical Roles +-It is a common requirement that a particular role in an application should automatically "include" other roles. ++It is a common requirement that a particular role in an application should automatically "`include`" other roles. + For example, in an application which has the concept of an "admin" and a "user" role, you may want an admin to be able to do everything a normal user can. +-To achieve this, you can either make sure that all admin users are also assigned the "user" role. +-Alternatively, you can modify every access constraint which requires the "user" role to also include the "admin" role. +-This can get quite complicated if you have a lot of different roles in your application. ++To achieve this, you can either make sure that all admin users are also assigned the "`user`" role or you can modify every access constraint which requires the "`user`" role to also include the "`admin`" role. ++This can get complicated if you have a lot of different roles in your application. + +-The use of a role-hierarchy allows you to configure which roles (or authorities) should include others. +-An extended version of Spring Security's <>, `RoleHierarchyVoter`, is configured with a `RoleHierarchy`, from which it obtains all the "reachable authorities" which the user is assigned. +-A typical configuration might look like this: ++The use of a role-hierarchy lets you configure which roles (or authorities) should include others. ++An extended version of Spring Security's <>, `RoleHierarchyVoter`, is configured with a `RoleHierarchy`, from which it obtains all the "`reachable authorities`" that the user is assigned. ++The following example shows a typical configuration: + ++==== + [source,xml] + ---- +- + + + +@@ -182,10 +186,11 @@ A typical configuration might look like this: + + + ---- ++==== + +-Here we have four roles in a hierarchy `ROLE_ADMIN => ROLE_STAFF => ROLE_USER => ROLE_GUEST`. +-A user who is authenticated with `ROLE_ADMIN`, will behave as if they have all four roles when security constraints are evaluated against an `AccessDecisionManager` configured with the above `RoleHierarchyVoter`. +-The `>` symbol can be thought of as meaning "includes". ++Here, we have four roles in a hierarchy `ROLE_ADMIN => ROLE_STAFF => ROLE_USER => ROLE_GUEST`. ++A user who is authenticated with `ROLE_ADMIN` behaves as if they have all four roles when security constraints are evaluated against an `AccessDecisionManager` configured with the preceding `RoleHierarchyVoter`. ++The `>` symbol can be thought of as meaning "`includes`". + +-Role hierarchies offer a convenient means of simplifying the access-control configuration data for your application and/or reducing the number of authorities which you need to assign to a user. +-For more complex requirements you may wish to define a logical mapping between the specific access-rights your application requires and the roles that are assigned to users, translating between the two when loading the user information. ++Role hierarchies offer a convenient means of simplifying the access-control configuration data for your application and reducing the number of authorities that you need to assign to a user. ++For more complex requirements, you may wish to define a logical mapping between the specific access-rights your application requires and the roles that are assigned to users, translating between the two when loading the user information. +diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authorization/authorize-requests.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authorization/authorize-requests.adoc +index 31ce88ecee..48ad3a3e15 100644 +--- a/docs/manual/src/docs/asciidoc/_includes/servlet/authorization/authorize-requests.adoc ++++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authorization/authorize-requests.adoc +@@ -3,27 +3,28 @@ + :figures: images/servlet/authorization + :icondir: images/icons + +-This section builds on <> by digging deeper into how <> works within Servlet based applications. ++This section builds on <> by digging deeper into how <> works within Servlet-based applications. + +-The {security-api-url}org/springframework/security/web/access/intercept/FilterSecurityInterceptor.html[`FilterSecurityInterceptor`] provides <> for ``HttpServletRequest``s. ++The {security-api-url}org/springframework/security/web/access/intercept/FilterSecurityInterceptor.html[`FilterSecurityInterceptor`] provides <> for `HttpServletRequest` instances. + It is inserted into the <> as one of the <>. + ++The following image shows the role of `FilterSecurityInterceptor`: ++ + .Authorize HttpServletRequest + image::{figures}/filtersecurityinterceptor.png[] + +-* image:{icondir}/number_1.png[] First, the `FilterSecurityInterceptor` obtains an <> from the <>. +-* image:{icondir}/number_2.png[] Second, `FilterSecurityInterceptor` creates a {security-api-url}org/springframework/security/web/FilterInvocation.html[`FilterInvocation`] from the `HttpServletRequest`, `HttpServletResponse`, and `FilterChain` that are passed into the `FilterSecurityInterceptor`. +-// FIXME: link to FilterInvocation +-* image:{icondir}/number_3.png[] Next, it passes the `FilterInvocation` to `SecurityMetadataSource` to get the ``ConfigAttribute``s. +-* image:{icondir}/number_4.png[] Finally, it passes the `Authentication`, `FilterInvocation`, and ``ConfigAttribute``s to the `AccessDecisionManager`. +-** image:{icondir}/number_5.png[] If authorization is denied, an `AccessDeniedException` is thrown. +-In this case the <> handles the `AccessDeniedException`. +-** image:{icondir}/number_6.png[] If access is granted, `FilterSecurityInterceptor` continues with the <> which allows the application to process normally. ++image:{icondir}/number_1.png[] The `FilterSecurityInterceptor` obtains an <> from the <>. ++image:{icondir}/number_2.png[] `FilterSecurityInterceptor` creates a {security-api-url}org/springframework/security/web/FilterInvocation.html[`FilterInvocation`] from the `HttpServletRequest`, `HttpServletResponse`, and `FilterChain` that are passed into the `FilterSecurityInterceptor`. ++image:{icondir}/number_3.png[] It passes the `FilterInvocation` to `SecurityMetadataSource` to get the ``ConfigAttribute``s. ++image:{icondir}/number_4.png[] It passes the `Authentication`, `FilterInvocation`, and ``ConfigAttribute``s to the `AccessDecisionManager`. ++image:{icondir}/number_5.png[] If authorization is denied, an `AccessDeniedException` is thrown. ++In this case, the <> handles the `AccessDeniedException`. ++image:{icondir}/number_6.png[] If access is granted, `FilterSecurityInterceptor` continues with the <>, which lets the application process normally. + + // configuration (xml/java) + +-By default, Spring Security's authorization will require all requests to be authenticated. +-The explicit configuration looks like: ++By default, Spring Security's authorization requires all requests to be authenticated. ++The following listing shows the explicit configuration: + + .Every Request Must be Authenticated + ==== +@@ -62,7 +63,7 @@ fun configure(http: HttpSecurity) { + ---- + ==== + +-We can configure Spring Security to have different rules by adding more rules in order of precedence. ++We can configure Spring Security to have different rules by adding more rules in order of precedence: + + .Authorize Requests + ==== +@@ -115,13 +116,13 @@ fun configure(http: HttpSecurity) { + } + ---- + ==== +-<1> There are multiple authorization rules specified. +-Each rule is considered in the order they were declared. +-<2> We specified multiple URL patterns that any user can access. +-Specifically, any user can access a request if the URL starts with "/resources/", equals "/signup", or equals "/about". +-<3> Any URL that starts with "/admin/" will be restricted to users who have the role "ROLE_ADMIN". +-You will notice that since we are invoking the `hasRole` method we do not need to specify the "ROLE_" prefix. +-<4> Any URL that starts with "/db/" requires the user to have both "ROLE_ADMIN" and "ROLE_DBA". +-You will notice that since we are using the `hasRole` expression we do not need to specify the "ROLE_" prefix. +-<5> Any URL that has not already been matched on is denied access. ++<1> Multiple authorization rules are specified. ++Each rule is considered in the order in which it is declared. ++<2> Specify multiple URL patterns that any user can access. ++Specifically, any user can access a request if the URL starts with `/resources/`, equals `/signup`, or equals `/about`. ++<3> Any URL that starts with `/admin/` is restricted to users who have the `ROLE_ADMIN` role. ++Notice that, since we invoke the `hasRole` method, we need not specify the `ROLE_` prefix. ++<4> Any URL that starts with `/db/` requires the user to have both `ROLE_ADMIN` and `ROLE_DBA`. ++Notice that, since we use the `hasRole` expression, we need not specify the `ROLE_` prefix. ++<5> Any URL that has not already been matched is denied access. + This is a good strategy if you do not want to accidentally forget to update your authorization rules. +diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authorization/expression-based.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authorization/expression-based.adoc +index 76d5f0ae5a..a9f15822f6 100644 +--- a/docs/manual/src/docs/asciidoc/_includes/servlet/authorization/expression-based.adoc ++++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authorization/expression-based.adoc +@@ -1,20 +1,20 @@ + + [[el-access]] + == 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 seen before. +-Expression-based access control is built on the same architecture but allows complicated Boolean logic to be encapsulated in a single expression. ++Spring Security 3.0 introduced the ability to use Spring Expression Language (SpEL) expressions as an authorization mechanism in addition to the existing configuration attributes and access-decision voters. ++Expression-based access control is built on the same architecture but lets complicated Boolean logic be encapsulated in a single expression. + + + === 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. ++Spring Security uses SpEL 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 to provide built-in expressions and access to values, such as the current principal. + + + [[el-common-built-in]] + ==== 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. ++This provides some common expressions that are available in both web and method security: + + [[common-expressions]] + .Common built-in expressions +@@ -24,95 +24,94 @@ This provides some common expressions which are available in both web and method + | `hasRole(String role)` + | Returns `true` if the current principal has the specified role. + +-For example, `hasRole('admin')` ++Example: `hasRole('admin')` + +-By default if the supplied role does not start with 'ROLE_' it will be added. +-This can be customized by modifying the `defaultRolePrefix` on `DefaultWebSecurityExpressionHandler`. ++By default, if the supplied role does not start with `ROLE_`, it is added. ++You can customize this behavior by modifying the `defaultRolePrefix` on `DefaultWebSecurityExpressionHandler`. + + | `hasAnyRole(String... roles)` + | Returns `true` if the current principal has any of the supplied roles (given as a comma-separated list of strings). + +-For example, `hasAnyRole('admin', 'user')` ++Example: `hasAnyRole('admin', 'user')`. + +-By default if the supplied role does not start with 'ROLE_' it will be added. +-This can be customized by modifying the `defaultRolePrefix` on `DefaultWebSecurityExpressionHandler`. ++By default, if the supplied role does not start with `ROLE_`, it is added. ++You can customize this behavior by modifying the `defaultRolePrefix` on `DefaultWebSecurityExpressionHandler`. + + | `hasAuthority(String authority)` + | Returns `true` if the current principal has the specified authority. + +-For example, `hasAuthority('read')` ++Example: `hasAuthority('read')` + + | `hasAnyAuthority(String... authorities)` +-| Returns `true` if the current principal has any of the supplied authorities (given as a comma-separated list of strings) ++| Returns `true` if the current principal has any of the supplied authorities (given as a comma-separated list of strings). + +-For example, `hasAnyAuthority('read', 'write')` ++Example: `hasAnyAuthority('read', 'write')`. + + | `principal` +-| Allows direct access to the principal object representing the current user ++| Allows direct access to the principal object that represents the current user. + + | `authentication` +-| Allows direct access to the current `Authentication` object obtained from the `SecurityContext` ++| Allows direct access to the current `Authentication` object obtained from the `SecurityContext`. + + | `permitAll` +-| Always evaluates to `true` ++| Always evaluates to `true`. + + | `denyAll` +-| Always evaluates to `false` ++| Always evaluates to `false`. + + | `isAnonymous()` +-| Returns `true` if the current principal is an anonymous user ++| Returns `true` if the current principal is an anonymous user. + + | `isRememberMe()` +-| Returns `true` if the current principal is a remember-me user ++| Returns `true` if the current principal is a remember-me user. + + | `isAuthenticated()` +-| Returns `true` if the user is not anonymous ++| Returns `true` if the user is not anonymous. + + | `isFullyAuthenticated()` +-| Returns `true` if the user is not an anonymous or a remember-me user ++| Returns `true` if the user is not an anonymous and is not a remember-me user. + + | `hasPermission(Object target, Object permission)` + | Returns `true` if the user has access to the provided target for the given permission. +-For example, `hasPermission(domainObject, 'read')` ++Example, `hasPermission(domainObject, 'read')`. + + | `hasPermission(Object targetId, String targetType, Object permission)` + | Returns `true` if the user has access to the provided target for the given permission. +-For example, `hasPermission(1, 'com.example.domain.Message', 'read')` ++Example, `hasPermission(1, 'com.example.domain.Message', 'read')`. + |=== + + +- + [[el-access-web]] + === Web Security Expressions +-To use expressions to secure individual URLs, you would first need to set the `use-expressions` attribute in the `` element to `true`. +-Spring Security will then expect the `access` attributes of the `` elements to contain Spring EL expressions. +-The expressions should evaluate to a Boolean, defining whether access should be allowed or not. +-For example: ++To use expressions to secure individual URLs, you first need to set the `use-expressions` attribute in the `` element to `true`. ++Spring Security then expects the `access` attributes of the `` elements to contain SpEL expressions. ++Each expression should evaluate to a Boolean, defining whether access should be allowed or not. ++The following listing shows an example: + ++==== + [source,xml] + ---- +- + + + ... + +- + ---- ++==== + +-Here we have defined that the "admin" area of an application (defined by the URL pattern) should only be available to users who have the granted authority "admin" and whose IP address matches a local subnet. +-We've already seen the built-in `hasRole` expression in the previous section. +-The expression `hasIpAddress` is an additional built-in expression which is specific to web security. ++Here, we have defined that the `admin` area of an application (defined by the URL pattern) should be available only to users who have the granted authority (`admin`) and whose IP address matches a local subnet. ++We have already seen the built-in `hasRole` expression in the previous section. ++The `hasIpAddress` expression is an additional built-in expression that is specific to web security. + It is defined by the `WebSecurityExpressionRoot` class, an instance of which is used as the expression root object when evaluating web-access expressions. +-This object also directly exposed the `HttpServletRequest` object under the name `request` so you can invoke the request directly in an expression. +-If expressions are being used, a `WebExpressionVoter` will be added to the `AccessDecisionManager` which is used by the namespace. +-So if you aren't using the namespace and want to use expressions, you will have to add one of these to your configuration. ++This object also directly exposed the `HttpServletRequest` object under the name `request` so that you can invoke the request directly in an expression. ++If expressions are being used, a `WebExpressionVoter` is added to the `AccessDecisionManager` that is used by the namespace. ++So, if you do not use the namespace and want to use expressions, you have to add one of these to your configuration. + + [[el-access-web-beans]] + ==== 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: ++For example, you could use the following, assuming you have a Bean with the name of `webSecurity` that contains the following method signature: + + ==== + .Java +@@ -136,7 +135,7 @@ class WebSecurity { + ---- + ==== + +-You could refer to the method using: ++You could then refer to the method as follows: + + .Refer to method + ==== +@@ -174,11 +173,11 @@ http { + [[el-access-web-path-variables]] + ==== 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}+`. ++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 a URL path in a format of `+/user/{userId}+`. + + You can easily refer to the path variable by placing it in the pattern. +-For example, if you had a Bean with the name of `webSecurity` that contains the following method signature: ++For example, you could use the following if you had a Bean with the name of `webSecurity` that contains the following method signature: + + ==== + .Java +@@ -202,7 +201,7 @@ class WebSecurity { + ---- + ==== + +-You could refer to the method using: ++You could then refer to the method as follows: + + .Path Variables + ==== +@@ -237,28 +236,30 @@ 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`. ++In this configuration, URLs that match would pass in the path variable (and convert it) into the `checkUserId` method. ++For example, if the URL were `/user/123/resource`, the ID passed in would be `123`. + + === 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. ++Spring Security 3.0 introduced some new annotations to allow comprehensive support for the use of expressions. + + + [[el-pre-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`. ++There are four annotations that 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: + ++==== + [source,xml] + ---- + + ---- ++==== + + ===== 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 "Contacts" sample application) ++The most obviously useful annotation is `@PreAuthorize`, which decides whether a method can actually be invoked or not. ++The following example (from the "Contacts" sample application) uses the `@PreAuthorize` annotation: + + ==== + .Java +@@ -276,9 +277,9 @@ fun create(contact: Contact?) + ---- + ==== + +-which means that access will only be allowed for users with the role "ROLE_USER". +-Obviously the same thing could easily be achieved using a traditional configuration and a simple configuration attribute for the required role. +-But what about: ++This means that access is allowed only for users with the `ROLE_USER` role. ++Obviously, the same thing could easily be achieved by using a traditional configuration and a simple configuration attribute for the required role. ++However, consider the following example: + + ==== + .Java +@@ -296,20 +297,18 @@ fun deletePermission(contact: Contact?, recipient: Sid?, permission: Permission? + ---- + ==== + +-Here we're actually using a method argument as part of the expression to decide whether the current user has the "admin"permission for the given contact. +-The built-in `hasPermission()` expression is linked into the Spring Security ACL module through the application context, as we'll <>. ++Here, we actually use a method argument as part of the expression to decide whether the current user has the `admin` permission for the given contact. ++The built-in `hasPermission()` expression is linked into the Spring Security ACL module through the application context, as we <>. + You can access any of the method arguments by name as expression variables. + +-There are a number of ways in which Spring Security can resolve the method arguments. ++Spring Security can resolve the method arguments in a number of ways. + Spring Security uses `DefaultSecurityParameterNameDiscoverer` to discover the parameter names. +-By default, the following options are tried for a method as a whole. +- +-* If Spring Security's `@P` annotation is present on a single argument to the method, the value will be used. +-This is useful for interfaces compiled with a JDK prior to JDK 8 which do not contain any information about the parameter names. +-For example: ++By default, the following options are tried for a method. + ++* If Spring Security's `@P` annotation is present on a single argument to the method, the value is used. ++This is useful for interfaces compiled with a JDK prior to JDK 8 (which do not contain any information about the parameter names). ++The following example uses the `@P` annotation: + + +- + ==== + .Java + [source,java,role="primary"] +@@ -333,17 +332,13 @@ import org.springframework.security.access.method.P + fun doSomething(@P("c") contact: Contact?) + ---- + ==== +- + + ++Behind the scenes, this is implemented by using `AnnotationParameterNameDiscoverer`, which you can customize to support the value attribute of any specified annotation. + +-Behind the scenes this is implemented using `AnnotationParameterNameDiscoverer` which can be customized to support the value attribute of any specified annotation. +- +-* If Spring Data's `@Param` annotation is present on at least one parameter for the method, the value will be used. ++* If Spring Data's `@Param` annotation is present on at least one parameter for the method, the value is used. + This is useful for interfaces compiled with a JDK prior to JDK 8 which do not contain any information about the parameter names. +-For example: +- ++The following example uses the `@Param` annotation: + + +- + ==== + .Java + [source,java,role="primary"] +@@ -367,23 +362,19 @@ import org.springframework.data.repository.query.Param + fun findContactByName(@Param("n") name: String?): Contact? + ---- + ==== +- + + ++Behind the scenes, this is implemented by using `AnnotationParameterNameDiscoverer`, which you can customize to support the value attribute of any specified annotation. + +-Behind the scenes this is implemented using `AnnotationParameterNameDiscoverer` which can be customized to support the value attribute of any specified annotation. +- +-* If JDK 8 was used to compile the source with the -parameters argument and Spring 4+ is being used, then the standard JDK reflection API is used to discover the parameter names. ++* If JDK 8 was used to compile the source with the `-parameters` argument and Spring 4+ is being used, the standard JDK reflection API is used to discover the parameter names. + This works on both classes and interfaces. + +-* Last, if the code was compiled with the debug symbols, the parameter names will be discovered using the debug symbols. +-This will not work for interfaces since they do not have debug information about the parameter names. ++* Finally, if the code was compiled with the debug symbols, the parameter names are discovered by using the debug symbols. ++This does not work for interfaces, since they do not have debug information about the parameter names. + For interfaces, annotations or the JDK 8 approach must be used. + + .[[el-pre-post-annotations-spel]] +--- +-Any Spring-EL functionality is available within the expression, so you can also access properties on the arguments. +-For example, if you wanted a particular method to only allow access to a user whose username matched that of the contact, you could write +--- ++Any SpEL functionality is available within the expression, so you can also access properties on the arguments. ++For example, if you wanted a particular method to allow access only to a user whose username matched that of the contact, you could write + + ==== + .Java +@@ -401,21 +392,19 @@ fun doSomething(contact: Contact?) + ---- + ==== + +-Here we are accessing another built-in expression, `authentication`, which is the `Authentication` stored in the security context. +-You can also access its "principal" property directly, using the expression `principal`. +-The value will often be a `UserDetails` instance, so you might use an expression like `principal.username` or `principal.enabled`. ++Here, we access another built-in expression, `authentication`, which is the `Authentication` stored in the security context. ++You can also access its `principal` property directly, by using the `principal` expression. ++The value is often a `UserDetails` instance, so you might use an expression such as `principal.username` or `principal.enabled`. + + .[[el-pre-post-annotations-post]] +--- + Less commonly, you may wish to perform an access-control check after the method has been invoked. +-This can be achieved using the `@PostAuthorize` annotation. ++You can do so by 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 +-Spring Security supports filtering of collections, arrays, maps and streams using expressions. ++Spring Security supports filtering of collections, arrays, maps, and streams by using expressions. + This is most commonly performed on the return value of a method. +-For example: ++The following example uses `@PostFilter`: + + ==== + .Java +@@ -436,29 +425,30 @@ fun getAll(): List + ==== + + When using the `@PostFilter` annotation, Spring Security iterates through the returned collection or map and removes any elements for which the supplied expression is false. +-For an array, a new array instance will be returned containing filtered elements. +-The name `filterObject` refers to the current object in the collection. +-In case when a map is used it will refer to the current `Map.Entry` object which allows one to use `filterObject.key` or `filterObject.value` in the expresion. +-You can also filter before the method call, using `@PreFilter`, though this is a less common requirement. +-The syntax is just the same, but if there is more than one argument which is a collection type then you have to select one by name using the `filterTarget` property of this annotation. ++For an array, a new array instance that contains filtered elements is returned. ++`filterObject` refers to the current object in the collection. ++When a map is used, it refers to the current `Map.Entry` object, which lets you use `filterObject.key` or `filterObject.value` in the expression. ++You can also filter before the method call by using `@PreFilter`, though this is a less common requirement. ++The syntax is the same. However, if there is more than one argument that is a collection type, you have to select one by name using the `filterTarget` property of this annotation. + + Note that filtering is obviously not a substitute for tuning your data retrieval queries. +-If you are filtering large collections and removing many of the entries then this is likely to be inefficient. ++If you are filtering large collections and removing many of the entries, this is likely to be inefficient. + + + [[el-method-built-in]] + ==== Built-In Expressions +-There are some built-in expressions which are specific to method security, which we have already seen in use above. ++There are some built-in expressions that are specific to method security, which we have already seen in use earlier. + 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 + `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 is intended to bridge between the expression system and Spring Security's ACL system, letting you 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. + The interface has two methods: + ++==== + [source,java] + ---- + boolean hasPermission(Authentication authentication, Object targetDomainObject, +@@ -467,17 +457,19 @@ boolean hasPermission(Authentication authentication, Object targetDomainObject, + boolean hasPermission(Authentication authentication, Serializable targetId, + String targetType, Object permission); + ---- ++==== + +-which map directly to the available versions of the expression, with the exception that the first argument (the `Authentication` object) is not supplied. ++These methods map directly to the available versions of the expression, with the exception that the first argument (the `Authentication` object) is not supplied. + The first is used in situations where the domain object, to which access is being controlled, is already loaded. +-Then expression will return true if the current user has the given permission for that object. +-The second version is used in cases where the object is not loaded, but its identifier is known. +-An abstract "type" specifier for the domain object is also required, allowing the correct ACL permissions to be loaded. +-This has traditionally been the Java class of the object, but does not have to be as long as it is consistent with how the permissions are loaded. ++Then the expression returns `true` if the current user has the given permission for that object. ++The second version is used in cases where the object is not loaded but its identifier is known. ++An abstract "`type`" specifier for the domain object is also required, letting the correct ACL permissions be loaded. ++This has traditionally been the Java class of the object but does not have to be, as long as it is consistent with how the permissions are loaded. + + To use `hasPermission()` expressions, you have to explicitly configure a `PermissionEvaluator` in your application context. +-This would look something like this: ++The following example shows how to do so: + ++==== + [source,xml] + ---- + +@@ -489,23 +481,26 @@ This would look something like this: + + + ---- ++==== + + Where `myPermissionEvaluator` is the bean which implements `PermissionEvaluator`. +-Usually this will be the implementation from the ACL module which is called `AclPermissionEvaluator`. +-See the "Contacts" sample application configuration for more details. ++Usually, this is the implementation from the ACL module, which is called `AclPermissionEvaluator`. ++See the "`Contacts`" sample application configuration for more details. + + ===== 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. ++This is especially convenient if you find that you repeat the same complex expression throughout your code base. + For example, consider the following: + ++==== + [source,java] + ---- + @PreAuthorize("#contact.name == authentication.name") + ---- ++==== + +-Instead of repeating this everywhere, we can create a meta annotation that can be used instead. ++Instead of repeating this everywhere, you can create a meta annotation: + + ==== + .Java +@@ -525,6 +520,5 @@ annotation class ContactPermission + ---- + ==== + +-Meta annotations can be used for any of the Spring Security method security annotations. +-In order to remain compliant with the specification JSR-250 annotations do not support meta annotations. +- ++You can use meta annotations for any of the Spring Security method security annotations. ++To remain compliant with the specification, JSR-250 annotations do not support meta annotations. +diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authorization/index.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authorization/index.adoc +index 2e4dfc59ac..d16b22ca15 100644 +--- a/docs/manual/src/docs/asciidoc/_includes/servlet/authorization/index.adoc ++++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authorization/index.adoc +@@ -1,10 +1,10 @@ + [[servlet-authorization]] + = Authorization + The advanced authorization capabilities within Spring Security represent one of the most compelling reasons for its popularity. +-Irrespective of how you choose to authenticate - whether using a Spring Security-provided mechanism and provider, or integrating with a container or other non-Spring Security authentication authority - you will find the authorization services can be used within your application in a consistent and simple way. ++Irrespective of how you choose to authenticate (whether using a Spring Security-provided mechanism and provider or integrating with a container or other non-Spring Security authentication authority), the authorization services can be used within your application in a consistent and simple way. + +-In this part we'll explore the different `AbstractSecurityInterceptor` implementations, which were introduced in Part I. +-We then move on to explore how to fine-tune authorization through use of domain access control lists. ++In this part, we explore the different `AbstractSecurityInterceptor` implementations, which were introduced in Part I. ++We then move on to explore how to fine-tune authorization through the use of domain access control lists. + + include::architecture.adoc[leveloffset=+1] + +@@ -17,4 +17,3 @@ include::secure-objects.adoc[] + include::method-security.adoc[] + + include::acls.adoc[] +- +diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authorization/method-security.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authorization/method-security.adoc +index 573412f6bf..30a4ccc234 100644 +--- a/docs/manual/src/docs/asciidoc/_includes/servlet/authorization/method-security.adoc ++++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authorization/method-security.adoc +@@ -1,16 +1,17 @@ + [[jc-method]] + == Method Security + +-From version 2.0 onwards Spring Security has improved support substantially for adding security to your service layer methods. ++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 <>. +-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. ++From 3.0, you can also make use of new <>. ++You can apply security to a single bean, by using the `intercept-methods` element to decorate the bean declaration, or you can secure multiple beans across the entire service layer by using AspectJ style pointcuts. + + === 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. ++We can enable annotation-based security by using the `@EnableGlobalMethodSecurity` annotation on any `@Configuration` instance. ++The following example enables Spring Security's `@Secured` annotation: + ++==== + [source,java] + ---- + @EnableGlobalMethodSecurity(securedEnabled = true) +@@ -18,11 +19,13 @@ public class MethodSecurityConfig { + // ... + } + ---- ++==== + + Adding an annotation to a method (on a class or interface) would then limit the access to that method accordingly. + Spring Security's native annotation support defines a set of attributes for the method. +-These will be passed to the AccessDecisionManager for it to make the actual decision: ++These are passed to the `AccessDecisionManager` for it to make the actual decision: + ++==== + [source,java] + ---- + public interface BankService { +@@ -37,9 +40,11 @@ public Account[] findAccounts(); + public Account post(Account account, double amount); + } + ---- ++==== + +-Support for JSR-250 annotations can be enabled using ++Support for JSR-250 annotations can be enabled by using: + ++==== + [source,java] + ---- + @EnableGlobalMethodSecurity(jsr250Enabled = true) +@@ -47,10 +52,12 @@ public class MethodSecurityConfig { + // ... + } + ---- ++==== + +-These are standards-based and allow simple role-based constraints to be applied but do not have the power Spring Security's native annotations. +-To use the new expression-based syntax, you would use ++These are standards-based and let simple role-based constraints be applied but do not have the power Spring Security's native annotations. ++To use the new expression-based syntax, you would use: + ++==== + [source,java] + ---- + @EnableGlobalMethodSecurity(prePostEnabled = true) +@@ -58,9 +65,11 @@ public class MethodSecurityConfig { + // ... + } + ---- ++==== + +-and the equivalent Java code would be ++The equivalent Java code is: + ++==== + [source,java] + ---- + public interface BankService { +@@ -75,13 +84,15 @@ public Account[] findAccounts(); + public Account post(Account account, double amount); + } + ---- ++==== + + === 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. ++Sometimes, you may need to perform operations that are more complicated than are possible with the `@EnableGlobalMethodSecurity` annotation. ++For these instances, you can extend the `GlobalMethodSecurityConfiguration`, ensuring that the `@EnableGlobalMethodSecurity` annotation is present on your subclass. + For example, if you wanted to provide a custom `MethodSecurityExpressionHandler`, you could use the following configuration: + ++==== + [source,java] + ---- + @EnableGlobalMethodSecurity(prePostEnabled = true) +@@ -93,24 +104,29 @@ public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration { + } + } + ---- ++==== + +-For additional information about methods that can be overridden, refer to the `GlobalMethodSecurityConfiguration` Javadoc. ++For additional information about methods that can be overridden, see the Javadoc for the {security-api-url}org/springframework/security/config/annotation/method/configuration/GlobalMethodSecurityConfiguration.html[`GlobalMethodSecurityConfiguration`] class. + + [[ns-global-method]] + === The 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. ++This element is used to enable annotation-based security in your application (by setting the appropriate attributes on the element) and to group together security pointcut declarations that are applied across your entire application context. + You should only declare one `` element. +-The following declaration would enable support for Spring Security's `@Secured`: ++The following declaration enables support for Spring Security's `@Secured`: + ++==== + [source,xml] + ---- + + ---- ++==== + +-Adding an annotation to a method (on an class or interface) would then limit the access to that method accordingly. ++Adding an annotation to a method (on a class or interface) would then limit the access to that method accordingly. + Spring Security's native annotation support defines a set of attributes for the method. +-These will be passed to the `AccessDecisionManager` for it to make the actual decision: ++These are passed to the `AccessDecisionManager` for it to make the actual decision. ++The following example shows the `@Secured` annotation in a typical interface: + ++==== + [source,java] + ---- + public interface BankService { +@@ -125,24 +141,30 @@ public Account[] findAccounts(); + public Account post(Account account, double amount); + } + ---- ++==== + +-Support for JSR-250 annotations can be enabled using ++Support for JSR-250 annotations can be enabled by using: + ++==== + [source,xml] + ---- + + ---- ++==== + +-These are standards-based and allow simple role-based constraints to be applied but do not have the power Spring Security's native annotations. +-To use the new expression-based syntax, you would use ++These are standards-based and allow simple role-based constraints to be applied, but they do not have the power Spring Security's native annotations. ++To use the expression-based syntax, use: + ++==== + [source,xml] + ---- + + ---- ++==== + +-and the equivalent Java code would be ++The equivalent Java code is: + ++==== + [source,java] + ---- + public interface BankService { +@@ -157,27 +179,23 @@ public Account[] findAccounts(); + public Account post(Account account, double amount); + } + ---- ++==== + + Expression-based annotations are a good choice if you need to define simple rules that go beyond checking the role names against the user's list of authorities. + +-[NOTE] +-==== +-The annotated methods will only be secured for instances which are defined as Spring beans (in the same application context in which method-security is enabled). ++NOTE: The annotated methods will only be secured for instances which are defined as Spring beans (in the same application context in which method-security is enabled). + If you want to secure instances which are not created by Spring (using the `new` operator, for example) then you need to use AspectJ. +-==== + +-[NOTE] +-==== +-You can enable more than one type of annotation in the same application, but only one type should be used for any interface or class as the behaviour will not be well-defined otherwise. ++NOTE: You can enable more than one type of annotation in the same application, but only one type should be used for any interface or class as the behaviour will not be well-defined otherwise. + If two annotations are found which apply to a particular method, then only one of them will be applied. +-==== + + [[ns-protect-pointcut]] +-=== Adding Security Pointcuts using protect-pointcut ++=== Adding Security Pointcuts by 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. ++`protect-pointcut` is particularly powerful, as it lets you apply security to many beans with only a simple declaration. + Consider the following example: + ++==== + [source,xml] + ---- + +@@ -185,8 +203,9 @@ Consider the following example: + access="ROLE_USER"/> + + ---- ++==== + +-This will protect all methods on beans declared in the application context whose classes are in the `com.mycompany` package and whose class names end in "Service". +-Only users with the `ROLE_USER` role will be able to invoke these methods. +-As with URL matching, the most specific matches must come first in the list of pointcuts, as the first matching expression will be used. ++This configuration protects all methods on beans declared in the application context whose classes are in the `com.mycompany` package and whose class names end in `Service`. ++Only users with the `ROLE_USER` role can invoke these methods. ++As with URL matching, the most specific matches must come first in the list of pointcuts, as the first matching expression is used. + Security annotations take precedence over pointcuts. +diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authorization/secure-objects.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authorization/secure-objects.adoc +index 7370a4202c..ebc9008e44 100644 +--- a/docs/manual/src/docs/asciidoc/_includes/servlet/authorization/secure-objects.adoc ++++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authorization/secure-objects.adoc +@@ -2,25 +2,27 @@ + [[secure-object-impls]] + == Secure Object Implementations + ++This section covers how Spring Security handles Secure Object implementations. ++ + [[aop-alliance]] + === AOP Alliance (MethodInvocation) Security Interceptor +-Prior to Spring Security 2.0, securing `MethodInvocation` s needed quite a lot of boiler plate configuration. ++Prior to Spring Security 2.0, securing `MethodInvocation` instances needed a lot of boiler plate configuration. + Now the recommended approach for method security is to use <>. +-This way the method security infrastructure beans are configured automatically for you so you don't really need to know about the implementation classes. +-We'll just provide a quick overview of the classes that are involved here. ++This way, the method security infrastructure beans are configured automatically for you, so you need not know about the implementation classes. ++We provide only a quick overview of the classes that are involved here. + +-Method security is enforced using a `MethodSecurityInterceptor`, which secures `MethodInvocation` s. ++Method security is enforced by using a `MethodSecurityInterceptor`, which secures `MethodInvocation` instances. + Depending on the configuration approach, an interceptor may be specific to a single bean or shared between multiple beans. + The interceptor uses a `MethodSecurityMetadataSource` instance to obtain the configuration attributes that apply to a particular method invocation. +-`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 `` or `` elements. +-Other implementations will be used to handle annotation-based configuration. ++`MapBasedMethodSecurityMetadataSource` is used to store configuration attributes keyed by method names (which can be wildcarded) and is used internally when the attributes are defined in the application context by using the `` or `` elements. ++Other implementations are used to handle annotation-based 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: ++You can configure a `MethodSecurityInterceptor` directly in your application context for use with one of Spring AOP's proxying mechanisms: + ++==== + [source,xml] + ---- +- + + +@@ -34,22 +36,22 @@ You can of course configure a `MethodSecurityInterceptor` directly in your appli + + + ---- ++==== + + [[aspectj]] + === 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. ++We discuss only the differences in this section. + + The AspectJ interceptor is named `AspectJSecurityInterceptor`. +-Unlike the AOP Alliance security interceptor, which relies on the Spring application context to weave in the security interceptor via proxying, the `AspectJSecurityInterceptor` is weaved in via the AspectJ compiler. ++Unlike the AOP Alliance security interceptor, which relies on the Spring application context to weave in the security interceptor through proxying, the `AspectJSecurityInterceptor` is woven in through the AspectJ compiler. + It would not be uncommon to use both types of security interceptors in the same application, with `AspectJSecurityInterceptor` being used for domain object instance security and the AOP Alliance `MethodSecurityInterceptor` being used for services layer security. + +-Let's first consider how the `AspectJSecurityInterceptor` is configured in the Spring application context: +- ++We first consider how the `AspectJSecurityInterceptor` is configured in the Spring application context: + ++==== + [source,xml] + ---- +- + + +@@ -63,19 +65,17 @@ Let's first consider how the `AspectJSecurityInterceptor` is configured in the S + + + ---- +- ++==== + + As you can see, aside from the class name, the `AspectJSecurityInterceptor` is exactly the same as the AOP Alliance security interceptor. +-Indeed the two interceptors can share the same `securityMetadataSource`, as the `SecurityMetadataSource` works with `java.lang.reflect.Method` s rather than an AOP library-specific class. +-Of course, your access decisions have access to the relevant AOP library-specific invocation (ie `MethodInvocation` or `JoinPoint`) and as such can consider a range of addition criteria when making access decisions (such as method arguments). +- +-Next you'll need to define an AspectJ `aspect`. +-For example: ++The two interceptors can share the same `securityMetadataSource`, as the `SecurityMetadataSource` works with `java.lang.reflect.Method` instances rather than an AOP library-specific class. ++Your access decisions have access to the relevant AOP library-specific invocation (`MethodInvocation` or `JoinPoint`) and can consider a range of additional criteria (such as method arguments) when making access decisions. + ++Next, you need to define an AspectJ `aspect`, as the following example shows: + ++==== + [source,java] + ---- +- + package org.springframework.security.samples.aspectj; + + import org.springframework.security.access.intercept.aspectj.AspectJSecurityInterceptor; +@@ -118,16 +118,16 @@ public aspect DomainObjectInstanceSecurityAspect implements InitializingBean { + } + } + ---- ++==== + +- +-In the above example, the security interceptor will be applied to every instance of `PersistableEntity`, which is an abstract class not shown (you can use any other class or `pointcut` expression you like). ++In the preceding example, the security interceptor is applied to every instance of `PersistableEntity`, which is an abstract class not shown (you can use any other class or `pointcut` expression you like). + For those curious, `AspectJCallback` is needed because the `proceed();` statement has special meaning only within an `around()` body. + The `AspectJSecurityInterceptor` calls this anonymous `AspectJCallback` class when it wants the target object to continue. + +-You will need to configure Spring to load the aspect and wire it with the `AspectJSecurityInterceptor`. +-A bean declaration which achieves this is shown below: +- ++You need to configure Spring to load the aspect and wire it with the `AspectJSecurityInterceptor`. ++The following example shows a bean declaration that achieves this: + ++==== + [source,xml] + ---- + +@@ -137,7 +137,6 @@ A bean declaration which achieves this is shown below: + + + ---- ++==== + +- +-That's it! +-Now you can create your beans from anywhere within your application, using whatever means you think fit (e.g. `new Person();`) and they will have the security interceptor applied. ++Now you can create your beans from anywhere within your application, using whatever means you think fit (e.g. `new Person();`), and they have the security interceptor applied. +diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/crypto/index.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/crypto/index.adoc +index 137b3e8b69..e5cd9f81e5 100644 +--- a/docs/manual/src/docs/asciidoc/_includes/servlet/crypto/index.adoc ++++ b/docs/manual/src/docs/asciidoc/_includes/servlet/crypto/index.adoc +@@ -3,21 +3,22 @@ + + + [[spring-security-crypto-introduction]] +-== Introduction + The Spring Security Crypto module provides support for symmetric encryption, key generation, and password encoding. + The code is distributed as part of the core module but has no dependencies on any other Spring Security (or Spring) code. + + + [[spring-security-crypto-encryption]] + == Encryptors +-The Encryptors class provides factory methods for constructing symmetric encryptors. +-Using this class, you can create ByteEncryptors to encrypt data in raw byte[] form. +-You can also construct TextEncryptors to encrypt text strings. ++The {security-api-url}org/springframework/security/crypto/encrypt/Encryptors.html[`Encryptors`] class provides factory methods for constructing symmetric encryptors. ++This class lets you create {security-api-url}org/springframework/security/crypto/encrypt/BytesEncryptor.html[`BytesEncryptor`] instances to encrypt data in raw `byte[]` form. ++You can also construct {security-api-url}org/springframework/security/crypto/encrypt/TextEncryptor.html[TextEncryptor] instances to encrypt text strings. + Encryptors are thread-safe. + ++NOTE: Both `BytesEncryptor` and `TextEncryptor` are interfaces. `BytesEncryptor` has multiple implementations. ++ + [[spring-security-crypto-encryption-bytes]] + === BytesEncryptor +-Use the `Encryptors.stronger` factory method to construct a BytesEncryptor: ++YOu can use the `Encryptors.stronger` factory method to construct a `BytesEncryptor`: + + .BytesEncryptor + ==== +@@ -34,16 +35,16 @@ Encryptors.stronger("password", "salt") + ---- + ==== + +-The "stronger" encryption method creates an encryptor using 256 bit AES encryption with ++The `stronger` encryption method creates an encryptor by using 256-bit AES encryption with + Galois Counter Mode (GCM). +-It derives the secret key using PKCS #5's PBKDF2 (Password-Based Key Derivation Function #2). ++It derives the secret key by using PKCS #5's PBKDF2 (Password-Based Key Derivation Function #2). + This method requires Java 6. +-The password used to generate the SecretKey should be kept in a secure place and not be shared. +-The salt is used to prevent dictionary attacks against the key in the event your encrypted data is compromised. +-A 16-byte random initialization vector is also applied so each encrypted message is unique. ++The password used to generate the `SecretKey` should be kept in a secure place and should not be shared. ++The salt is used to prevent dictionary attacks against the key in the event that your encrypted data is compromised. ++A 16-byte random initialization vector is also applied so that each encrypted message is unique. + + The provided salt should be in hex-encoded String form, be random, and be at least 8 bytes in length. +-Such a salt may be generated using a KeyGenerator: ++You can generate such a salt by using a `KeyGenerator`: + + .Generating a key + ==== +@@ -60,14 +61,14 @@ val salt = KeyGenerators.string().generateKey() // generates a random 8-byte sal + ---- + ==== + +-Users may also use the `standard` encryption method, which is 256-bit AES in Cipher Block Chaining (CBC) Mode. ++You can also use the `standard` encryption method, which is 256-bit AES in Cipher Block Chaining (CBC) Mode. + This mode is not https://en.wikipedia.org/wiki/Authenticated_encryption[authenticated] and does not provide any + guarantees about the authenticity of the data. +-For a more secure alternative, users should prefer `Encryptors.stronger`. ++For a more secure alternative, use `Encryptors.stronger`. + + [[spring-security-crypto-encryption-text]] + === TextEncryptor +-Use the Encryptors.text factory method to construct a standard TextEncryptor: ++You can use the `Encryptors.text` factory method to construct a standard TextEncryptor: + + .TextEncryptor + ==== +@@ -84,10 +85,10 @@ Encryptors.text("password", "salt") + ---- + ==== + +-A TextEncryptor uses a standard BytesEncryptor to encrypt text data. +-Encrypted results are returned as hex-encoded strings for easy storage on the filesystem or in the database. ++A `TextEncryptor` uses a standard `BytesEncryptor` to encrypt text data. ++Encrypted results are returned as hex-encoded strings for easy storage on the filesystem or in a database. + +-Use the Encryptors.queryableText factory method to construct a "queryable" TextEncryptor: ++You can use the `Encryptors.queryableText` factory method to construct a "`queryable`" `TextEncryptor`: + + .Queryable TextEncryptor + ==== +@@ -104,21 +105,21 @@ Encryptors.queryableText("password", "salt") + ---- + ==== + +-The difference between a queryable TextEncryptor and a standard TextEncryptor has to do with initialization vector (iv) handling. +-The iv used in a queryable TextEncryptor#encrypt operation is shared, or constant, and is not randomly generated. +-This means the same text encrypted multiple times will always produce the same encryption result. +-This is less secure, but necessary for encrypted data that needs to be queried against. +-An example of queryable encrypted text would be an OAuth apiKey. ++The difference between a queryable `TextEncryptor` and a standard `TextEncryptor` has to do with initialization vector (IV) handling. ++The IV used in a queryable `TextEncryptor.encrypt` operation is shared, or constant, and is not randomly generated. ++This means the same text encrypted multiple times always produces the same encryption result. ++This is less secure but necessary for encrypted data that needs to be queried against. ++An example of queryable encrypted text would be an OAuth `apiKey`. + + [[spring-security-crypto-keygenerators]] + == Key Generators +-The KeyGenerators class provides a number of convenience factory methods for constructing different types of key generators. +-Using this class, you can create a BytesKeyGenerator to generate byte[] keys. +-You can also construct a StringKeyGenerator to generate string keys. +-KeyGenerators are thread-safe. ++The {security-api-url}org/springframework/security/crypto/keygen/KeyGenerators.html[`KeyGenerators`] class provides a number of convenience factory methods for constructing different types of key generators. ++By using this class, you can create a {security-api-url}org/springframework/security/crypto/keygen/BytesKeyGenerator.html[`BytesKeyGenerator`] to generate `byte[]` keys. ++You can also construct a {security-api-url}org/springframework/security/crypto/keygen/StringKeyGenerator.html`[StringKeyGenerator]` to generate string keys. ++`KeyGenerators` is a thread-safe class. + + === BytesKeyGenerator +-Use the KeyGenerators.secureRandom factory methods to generate a BytesKeyGenerator backed by a SecureRandom instance: ++You can use the `KeyGenerators.secureRandom` factory methods to generate a `BytesKeyGenerator` backed by a `SecureRandom` instance: + + .BytesKeyGenerator + ==== +@@ -138,7 +139,7 @@ val key = generator.generateKey() + ==== + + The default key length is 8 bytes. +-There is also a KeyGenerators.secureRandom variant that provides control over the key length: ++A `KeyGenerators.secureRandom` variant provides control over the key length: + + .KeyGenerators.secureRandom + ==== +@@ -155,7 +156,7 @@ KeyGenerators.secureRandom(16) + ---- + ==== + +-Use the KeyGenerators.shared factory method to construct a BytesKeyGenerator that always returns the same key on every invocation: ++Use the `KeyGenerators.shared` factory method to construct a BytesKeyGenerator that always returns the same key on every invocation: + + .KeyGenerators.shared + ==== +@@ -173,7 +174,7 @@ KeyGenerators.shared(16) + ==== + + === StringKeyGenerator +-Use the KeyGenerators.string factory method to construct a 8-byte, SecureRandom KeyGenerator that hex-encodes each key as a String: ++You can use the `KeyGenerators.string` factory method to construct an 8-byte, `SecureRandom` `KeyGenerator` that hex-encodes each key as a `String`: + + .StringKeyGenerator + ==== +@@ -192,9 +193,10 @@ KeyGenerators.string() + + [[spring-security-crypto-passwordencoders]] + == Password Encoding +-The password package of the spring-security-crypto module provides support for encoding passwords. ++The password package of the `spring-security-crypto` module provides support for encoding passwords. + `PasswordEncoder` is the central service interface and has the following signature: + ++==== + [source,java] + ---- + public interface PasswordEncoder { +@@ -204,16 +206,18 @@ String encode(String rawPassword); + boolean matches(String rawPassword, String encodedPassword); + } + ---- ++==== + +-The matches method returns true if the rawPassword, once encoded, equals the encodedPassword. ++The `matches` method returns true if the `rawPassword`, once encoded, equals the `encodedPassword`. + This method is designed to support password-based authentication schemes. + +-The `BCryptPasswordEncoder` implementation uses the widely supported "bcrypt" algorithm to hash the passwords. +-Bcrypt uses a random 16 byte salt value and is a deliberately slow algorithm, in order to hinder password crackers. +-The amount of work it does can be tuned using the "strength" parameter which takes values from 4 to 31. ++The `BCryptPasswordEncoder` implementation uses the widely supported "`bcrypt`" algorithm to hash the passwords. ++Bcrypt uses a random 16-byte salt value and is a deliberately slow algorithm, to hinder password crackers. ++You can tune the amount of work it does by using the `strength` parameter, which takes a value from 4 to 31. + The higher the value, the more work has to be done to calculate the hash. +-The default value is 10. ++The default value is `10`. + You can change this value in your deployed system without affecting existing passwords, as the value is also stored in the encoded hash. ++The following example uses the `BCryptPasswordEncoder`: + + .BCryptPasswordEncoder + ==== +@@ -239,8 +243,8 @@ assertTrue(encoder.matches("myPassword", result)) + ==== + + The `Pbkdf2PasswordEncoder` implementation uses PBKDF2 algorithm to hash the passwords. +-In order to defeat password cracking PBKDF2 is a deliberately slow algorithm and should be tuned to take about .5 seconds to verify a password on your system. +- ++To defeat password cracking, PBKDF2 is a deliberately slow algorithm and should be tuned to take about .5 seconds to verify a password on your system. ++The following system uses the `Pbkdf2PasswordEncoder`: + + .Pbkdf2PasswordEncoder + ==== +diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/exploits/csrf.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/exploits/csrf.adoc +index ec05a78fc0..ca941c692f 100644 +--- a/docs/manual/src/docs/asciidoc/_includes/servlet/exploits/csrf.adoc ++++ b/docs/manual/src/docs/asciidoc/_includes/servlet/exploits/csrf.adoc +@@ -7,33 +7,32 @@ This section discusses Spring Security's <> +-* <> +-* <> ++* <> ++* <> ++* <> + + [[servlet-csrf-idempotent]] + === Use proper HTTP verbs +-The first step to protecting against CSRF attacks is to ensure your website uses proper HTTP verbs. ++The first step to protecting against CSRF attacks is to ensure that your website uses proper HTTP verbs. + This is covered in detail in <>. + + [[servlet-csrf-configure]] + === Configure CSRF Protection + The next step is to configure Spring Security's CSRF protection within your application. + Spring Security's CSRF protection is enabled by default, but you may need to customize the configuration. +-Below are a few common customizations. ++The next few sections cover a few common customizations. + + [[servlet-csrf-configure-custom-repository]] + ==== Custom CsrfTokenRepository + +-By default Spring Security stores the expected CSRF token in the `HttpSession` using `HttpSessionCsrfTokenRepository`. +-There can be cases where users will want to configure a custom `CsrfTokenRepository`. +-For example, it might be desirable to persist the `CsrfToken` in a cookie to <>. ++By default, Spring Security stores the expected CSRF token in the `HttpSession` by using `HttpSessionCsrfTokenRepository`. ++There can be cases where users want to configure a custom `CsrfTokenRepository`. ++For example, it might be desirable to persist the `CsrfToken` in a cookie to <>. + +-By default the `CookieCsrfTokenRepository` will write to a cookie named `XSRF-TOKEN` and read it from a header named `X-XSRF-TOKEN` or the HTTP parameter `_csrf`. +-These defaults come from https://docs.angularjs.org/api/ng/service/$http#cross-site-request-forgery-xsrf-protection[AngularJS] +- +-You can configure `CookieCsrfTokenRepository` in XML using the following: ++By default, the `CookieCsrfTokenRepository` writes to a cookie named `XSRF-TOKEN` and reads it from a header named `X-XSRF-TOKEN` or the HTTP parameter `_csrf`. ++These defaults come from https://docs.angularjs.org/api/ng/service/$http#cross-site-request-forgery-xsrf-protection[AngularJS]. + ++You can configure `CookieCsrfTokenRepository` in XML byusing the following: + + .Store CSRF Token in a Cookie with XML Configuration + ==== +@@ -49,15 +48,11 @@ You can configure `CookieCsrfTokenRepository` in XML using the following: + ---- + ==== + +-[NOTE] +-==== +-The sample explicitly sets `cookieHttpOnly=false`. +-This is necessary to allow JavaScript (i.e. AngularJS) to read it. +-If you do not need the ability to read the cookie with JavaScript directly, it is recommended to omit `cookieHttpOnly=false` to improve security. +-==== ++NOTE: The sample explicitly sets `cookieHttpOnly=false`. ++This is necessary to allow JavaScript (such as AngularJS) to read it. ++If you do not need the ability to read the cookie with JavaScript directly, we recommend omitting `cookieHttpOnly=false` to improve security. + +- +-You can configure `CookieCsrfTokenRepository` in Java Configuration using: ++You can configure `CookieCsrfTokenRepository` in Java or Kotlin configuration by using: + + .Store CSRF Token in a Cookie + ==== +@@ -95,20 +90,16 @@ class SecurityConfig : WebSecurityConfigurerAdapter() { + ---- + ==== + +-[NOTE] +-==== +-The sample explicitly sets `cookieHttpOnly=false`. +-This is necessary to allow JavaScript (i.e. AngularJS) to read it. +-If you do not need the ability to read the cookie with JavaScript directly, it is recommended to omit `cookieHttpOnly=false` (by using `new CookieCsrfTokenRepository()` instead) to improve security. +-==== ++NOTE: The sample explicitly sets `cookieHttpOnly=false`. ++This is necessary to let JavaScript (such as AngularJS) read it. ++If you do not need the ability to read the cookie with JavaScript directly, we recommend omitting `cookieHttpOnly=false` (by using `new CookieCsrfTokenRepository()` instead) to improve security. + + [[servlet-csrf-configure-disable]] + ==== Disable CSRF Protection +-CSRF protection is enabled by default. +-However, it is simple to disable CSRF protection if it <>. +- +-The XML configuration below will disable CSRF protection. ++By default, CSRF protection is enabled. ++However, you can disable CSRF protection if it <>. + ++The following XML configuration disables CSRF protection: + + .Disable CSRF XML Configuration + ==== +@@ -121,7 +112,7 @@ The XML configuration below will disable CSRF protection. + ---- + ==== + +-The Java configuration below will disable CSRF protection. ++The following Java or Kotlin configuration disables CSRF protection: + + .Disable CSRF + ==== +@@ -162,16 +153,16 @@ class SecurityConfig : WebSecurityConfigurerAdapter() { + [[servlet-csrf-include]] + === Include the CSRF Token + +-In order for the <> to protect against CSRF attacks, we must include the actual CSRF token in the HTTP request. +-This must be included in a part of the request (i.e. form parameter, HTTP header, etc) that is not automatically included in the HTTP request by the browser. ++For the <> to protect against CSRF attacks, we must include the actual CSRF token in the HTTP request. ++This must be included in a part of the request (a form parameter, an HTTP header, or other part) that is not automatically included in the HTTP request by the browser. + +-Spring Security's https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/web/csrf/CsrfFilter.html[CsrfFilter] exposes a https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/web/csrf/CsrfToken.html[CsrfToken] as an `HttpServletRequest` attribute named `_csrf`. ++Spring Security's https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/web/csrf/CsrfFilter.html[`CsrfFilter`] exposes a https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/web/csrf/CsrfToken.html[`CsrfToken`] as an `HttpServletRequest` attribute named `_csrf`. + This means that any view technology can access the `CsrfToken` to expose the expected token as either a <> or <>. +-Fortunately, there are integrations listed below that make including the token in <> and <> requests even easier. ++Fortunately, there are integrations listed later in this chapter that make including the token in <> and <> requests even easier. + + [[servlet-csrf-include-form]] + ==== Form URL Encoded +-In order to post an HTML form the CSRF token must be included in the form as a hidden input. ++To post an HTML form, the CSRF token must be included in the form as a hidden input. + For example, the rendered HTML might look like: + + .CSRF Token HTML +@@ -184,26 +175,26 @@ For example, the rendered HTML might look like: + ---- + ==== + +-Next we will discuss various ways of including the CSRF token in a form as a hidden input. ++Next, we discuss various ways of including the CSRF token in a form as a hidden input. + + [[servlet-csrf-include-form-auto]] + ===== Automatic CSRF Token Inclusion + +-Spring Security's CSRF support provides integration with Spring's https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/servlet/support/RequestDataValueProcessor.html[RequestDataValueProcessor] via its https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/web/servlet/support/csrf/CsrfRequestDataValueProcessor.html[CsrfRequestDataValueProcessor]. +-This means that if you leverage https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#mvc-view-jsp-formtaglib[Spring’s form tag library], https://www.thymeleaf.org/doc/tutorials/2.1/thymeleafspring.html#integration-with-requestdatavalueprocessor[Thymeleaf], or any other view technology that integrates with `RequestDataValueProcessor`, then forms that have an unsafe HTTP method (i.e. post) will automatically include the actual CSRF token. ++Spring Security's CSRF support provides integration with Spring's https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/servlet/support/RequestDataValueProcessor.html[`RequestDataValueProcessor`] through its https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/web/servlet/support/csrf/CsrfRequestDataValueProcessor.html[`CsrfRequestDataValueProcessor`]. ++This means that, if you use https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#mvc-view-jsp-formtaglib[Spring’s form tag library], https://www.thymeleaf.org/doc/tutorials/2.1/thymeleafspring.html#integration-with-requestdatavalueprocessor[Thymeleaf], or any other view technology that integrates with `RequestDataValueProcessor`, then forms that have an unsafe HTTP method (such as post) automatically include the actual CSRF token. + + [[servlet-csrf-include-form-tag]] + ===== csrfInput Tag + +-If you are using JSPs, then you can use https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#mvc-view-jsp-formtaglib[Spring’s form tag library]. +-However, if that is not an option, you can also easily include the token with the <> tag. ++If you use JSPs, you can use https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#mvc-view-jsp-formtaglib[Spring’s form tag library]. ++However, if that is not an option, you can also include the token with the <> tag. + + [[servlet-csrf-include-form-attr]] + ===== CsrfToken Request Attribute + + If the <> for including the actual CSRF token in the request do not work, you can take advantage of the fact that the `CsrfToken` <> as an `HttpServletRequest` attribute named `_csrf`. + +-An example of doing this with a JSP is shown below: ++The following example does this with a JSP: + + .CSRF Token in Form with Request Attribute + ==== +@@ -223,19 +214,19 @@ An example of doing this with a JSP is shown below: + + [[servlet-csrf-include-ajax]] + ==== Ajax and JSON Requests +-If you are using JSON, then it is not possible to submit the CSRF token within an HTTP parameter. +-Instead you can submit the token within a HTTP header. ++If you use JSON, you cannot submit the CSRF token within an HTTP parameter. ++Instead, you can submit the token within a HTTP header. + +-In the following sections we will discuss various ways of including the CSRF token as an HTTP request header in JavaScript based applications. ++The following sections discuss various ways of including the CSRF token as an HTTP request header in JavaScript based applications. + + [[servlet-csrf-include-ajax-auto]] + ===== Automatic Inclusion + +-Spring Security can easily be <> to store the expected CSRF token in a cookie. +-By storing the expected CSRF in a cookie, JavaScript frameworks like https://docs.angularjs.org/api/ng/service/$http#cross-site-request-forgery-xsrf-protection[AngularJS] will automatically include the actual CSRF token in the HTTP request headers. ++You can <> Spring Security to store the expected CSRF token in a cookie. ++By storing the expected CSRF in a cookie, JavaScript frameworks, such as https://docs.angularjs.org/api/ng/service/$http#cross-site-request-forgery-xsrf-protection[AngularJS], automatically include the actual CSRF token in the HTTP request headers. + + [[servlet-csrf-include-ajax-meta]] +-===== Meta tags ++===== Meta Tags + + An alternative pattern to <> is to include the CSRF token within your `meta` tags. + The HTML might look something like this: +@@ -254,8 +245,8 @@ The HTML might look something like this: + ---- + ==== + +-Once the meta tags contained the CSRF token, the JavaScript code would read the meta tags and include the CSRF token as a header. +-If you were using jQuery, this could be done with the following: ++Once the meta tags contain the CSRF token, the JavaScript code can read the meta tags and include the CSRF token as a header. ++If you use jQuery, you can do this with the following code: + + .AJAX send CSRF Token + ==== +@@ -274,13 +265,13 @@ $(function () { + [[servlet-csrf-include-ajax-meta-tag]] + ====== csrfMeta tag + +-If you are using JSPs a simple way to write the CSRF token to the `meta` tags is by leveraging the <> tag. ++If you use JSPs, one way to write the CSRF token to the `meta` tags is by using the <> tag. + + [[servlet-csrf-include-ajax-meta-attr]] + ====== CsrfToken Request Attribute + + If the <> for including the actual CSRF token in the request do not work, you can take advantage of the fact that the `CsrfToken` <> as an `HttpServletRequest` attribute named `_csrf`. +-An example of doing this with a JSP is shown below: ++The following example does this with a JSP: + + .CSRF meta tag JSP + ==== +@@ -300,31 +291,31 @@ An example of doing this with a JSP is shown below: + [[servlet-csrf-considerations]] + == CSRF Considerations + There are a few special considerations to consider when implementing protection against CSRF attacks. +-This section discusses those considerations as it pertains to servlet environments. +-Refer to <> for a more general discussion. ++This section discusses those considerations as they pertain to servlet environments. ++See <> for a more general discussion. + + + [[servlet-considerations-csrf-login]] + === Logging In + +-It is important to <> requests to protect against forging log in attempts. ++It is important to <> requests, to protect against forging login attempts. + Spring Security's servlet support does this out of the box. + + [[servlet-considerations-csrf-logout]] + === Logging Out + +-It is important to <> requests to protect against forging log out attempts. +-If CSRF protection is enabled (default), Spring Security's `LogoutFilter` to only process HTTP POST. +-This ensures that log out requires a CSRF token and that a malicious user cannot forcibly log out your users. ++It is important to <> requests to protect against forging logout attempts. ++If CSRF protection is enabled (the default), Spring Security's `LogoutFilter` to only process HTTP POST. ++This ensures that logging out requires a CSRF token and that a malicious user cannot forcibly log out your users. + + The easiest approach is to use a form to log out. +-If you really want a link, you can use JavaScript to have the link perform a POST (i.e. maybe on a hidden form). +-For browsers with JavaScript that is disabled, you can optionally have the link take the user to a log out confirmation page that will perform the POST. ++If you really want a link, you can use JavaScript to have the link perform a POST (maybe on a hidden form). ++For browsers with JavaScript that is disabled, you can optionally have the link take the user to a log out confirmation page that performs the POST. + +-If you really want to use HTTP GET with logout you can do so, but remember this is generally not recommended. +-For example, the following Java Configuration will perform logout with the URL `/logout` is requested with any HTTP method: ++If you really want to use HTTP GET with logout, you can do so. However, remember that this is generally not recommended. ++For example, the following Java Configuration logs out when the `/logout` URL is requested with any HTTP method: + +-.Log out with HTTP GET ++.Log out with any HTTP method + ==== + .Java + [source,java,role="primary"] +@@ -364,18 +355,18 @@ class SecurityConfig : WebSecurityConfigurerAdapter() { + [[servlet-considerations-csrf-timeouts]] + === CSRF and Session Timeouts + +-By default Spring Security stores the CSRF token in the `HttpSession`. +-This can lead to a situation where the session expires which means there is not an expected CSRF token to validate against. ++By default, Spring Security stores the CSRF token in the `HttpSession`. ++This can lead to a situation where the session expires, leaving no CSRF token to validate against. + +-We've already discussed <> to session timeouts. ++We have already discussed <> to session timeouts. + This section discusses the specifics of CSRF timeouts as it pertains to the servlet support. + +-It is simple to change storage of the expected CSRF token to be in a cookie. +-For details, refer to the <> section. ++You can change the storage of the CSRF token to be in a cookie. ++For details, see the <> section. + + If a token does expire, you might want to customize how it is handled by specifying a custom `AccessDeniedHandler`. + The custom `AccessDeniedHandler` can process the `InvalidCsrfTokenException` any way you like. +-For an example of how to customize the `AccessDeniedHandler` refer to the provided links for both <> and https://github.com/spring-projects/spring-security/blob/3.2.0.RC1/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpAccessDeniedHandlerTests.java#L64[Java configuration]. ++For an example of how to customize the `AccessDeniedHandler`, see the provided links for both <> and https://github.com/spring-projects/spring-security/blob/3.2.0.RC1/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpAccessDeniedHandlerTests.java#L64[Java configuration]. + // FIXME: We should add a custom AccessDeniedHandler section in the reference and update the links above + + +@@ -384,25 +375,22 @@ For an example of how to customize the `AccessDeniedHandler` refer to the provid + We have <> how protecting multipart requests (file uploads) from CSRF attacks causes a https://en.wikipedia.org/wiki/Chicken_or_the_egg[chicken and the egg] problem. + This section discusses how to implement placing the CSRF token in the <> and <> within a servlet application. + +-[NOTE] +-==== +-More information about using multipart forms with Spring can be found within the https://docs.spring.io/spring/docs/5.2.x/spring-framework-reference/web.html#mvc-multipart[1.1.11. Multipart Resolver] section of the Spring reference and the https://docs.spring.io/spring/docs/5.2.x/javadoc-api/org/springframework/web/multipart/support/MultipartFilter.html[MultipartFilter javadoc]. +-==== ++NOTE: You can find more information about using multipart forms with Spring in the https://docs.spring.io/spring/docs/5.2.x/spring-framework-reference/web.html#mvc-multipart[1.1.11. Multipart Resolver] section of the Spring reference and the https://docs.spring.io/spring/docs/5.2.x/javadoc-api/org/springframework/web/multipart/support/MultipartFilter.html[`MultipartFilter` javadoc]. + + [[servlet-csrf-considerations-multipart-body]] + ==== Place CSRF Token in the Body + + We have <> the tradeoffs of placing the CSRF token in the body. +-In this section we will discuss how to configure Spring Security to read the CSRF from the body. ++In this section, we discuss how to configure Spring Security to read the CSRF from the body. + +-In order to read the CSRF token from the body, the `MultipartFilter` is specified before the Spring Security filter. +-Specifying the `MultipartFilter` before the Spring Security filter means that there is no authorization for invoking the `MultipartFilter` which means anyone can place temporary files on your server. +-However, only authorized users will be able to submit a File that is processed by your application. ++To read the CSRF token from the body, the `MultipartFilter` is specified before the Spring Security filter. ++Specifying the `MultipartFilter` before the Spring Security filter means that there is no authorization for invoking the `MultipartFilter`, which means anyone can place temporary files on your server. ++However, only authorized users can submit a file that is processed by your application. + In general, this is the recommended approach because the temporary file upload should have a negligible impact on most servers. + + // FIXME: Document Spring Boot + +-To ensure `MultipartFilter` is specified before the Spring Security filter with java configuration, users can override beforeSpringSecurityFilterChain as shown below: ++To ensure `MultipartFilter` is specified before the Spring Security filter with Java configuration, you can override `beforeSpringSecurityFilterChain`: + + .Initializer MultipartFilter + ==== +@@ -429,7 +417,7 @@ class SecurityApplicationInitializer : AbstractSecurityWebApplicationInitializer + ---- + ==== + +-To ensure `MultipartFilter` is specified before the Spring Security filter with XML configuration, users can ensure the element of the `MultipartFilter` is placed before the springSecurityFilterChain within the web.xml as shown below: ++To ensure that `MultipartFilter` is specified before the Spring Security filter with XML configuration, you can ensure the `` element of the `MultipartFilter` is placed before the `springSecurityFilterChain` within the `web.xml` file: + + .web.xml - MultipartFilter + ==== +@@ -455,11 +443,11 @@ To ensure `MultipartFilter` is specified before the Spring Security filter with + ==== + + [[servlet-csrf-considerations-multipart-url]] +-==== Include CSRF Token in URL ++==== Include a CSRF Token in a URL + +-If allowing unauthorized users to upload temporary files is not acceptable, an alternative is to place the `MultipartFilter` after the Spring Security filter and include the CSRF as a query parameter in the action attribute of the form. ++If letting unauthorized users upload temporary files is not acceptable, an alternative is to place the `MultipartFilter` after the Spring Security filter and include the CSRF as a query parameter in the action attribute of the form. + Since the `CsrfToken` is exposed as an `HttpServletRequest` <>, we can use that to create an `action` with the CSRF token in it. +-An example with a jsp is shown below ++The following example does this with a JSP: + + .CSRF Token in Action + ==== +@@ -475,5 +463,5 @@ An example with a jsp is shown below + === HiddenHttpMethodFilter + We have <> the trade-offs of placing the CSRF token in the body. + +-In Spring's Servlet support, overriding the HTTP method is done using https://docs.spring.io/spring-framework/docs/5.2.x/javadoc-api/org/springframework/web/filter/reactive/HiddenHttpMethodFilter.html[HiddenHttpMethodFilter]. +-More information can be found in https://docs.spring.io/spring/docs/5.2.x/spring-framework-reference/web.html#mvc-rest-method-conversion[HTTP Method Conversion] section of the reference documentation. ++In Spring's Servlet support, overriding the HTTP method is done by using https://docs.spring.io/spring-framework/docs/5.2.x/javadoc-api/org/springframework/web/filter/reactive/HiddenHttpMethodFilter.html[`HiddenHttpMethodFilter`]. ++You can find more information in the https://docs.spring.io/spring/docs/5.2.x/spring-framework-reference/web.html#mvc-rest-method-conversion[HTTP Method Conversion] section of the reference documentation. +diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/exploits/firewall.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/exploits/firewall.adoc +index 71171992b3..618368eef4 100644 +--- a/docs/manual/src/docs/asciidoc/_includes/servlet/exploits/firewall.adoc ++++ b/docs/manual/src/docs/asciidoc/_includes/servlet/exploits/firewall.adoc +@@ -1,49 +1,49 @@ + [[servlet-httpfirewall]] + = HttpFirewall +-Spring Security has several areas where patterns you have defined are tested against incoming requests in order to decide how the request should be handled. +-This occurs when the `FilterChainProxy` decides which filter chain a request should be passed through and also when the `FilterSecurityInterceptor` decides which security constraints apply to a request. +-It's important to understand what the mechanism is and what URL value is used when testing against the patterns that you define. ++Spring Security has several areas where patterns you have defined are tested against incoming requests to decide how the request should be handled. ++This occurs when the `FilterChainProxy` decides which filter chain a request should be passed through and when the `FilterSecurityInterceptor` decides which security constraints apply to a request. ++It is important to understand what the mechanism is and what URL value is used when testing against the patterns that you define. + +-The Servlet Specification defines several properties for the `HttpServletRequest` which are accessible via getter methods, and which we might want to match against. +-These are the `contextPath`, `servletPath`, `pathInfo` and `queryString`. ++The servlet specification defines several properties for the `HttpServletRequest` that are accessible via getter methods and that we might want to match against. ++These are the `contextPath`, `servletPath`, `pathInfo`, and `queryString`. + Spring Security is only interested in securing paths within the application, so the `contextPath` is ignored. +-Unfortunately, the servlet spec does not define exactly what the values of `servletPath` and `pathInfo` will contain for a particular request URI. ++Unfortunately, the servlet spec does not define exactly what the values of `servletPath` and `pathInfo` contain for a particular request URI. + For example, each path segment of a URL may contain parameters, as defined in https://www.ietf.org/rfc/rfc2396.txt[RFC 2396] +-footnote:[You have probably seen this when a browser doesn't support cookies and the `jsessionid` parameter is appended to the URL after a semi-colon. +-However the RFC allows the presence of these parameters in any path segment of the URL]. +-The Specification does not clearly state whether these should be included in the `servletPath` and `pathInfo` values and the behaviour varies between different servlet containers. +-There is a danger that when an application is deployed in a container which does not strip path parameters from these values, an attacker could add them to the requested URL in order to cause a pattern match to succeed or fail unexpectedly. +-footnote:[The original values will be returned once the request leaves the `FilterChainProxy`, so will still be available to the application.]. ++(You have probably seen this when a browser does not support cookies and the `jsessionid` parameter is appended to the URL after a semicolon. ++However, the RFC allows the presence of these parameters in any path segment of the URL.) ++The Specification does not clearly state whether these should be included in the `servletPath` and `pathInfo` values and the behavior varies between different servlet containers. ++There is a danger that, when an application is deployed in a container that does not strip path parameters from these values, an attacker could add them to the requested URL to cause a pattern match to succeed or fail unexpectedly. ++(The original values will be returned once the request leaves the `FilterChainProxy`, so will still be available to the application.) + Other variations in the incoming URL are also possible. +-For example, it could contain path-traversal sequences (like `/../`) or multiple forward slashes (`//`) which could also cause pattern-matches to fail. +-Some containers normalize these out before performing the servlet mapping, but others don't. ++For example, it could contain path-traversal sequences (such as `/../`) or multiple forward slashes (`//`) that could also cause pattern-matches to fail. ++Some containers normalize these out before performing the servlet mapping, but others do not. + To protect against issues like these, `FilterChainProxy` uses an `HttpFirewall` strategy to check and wrap the request. +-Un-normalized requests are automatically rejected by default, and path parameters and duplicate slashes are removed for matching purposes. +-footnote:[So, for example, an original request path `/secure;hack=1/somefile.html;hack=2` will be returned as `/secure/somefile.html`.]. +-It is therefore essential that a `FilterChainProxy` is used to manage the security filter chain. +-Note that the `servletPath` and `pathInfo` values are decoded by the container, so your application should not have any valid paths which contain semi-colons, as these parts will be removed for matching purposes. ++By default, un-normalized requests are automatically rejected, and path parameters and duplicate slashes are removed for matching purposes. ++(So, for example, an original request path of `/secure;hack=1/somefile.html;hack=2` is returned as `/secure/somefile.html`.) ++It is, therefore, essential that a `FilterChainProxy` is used to manage the security filter chain. ++Note that the `servletPath` and `pathInfo` values are decoded by the container, so your application should not have any valid paths that contain semi-colons, as these parts are removed for matching purposes. + +-As mentioned above, the default strategy is to use Ant-style paths for matching and this is likely to be the best choice for most users. +-The strategy is implemented in the class `AntPathRequestMatcher` which uses Spring's `AntPathMatcher` to perform a case-insensitive match of the pattern against the concatenated `servletPath` and `pathInfo`, ignoring the `queryString`. ++As mentioned earlier, the default strategy is to use Ant-style paths for matching, and this is likely to be the best choice for most users. ++The strategy is implemented in the class `AntPathRequestMatcher`, which uses Spring's `AntPathMatcher` to perform a case-insensitive match of the pattern against the concatenated `servletPath` and `pathInfo`, ignoring the `queryString`. + +-If for some reason, you need a more powerful matching strategy, you can use regular expressions. ++If you need a more powerful matching strategy, you can use regular expressions. + The strategy implementation is then `RegexRequestMatcher`. +-See the Javadoc for this class for more information. ++See the {security-api-url}/org/springframework/security/web/util/matcher/RegexRequestMatcher.html[Javadoc for this class] for more information. + +-In practice we recommend that you use method security at your service layer, to control access to your application, and do not rely entirely on the use of security constraints defined at the web-application level. +-URLs change and it is difficult to take account of all the possible URLs that an application might support and how requests might be manipulated. +-You should try and restrict yourself to using a few simple ant paths which are simple to understand. +-Always try to use a "deny-by-default" approach where you have a catch-all wildcard ( /** or **) defined last and denying access. ++In practice, we recommend that you use method security at your service layer, to control access to your application, rather than rely entirely on the use of security constraints defined at the web-application level. ++URLs change, and it is difficult to take into account all the possible URLs that an application might support and how requests might be manipulated. ++You should restrict yourself to using a few simple Ant paths that are simple to understand. ++Always try to use a "`deny-by-default`" approach, where you have a catch-all wildcard (`/**` or `**`) defined last to deny access. + + Security defined at the service layer is much more robust and harder to bypass, so you should always take advantage of Spring Security's method security options. + + The `HttpFirewall` also prevents https://www.owasp.org/index.php/HTTP_Response_Splitting[HTTP Response Splitting] by rejecting new line characters in the HTTP Response headers. + +-By default the `StrictHttpFirewall` is used. ++By default, the `StrictHttpFirewall` implementation is used. + This implementation rejects requests that appear to be malicious. +-If it is too strict for your needs, then you can customize what types of requests are rejected. ++If it is too strict for your needs, you can customize what types of requests are rejected. + However, it is important that you do so knowing that this can open your application up to attacks. +-For example, if you wish to leverage Spring MVC's Matrix Variables, the following configuration could be used: ++For example, if you wish to use Spring MVC's matrix variables, you could use the following configuration: + + .Allow Matrix Variables + ==== +@@ -80,11 +80,10 @@ fun httpFirewall(): StrictHttpFirewall { + ---- + ==== + +-The `StrictHttpFirewall` provides an allowed list of valid HTTP methods that are allowed to protect against https://www.owasp.org/index.php/Cross_Site_Tracing[Cross Site Tracing (XST)] and https://www.owasp.org/index.php/Test_HTTP_Methods_(OTG-CONFIG-006)[HTTP Verb Tampering]. +-The default valid methods are "DELETE", "GET", "HEAD", "OPTIONS", "PATCH", "POST", and "PUT". ++To protect against https://www.owasp.org/index.php/Cross_Site_Tracing[Cross Site Tracing (XST)] and https://www.owasp.org/index.php/Test_HTTP_Methods_(OTG-CONFIG-006)[HTTP Verb Tampering], the `StrictHttpFirewall` provides an allowed list of valid HTTP methods that are allowed. ++The default valid methods are `DELETE`, `GET`, `HEAD`, `OPTIONS`, `PATCH`, `POST`, and `PUT`. + If your application needs to modify the valid methods, you can configure a custom `StrictHttpFirewall` bean. +-For example, the following will only allow HTTP "GET" and "POST" methods: +- ++The following example allows only HTTP `GET` and `POST` methods: + + .Allow Only GET & POST + ==== +@@ -121,31 +120,28 @@ fun httpFirewall(): StrictHttpFirewall { + ---- + ==== + +-[TIP] +-==== +-If you are using `new MockHttpServletRequest()` it currently creates an HTTP method as an empty String "". +-This is an invalid HTTP method and will be rejected by Spring Security. ++TIP: If you use `new MockHttpServletRequest()`, it currently creates an HTTP method as an empty String (`""`). ++This is an invalid HTTP method and is rejected by Spring Security. + You can resolve this by replacing it with `new MockHttpServletRequest("GET", "")`. +-See https://jira.spring.io/browse/SPR-16851[SPR_16851] for an issue requesting to improve this. +-==== ++See https://jira.spring.io/browse/SPR-16851[SPR_16851] for an issue that requests improving this. + + If you must allow any HTTP method (not recommended), you can use `StrictHttpFirewall.setUnsafeAllowAnyHttpMethod(true)`. +-This will disable validation of the HTTP method entirely. ++Doing so entirely disables validation of the HTTP method. + + [[servlet-httpfirewall-headers-parameters]] + + `StrictHttpFirewall` also checks header names and values and parameter names. + It requires that each character have a defined code point and not be a control character. + +-This requirement can be relaxed or adjusted as necessary using the following methods: ++This requirement can be relaxed or adjusted as necessary by using the following methods: + + * `StrictHttpFirewall#setAllowedHeaderNames(Predicate)` + * `StrictHttpFirewall#setAllowedHeaderValues(Predicate)` + * `StrictHttpFirewall#setAllowedParameterNames(Predicate)` + +-NOTE: Also, parameter values can be controlled with `setAllowedParameterValues(Predicate)`. ++NOTE: Parameter values can be also controlled with `setAllowedParameterValues(Predicate)`. + +-For example, to switch off this check, you can wire your `StrictHttpFirewall` with `Predicate` s that always return `true`, like so: ++For example, to switch off this check, you can wire your `StrictHttpFirewall` with `Predicate` instances that always return `true`: + + .Allow Any Header Name, Header Value, and Parameter Name + ==== +@@ -176,12 +172,12 @@ fun httpFirewall(): StrictHttpFirewall { + ---- + ==== + +-Or, there might be a specific value that you need to allow. ++Alternatively, there might be a specific value that you need to allow. + +-For example, iPhone Xʀ uses a `User-Agent` that includes a character not in the ISO-8859-1 charset. +-Due to this fact, some application servers will parse this value into two separate characters, the latter being an undefined character. ++For example, iPhone Xʀ uses a `User-Agent` that includes a character that is not in the ISO-8859-1 charset. ++Due to this fact, some application servers parse this value into two separate characters, the latter being an undefined character. + +-You can address this with the `setAllowedHeaderValues` method, as you can see below: ++You can address this with the `setAllowedHeaderValues` method: + + .Allow Certain User Agents + ==== +@@ -212,7 +208,7 @@ fun httpFirewall(): StrictHttpFirewall { + ---- + ==== + +-In the case of header values, you may instead consider parsing them as UTF-8 at verification time like so: ++In the case of header values, you may instead consider parsing them as UTF-8 at verification time: + + .Parse Headers As UTF-8 + ==== +diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/exploits/headers.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/exploits/headers.adoc +index e45c5c96c9..15978085b4 100644 +--- a/docs/manual/src/docs/asciidoc/_includes/servlet/exploits/headers.adoc ++++ b/docs/manual/src/docs/asciidoc/_includes/servlet/exploits/headers.adoc +@@ -1,19 +1,19 @@ + [[servlet-headers]] + = Security HTTP Response Headers + +-<> can be used to increase the security of web applications. +-This section is dedicated to servlet based support for Security HTTP Response Headers. ++You can use <> to increase the security of web applications. ++This section is dedicated to servlet-based support for Security HTTP Response Headers. + + [[servlet-headers-default]] + == Default Security Headers + + Spring Security provides a <> to provide secure defaults. +-While each of these headers are considered best practice, it should be noted that not all clients utilize the headers, so additional testing is encouraged. ++While each of these headers are considered best practice, it should be noted that not all clients use the headers, so additional testing is encouraged. + + You can customize specific headers. +-For example, assume that you want the defaults except you wish to specify `SAMEORIGIN` for <>. ++For example, assume that you want the defaults but you wish to specify `SAMEORIGIN` for <>. + +-You can easily do this with the following Configuration: ++You can do so with the following configuration: + + .Customize Default Security Headers + ==== +@@ -69,9 +69,9 @@ class SecurityConfig : WebSecurityConfigurerAdapter() { + ==== + + If you do not want the defaults to be added and want explicit control over what should be used, you can disable the defaults. +-An example is provided below: ++The next code listing shows how to do so. + +-If you are using Spring Security's Configuration the following will only add <>. ++If you use Spring Security's configuration, the following adds only <>: + + .Customize Cache Control Headers + ==== +@@ -127,7 +127,7 @@ class SecurityConfig : WebSecurityConfigurerAdapter() { + ---- + ==== + +-If necessary, you can disable all of the HTTP Security response headers with the following Configuration: ++If necessary, you can disable all of the HTTP Security response headers with the following configuration: + + .Disable All HTTP Security Headers + ==== +@@ -179,11 +179,11 @@ class SecurityConfig : WebSecurityConfigurerAdapter() { + + Spring Security includes <> headers by default. + +-However, if you actually want to cache specific responses, your application can selectively invoke https://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletResponse.html#setHeader(java.lang.String,java.lang.String)[HttpServletResponse.setHeader(String,String)] to override the header set by Spring Security. +-This is useful to ensure things like CSS, JavaScript, and images are properly cached. ++However, if you actually want to cache specific responses, your application can selectively invoke https://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletResponse.html#setHeader(java.lang.String,java.lang.String)[`HttpServletResponse.setHeader(String,String)`] to override the header set by Spring Security. ++You can use this to ensure that content (such as CSS, JavaScript, and images) is properly cached. + +-When using Spring Web MVC, this is typically done within your configuration. +-Details on how to do this can be found in the https://docs.spring.io/spring/docs/5.0.0.RELEASE/spring-framework-reference/web.html#mvc-config-static-resources[Static Resources] portion of the Spring Reference documentation ++When you use Spring Web MVC, this is typically done within your configuration. ++You can find details on how to do this in the https://docs.spring.io/spring/docs/5.0.0.RELEASE/spring-framework-reference/web.html#mvc-config-static-resources[Static Resources] portion of the Spring Reference documentation + + If necessary, you can also disable Spring Security's cache control HTTP response headers. + +@@ -243,7 +243,7 @@ class SecurityConfig : WebSecurityConfigurerAdapter() { + == Content Type Options + + Spring Security includes <> headers by default. +-However, you can disable it with: ++However, you can disable it: + + .Content Type Options Disabled + ==== +@@ -300,9 +300,9 @@ class SecurityConfig : WebSecurityConfigurerAdapter() { + [[servlet-headers-hsts]] + == HTTP Strict Transport Security (HSTS) + +-Spring Security provides the <> header by default. +-However, you can customize the results explicitly. +-For example, the following is an example of explicitly providing HSTS: ++By default, Spring Security provides the <> header. ++However, you can explicitly customize the results. ++The following example explicitly provides HSTS: + + .Strict Transport Security + ==== +@@ -366,9 +366,9 @@ class SecurityConfig : WebSecurityConfigurerAdapter() { + + [[servlet-headers-hpkp]] + == HTTP Public Key Pinning (HPKP) +-For passivity reasons, Spring Security provides servlet support for <> but it is <>. ++Spring Security provides servlet support for <>, but it is <>. + +-You can enable HPKP headers with the following Configuration: ++You can enable HPKP headers with the following configuration: + + .HTTP Public Key Pinning + ==== +@@ -437,9 +437,9 @@ class SecurityConfig : WebSecurityConfigurerAdapter() { + [[servlet-headers-frame-options]] + == X-Frame-Options + +-By default, Spring Security disables rendering within an iframe using <>. ++By default, Spring Security disables rendering within an iframe by using <>. + +-You can customize frame options to use the same origin within a Configuration using the following: ++You can customize frame options to use the same origin within a configuration by using the following: + + .X-Frame-Options: SAMEORIGIN + ==== +@@ -499,9 +499,9 @@ class SecurityConfig : WebSecurityConfigurerAdapter() { + [[servlet-headers-xss-protection]] + == X-XSS-Protection + +-By default, Spring Security instructs browsers to block reflected XSS attacks using the <. ++By default, Spring Security instructs browsers to block reflected XSS attacks by using the <>. + However, you can change this default. +-For example, the following Configuration specifies that Spring Security should no longer instruct browsers to block the content: ++For example, the following configuration specifies that Spring Security should no longer instruct browsers to block the content: + + .X-XSS-Protection Customization + ==== +@@ -560,10 +560,10 @@ class SecurityConfig : WebSecurityConfigurerAdapter() { + [[servlet-headers-csp]] + == Content Security Policy (CSP) + +-Spring Security does not add <> by default, because a reasonable default is impossible to know without context of the application. +-The web application author must declare the security policy(s) to enforce and/or monitor for the protected resources. ++Spring Security does not add <> by default, because a reasonable default is impossible to know without knowing the context of the application. ++The web application author must declare the security policy (or policies) to enforce or monitor for the protected resources. + +-For example, given the following security policy: ++Consider the following security policy: + + .Content Security Policy Example + ==== +@@ -573,7 +573,7 @@ Content-Security-Policy: script-src 'self' https://trustedscripts.example.com; o + ---- + ==== + +-You can enable the CSP header as shown below: ++Given the preceding security policy, you can enable the CSP header: + + .Content Security Policy + ==== +@@ -694,7 +694,7 @@ class SecurityConfig : WebSecurityConfigurerAdapter() { + == Referrer Policy + + Spring Security does not add <> headers by default. +-You can enable the Referrer Policy header using the configuration as shown below: ++You can enable the Referrer Policy header by using the configuration: + + .Referrer Policy + ==== +@@ -754,7 +754,7 @@ class SecurityConfig : WebSecurityConfigurerAdapter() { + == Feature Policy + + Spring Security does not add <> headers by default. +-The following `Feature-Policy` header: ++Consider the following `Feature-Policy` header: + + .Feature-Policy Example + ==== +@@ -764,7 +764,7 @@ Feature-Policy: geolocation 'self' + ---- + ==== + +-can enable the Feature Policy header using the configuration shown below: ++You can enable the preceding feature policy header by using the following configuration: + + .Feature-Policy + ==== +@@ -820,7 +820,7 @@ class SecurityConfig : WebSecurityConfigurerAdapter() { + == Permissions Policy + + Spring Security does not add <> headers by default. +-The following `Permissions-Policy` header: ++Consider the following `Permissions-Policy` header: + + .Permissions-Policy Example + ==== +@@ -830,7 +830,7 @@ Permissions-Policy: geolocation=(self) + ---- + ==== + +-can enable the Permissions Policy header using the configuration shown below: ++You can enable the preceding permissions policy header using the following configuration: + + .Permissions-Policy + ==== +@@ -890,7 +890,7 @@ class SecurityConfig : WebSecurityConfigurerAdapter() { + == Clear Site Data + + Spring Security does not add <> headers by default. +-The following Clear-Site-Data header: ++Consider the following Clear-Site-Data header: + + .Clear-Site-Data Example + ==== +@@ -899,7 +899,7 @@ Clear-Site-Data: "cache", "cookies" + ---- + ==== + +-can be sent on log out with the following configuration: ++You can send the preceding header on log out with the following configuration: + + .Clear-Site-Data + ==== +@@ -945,15 +945,15 @@ However, it also provides hooks to enable adding custom headers. + + [[servlet-headers-static]] + === Static Headers +-There may be times you wish to inject custom security headers into your application that are not supported out of the box. +-For example, given the following custom security header: ++There may be times when you wish to inject custom security headers that are not supported out of the box into your application. ++Consider the following custom security header: + + [source] + ---- + X-Custom-Security-Header: header-value + ---- + +-The headers could be added to the response using the following Configuration: ++Given the preceding header, you could add the headers to the response by using the following configuration: + + .StaticHeadersWriter + ==== +@@ -1009,8 +1009,8 @@ class SecurityConfig : WebSecurityConfigurerAdapter() { + === Headers Writer + When the namespace or Java configuration does not support the headers you want, you can create a custom `HeadersWriter` instance or even provide a custom implementation of the `HeadersWriter`. + +-Let's take a look at an example of using an custom instance of `XFrameOptionsHeaderWriter`. +-If you wanted to explicitly configure <> it could be done with the following Configuration: ++The next example use a custom instance of `XFrameOptionsHeaderWriter`. ++If you wanted to explicitly configure <>, you could do so with the following configuration: + + .Headers Writer + ==== +@@ -1071,11 +1071,11 @@ class SecurityConfig : WebSecurityConfigurerAdapter() { + [[headers-delegatingrequestmatcherheaderwriter]] + === DelegatingRequestMatcherHeaderWriter + +-At times you may want to only write a header for certain requests. +-For example, perhaps you want to only protect your log in page from being framed. ++At times, you may want to write a header only for certain requests. ++For example, perhaps you want to protect only your login page from being framed. + You could use the `DelegatingRequestMatcherHeaderWriter` to do so. + +-An example of using `DelegatingRequestMatcherHeaderWriter` in Java Configuration can be seen below: ++The following configuration example uses `DelegatingRequestMatcherHeaderWriter`: + + .DelegatingRequestMatcherHeaderWriter Java Configuration + ==== +diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/exploits/http.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/exploits/http.adoc +index f9d8c3275b..c077006a08 100644 +--- a/docs/manual/src/docs/asciidoc/_includes/servlet/exploits/http.adoc ++++ b/docs/manual/src/docs/asciidoc/_includes/servlet/exploits/http.adoc +@@ -1,16 +1,16 @@ + [[servlet-http]] + = HTTP + +-All HTTP based communication should be protected <>. ++All HTTP-based communication should be protected <>. + +-Below you can find details around Servlet specific features that assist with HTTPS usage. ++This section discusses the details of servlet-specific features that assist with HTTPS usage. + + [[servlet-http-redirect]] + == Redirect to HTTPS + +-If a client makes a request using HTTP rather than HTTPS, Spring Security can be configured to redirect to HTTPS. ++If a client makes a request using HTTP rather than HTTPS, you can configure Spring Security to redirect to HTTPS. + +-For example, the following Java configuration will redirect any HTTP requests to HTTPS: ++For example, the following Java or Kotlin configuration redirects any HTTP requests to HTTPS: + + .Redirect to HTTPS + ==== +@@ -52,7 +52,7 @@ class SecurityConfig : WebSecurityConfigurerAdapter() { + ---- + ==== + +-The following XML configuration will redirect all HTTP requests to HTTPS ++The following XML configuration redirects all HTTP requests to HTTPS + + .Redirect to HTTPS with XML Configuration + ==== +diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/exploits/index.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/exploits/index.adoc +index bc955238c2..6a8e4b15e7 100644 +--- a/docs/manual/src/docs/asciidoc/_includes/servlet/exploits/index.adoc ++++ b/docs/manual/src/docs/asciidoc/_includes/servlet/exploits/index.adoc +@@ -1,6 +1,8 @@ + [[servlet-exploits]] + = Protection Against Exploits + ++This section details how Spring Security provides protection against some of the most common exploits. ++ + include::csrf.adoc[leveloffset=+1] + + include::headers.adoc[leveloffset=+1] +diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/hello/index.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/hello/index.adoc +index 57e9f5f1ce..98bd31f5c4 100644 +--- a/docs/manual/src/docs/asciidoc/_includes/servlet/hello/index.adoc ++++ b/docs/manual/src/docs/asciidoc/_includes/servlet/hello/index.adoc +@@ -3,11 +3,8 @@ + + This section covers the minimum setup for how to use Spring Security with Spring Boot. + +-[NOTE] +-==== +-The completed application can be found at {gh-samples-url}/boot/helloworld[samples/boot/helloworld] +-For your convenience, you can download a minimal Spring Boot + Spring Security application by https://start.spring.io/starter.zip?type=maven-project&language=java&packaging=jar&jvmVersion=1.8&groupId=example&artifactId=hello-security&name=hello-security&description=Hello%20Security&packageName=example.hello-security&dependencies=web,security[clicking here]. +-==== ++NOTE: The completed application can be found at {gh-samples-url}/boot/helloworld[samples/boot/helloworld] ++For your convenience, you can download https://start.spring.io/starter.zip?type=maven-project&language=java&packaging=jar&jvmVersion=1.8&groupId=example&artifactId=hello-security&name=hello-security&description=Hello%20Security&packageName=example.hello-security&dependencies=web,security[a minimal Spring Boot + Spring Security application]. + + [[servlet-hello-dependencies]] + == Updating Dependencies +@@ -40,12 +37,12 @@ Using generated security password: 8e557245-73e2-4286-969a-ff57fe326336 + + // FIXME: Link to relevant portions of documentation + // FIXME: Link to Spring Boot's Security Auto configuration classes +-// FIXME: Add a links for what user's should do next ++// FIXME: Add links for what user's should do next + + Spring Boot automatically: + + * Enables Spring Security's default configuration, which creates a servlet `Filter` as a bean named `springSecurityFilterChain`. +-This bean is responsible for all the security (protecting the application URLs, validating submitted username and passwords, redirecting to the log in form, and so on) within your application. ++This bean is responsible for all the security (protecting the application URLs, validating submitted username and passwords, redirecting to the login form, and so on) within your application. + * Creates a `UserDetailsService` bean with a username of `user` and a randomly generated password that is logged to the console. + * Registers the `Filter` with a bean named `springSecurityFilterChain` with the Servlet container for every request. + +@@ -71,4 +68,3 @@ A summary of the features follows: + ** https://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletRequest.html#isUserInRole(java.lang.String)[`HttpServletRequest.html#isUserInRole(java.lang.String)`] + ** https://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletRequest.html#login(java.lang.String,%20java.lang.String)[`HttpServletRequest.html#login(java.lang.String, java.lang.String)`] + ** https://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletRequest.html#logout()[`HttpServletRequest.html#logout()`] +- +diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/concurrency.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/concurrency.adoc +index 78aeb0b674..d276815e2d 100644 +--- a/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/concurrency.adoc ++++ b/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/concurrency.adoc +@@ -1,19 +1,20 @@ + [[concurrency]] + == Concurrency Support + +-In most environments, Security is stored on a per `Thread` basis. ++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. +-Spring Security provides some infrastructure to help make this much easier for users. +-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 <> and <>. ++Spring Security provides some infrastructure to help make this much easier to manage. ++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 integrate with <> and <>. + + === 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. +-It then invokes the delegate Runnable ensuring to clear the `SecurityContextHolder` afterwards. ++It wraps a delegate `Runnable` to initialize the `SecurityContextHolder` with a specified `SecurityContext` for the delegate. ++It then invokes the delegate `Runnable`, ensuring to clear the `SecurityContextHolder` afterwards. + The `DelegatingSecurityContextRunnable` looks something like this: + ++==== + [source,java] + ---- + public void run() { +@@ -25,13 +26,15 @@ try { + } + } + ---- ++==== + +-While very simple, it makes it seamless to transfer the SecurityContext from one Thread to another. +-This is important since, in most cases, the SecurityContextHolder acts on a per Thread basis. ++While very simple, it makes it seamless to transfer the `SecurityContext` from one `Thread` to another. ++This is important since, in most cases, the `SecurityContextHolder` acts on a per-`Thread` basis. + For example, you might have used Spring Security's <> support to secure one of your services. +-You can now easily transfer the `SecurityContext` of the current `Thread` to the `Thread` that invokes the secured service. +-An example of how you might do this can be found below: ++You can now transfer the `SecurityContext` of the current `Thread` to the `Thread` that invokes the secured service. ++The following example show how you might do so: + ++==== + [source,java] + ---- + Runnable originalRunnable = new Runnable() { +@@ -46,18 +49,18 @@ DelegatingSecurityContextRunnable wrappedRunnable = + + new Thread(wrappedRunnable).start(); + ---- ++==== + +-The code above performs the following steps: ++The preceding code: + +-* Creates a `Runnable` that will be invoking our secured service. +-Notice that it is not aware of Spring Security +-* Obtains the `SecurityContext` that we wish to use from the `SecurityContextHolder` and initializes the `DelegatingSecurityContextRunnable` +-* Use the `DelegatingSecurityContextRunnable` to create a Thread +-* Start the Thread we created +- +-Since it is quite common to create a `DelegatingSecurityContextRunnable` with the `SecurityContext` from the `SecurityContextHolder` there is a shortcut constructor for it. +-The following code is the same as the code above: ++* Creates a `Runnable` that invokes our secured service. ++Note that it is not aware of Spring Security. ++* Obtains the `SecurityContext` that we wish to use from the `SecurityContextHolder` and initializes the `DelegatingSecurityContextRunnable`. ++* Uses the `DelegatingSecurityContextRunnable` to create a `Thread`. ++* Starts the `Thread` we created. + ++Since it is common to create a `DelegatingSecurityContextRunnable` with the `SecurityContext` from the `SecurityContextHolder`, there is a shortcut constructor for it. ++The following code has the same effect as the preceding code: + + [source,java] + ---- +@@ -73,18 +76,18 @@ DelegatingSecurityContextRunnable wrappedRunnable = + new 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. ++This code still requires us to know that we are using Spring Security. ++In the next section, we take a look at how we can use `DelegatingSecurityContextExecutor` to hide the fact that we use Spring Security. + + === 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. +- +-The design of `DelegatingSecurityContextExecutor` is very similar to that of `DelegatingSecurityContextRunnable` except it accepts a delegate `Executor` instead of a delegate `Runnable`. +-You can see an example of how it might be used below: ++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 to use it. ++Now we look at how `DelegatingSecurityContextExecutor` can shield our code from any knowledge that we are using Spring Security. + ++The design of `DelegatingSecurityContextExecutor` is similar to that of `DelegatingSecurityContextRunnable`, except that it accepts a delegate `Executor` instead of a delegate `Runnable`. ++The following example shows how to use it: + ++==== + [source,java] + ---- + SecurityContext context = SecurityContextHolder.createEmptyContext(); +@@ -105,19 +108,23 @@ public void run() { + + executor.execute(originalRunnable); + ---- ++==== + +-The code performs the following steps: ++This code: + + * Creates the `SecurityContext` to be used for our `DelegatingSecurityContextExecutor`. +-Note that in this example we simply create the `SecurityContext` by hand. +-However, it does not matter where or how we get the `SecurityContext` (i.e. we could obtain it from the `SecurityContextHolder` if we wanted). +-* Creates a delegateExecutor that is in charge of executing submitted ``Runnable``s +-* Finally we create a `DelegatingSecurityContextExecutor` which is in charge of wrapping any Runnable that is passed into the execute method with a `DelegatingSecurityContextRunnable`. +-It then passes the wrapped Runnable to the delegateExecutor. +-In this instance, the same `SecurityContext` will be used for every Runnable submitted to our `DelegatingSecurityContextExecutor`. +-This is nice if we are running background tasks that need to be run by a user with elevated privileges. +-* At this point you may be asking yourself "How does this shield my code of any knowledge of Spring Security?" Instead of creating the `SecurityContext` and the `DelegatingSecurityContextExecutor` in our own code, we can inject an already initialized instance of `DelegatingSecurityContextExecutor`. +- ++Note that, in this example, we create the `SecurityContext` by hand. ++However, it does not matter where or how we get the `SecurityContext` (for example, we could obtain it from the `SecurityContextHolder`). ++* Creates a `delegateExecutor` that is in charge of executing submitted `Runnable` objects. ++* Finally, we create a `DelegatingSecurityContextExecutor`, which is in charge of wrapping any `Runnable` that is passed into the `execute` method with a `DelegatingSecurityContextRunnable`. ++It then passes the wrapped `Runnable` to the `delegateExecutor`. ++In this case, the same `SecurityContext` is used for every `Runnable` submitted to our `DelegatingSecurityContextExecutor`. ++This is nice if we run background tasks that need to be run by a user with elevated privileges. ++* At this point, you may ask yourself, "`How does this shield my code of any knowledge of Spring Security?`" Instead of creating the `SecurityContext` and the `DelegatingSecurityContextExecutor` in our own code, we can inject an already initialized instance of `DelegatingSecurityContextExecutor`. ++ ++Consider the following example: ++ ++==== + [source,java] + ---- + @Autowired +@@ -132,35 +139,36 @@ Runnable originalRunnable = new Runnable() { + executor.execute(originalRunnable); + } + ---- ++==== + +-Now our code is unaware that the `SecurityContext` is being propagated to the `Thread`, then the `originalRunnable` is run, and then the `SecurityContextHolder` is cleared out. ++Now our code is unaware that the `SecurityContext` is being propagated to the `Thread`, the `originalRunnable` is run, and the `SecurityContextHolder` is cleared out. + In this example, the same user is being used to run each thread. +-What if we wanted to use the user from `SecurityContextHolder` at the time we invoked `executor.execute(Runnable)` (i.e. the currently logged in user) to process ``originalRunnable``? +-This can be done by removing the `SecurityContext` argument from our `DelegatingSecurityContextExecutor` constructor. +-For example: +- ++What if we wanted to use the user from `SecurityContextHolder` (that is, the currently logged in-user) at the time we invoked `executor.execute(Runnable)` to process `originalRunnable`? ++You can do so by removing the `SecurityContext` argument from our `DelegatingSecurityContextExecutor` constructor: + ++==== + [source,java] + ---- + SimpleAsyncTaskExecutor delegateExecutor = new SimpleAsyncTaskExecutor(); + DelegatingSecurityContextExecutor executor = + new 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`. ++Now, any time `executor.execute(Runnable)` is run, 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 + +-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. +- +-* `DelegatingSecurityContextCallable` +-* `DelegatingSecurityContextExecutor` +-* `DelegatingSecurityContextExecutorService` +-* `DelegatingSecurityContextRunnable` +-* `DelegatingSecurityContextScheduledExecutorService` +-* `DelegatingSecurityContextSchedulingTaskExecutor` +-* `DelegatingSecurityContextAsyncTaskExecutor` +-* `DelegatingSecurityContextTaskExecutor` +-* `DelegatingSecurityContextTaskScheduler` ++See the {security-api-url}index.html[Javadoc] for additional integrations with both the Java concurrent APIs and the Spring Task abstractions. ++They are self-explanatory once you understand the previous code. ++ ++* {security-api-url}org/springframework/security/concurrent/DelegatingSecurityContextCallable.html[`DelegatingSecurityContextCallable`] ++* {security-api-url}org/springframework/security/concurrent/DelegatingSecurityContextExecutor.html[`DelegatingSecurityContextExecutor`] ++* {security-api-url}org/springframework/security/concurrent/DelegatingSecurityContextExecutorService.html[`DelegatingSecurityContextExecutorService`] ++* {security-api-url}org/springframework/security/concurrent/DelegatingSecurityContextRunnable.html[`DelegatingSecurityContextRunnable`] ++* {security-api-url}org/springframework/security/concurrent/DelegatingSecurityContextScheduledExecutorService.html[`DelegatingSecurityContextScheduledExecutorService`] ++* {security-api-url}org/springframework/security/scheduling/DelegatingSecurityContextSchedulingTaskExecutor.html[`DelegatingSecurityContextSchedulingTaskExecutor`] ++* {security-api-url}org/springframework/security/task/DelegatingSecurityContextAsyncTaskExecutor.html[`DelegatingSecurityContextAsyncTaskExecutor`] ++* {security-api-url}org/springframework/security/task/DelegatingSecurityContextTaskExecutor.html[`DelegatingSecurityContextTaskExecutor`] ++* {security-api-url}org/springframework/security/scheduling/DelegatingSecurityContextTaskScheduler.html[`DelegatingSecurityContextTaskScheduler`] +diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/cors.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/cors.adoc +index 188da871c1..ce315decd1 100644 +--- a/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/cors.adoc ++++ b/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/cors.adoc +@@ -2,12 +2,13 @@ + == 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`). +-If the request does not contain any cookies and Spring Security is first, the request will determine the user is not authenticated (since there are no cookies in the request) and reject it. ++CORS must be processed before Spring Security, because the pre-flight request does not contain any cookies (that is, the `JSESSIONID`). ++If the request does not contain any cookies and Spring Security is first, the request determines that the user is not authenticated (since there are no cookies in the request) and rejects it. + + The easiest way to ensure that CORS is handled first is to use the `CorsFilter`. +-Users can integrate the `CorsFilter` with Spring Security by providing a `CorsConfigurationSource` using the following: ++Users can integrate the `CorsFilter` with Spring Security by providing a `CorsConfigurationSource` that uses the following: + ++==== + [source,java] + ---- + @EnableWebSecurity +@@ -32,9 +33,11 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter { + } + } + ---- ++==== + +-or in XML ++The following listing does the same thing in XML: + ++==== + [source,xml] + ---- + +@@ -45,9 +48,11 @@ or in XML + ... + + ---- ++==== + +-If you are using Spring MVC's CORS support, you can omit specifying the `CorsConfigurationSource` and Spring Security will leverage the CORS configuration provided to Spring MVC. ++If you use Spring MVC's CORS support, you can omit specifying the `CorsConfigurationSource` and Spring Security uses the CORS configuration provided to Spring MVC: + ++==== + [source,java] + ---- + @EnableWebSecurity +@@ -63,9 +68,11 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter { + } + } + ---- ++==== + +-or in XML ++The following listing does the same thing in XML: + ++==== + [source,xml] + ---- + +@@ -74,3 +81,4 @@ or in XML + ... + + ---- ++==== +diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/data.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/data.adoc +index 07a1decc3f..04e5a8c7bf 100644 +--- a/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/data.adoc ++++ b/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/data.adoc +@@ -2,14 +2,15 @@ + == 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. ++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 + +-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: ++To use this support, add the `org.springframework.security:spring-security-data` dependency and provide a bean of type `SecurityEvaluationContextExtension`. ++In Java configuration, this would look like: + ++==== + [source,java] + ---- + @Bean +@@ -17,20 +18,23 @@ public SecurityEvaluationContextExtension securityEvaluationContextExtension() { + return new SecurityEvaluationContextExtension(); + } + ---- ++==== + + In XML Configuration, this would look like: + ++==== + [source,xml] + ---- + + ---- ++==== + + [[data-query]] + === Security Expressions within @Query + +-Now Spring Security can be used within your queries. +-For example: ++Now you can use Spring Security within your queries: + ++==== + [source,java] + ---- + @Repository +@@ -39,7 +43,8 @@ public interface MessageRepository extends PagingAndSortingRepository findInbox(Pageable pageable); + } + ---- ++==== + + This checks to see if the `Authentication.getPrincipal().getId()` is equal to the recipient of the `Message`. +-Note that this example assumes you have customized the principal to be an Object that has an id property. +-By exposing the `SecurityEvaluationContextExtension` bean, all of the <> are available within the Query. ++Note that this example assumes you have customized the principal to be an `Object` that has an `id` property. ++By exposing the `SecurityEvaluationContextExtension` bean, all of the <> are available within the query. +diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/index.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/index.adoc +index 90b9783a1f..8673bae878 100644 +--- a/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/index.adoc ++++ b/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/index.adoc +@@ -1,5 +1,7 @@ + = Integrations + ++This section describes various integrations that Spring Security has with other technologies: ++ + include::servlet-api.adoc[] + + include::data.adoc[] +diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/jackson.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/jackson.adoc +index 9e6418a175..d7ef8670ca 100644 +--- a/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/jackson.adoc ++++ b/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/jackson.adoc +@@ -1,11 +1,12 @@ + [[jackson]] + == 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). ++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 (session replication, Spring Session, and so on). + + To use it, register the `SecurityJackson2Modules.getModules(ClassLoader)` with `ObjectMapper` (https://github.com/FasterXML/jackson-databind[jackson-databind]): + ++==== + [source,java] + ---- + ObjectMapper mapper = new ObjectMapper(); +@@ -18,13 +19,14 @@ SecurityContext context = new SecurityContextImpl(); + // ... + String json = mapper.writeValueAsString(context); + ---- ++==== + + [NOTE] + ==== + The following Spring Security modules provide Jackson support: + +-- spring-security-core (`CoreJackson2Module`) +-- spring-security-web (`WebJackson2Module`, `WebServletJackson2Module`, `WebServerJackson2Module`) +-- <> (`OAuth2ClientJackson2Module`) +-- spring-security-cas (`CasJackson2Module`) ++- spring-security-core ({security-api-url}org/springframework/security/jackson2/CoreJackson2Module.html[`CoreJackson2Module`]) ++- spring-security-web ({security-api-url}org/springframework/security/web/jackson2/WebJackson2Module.html[`WebJackson2Module`], {security-api-url}org/springframework/security/web/jackson2/WebServletJackson2Module.html[`WebServletJackson2Module`], {security-api-url}org/springframework/security/web/server/jackson2/WebServerJackson2Module.html[`WebServerJackson2Module`]) ++- <> ({security-api-url}org/springframework/security/oauth2/client/jackson2/OAuth2ClientJackson2Module.html[`OAuth2ClientJackson2Module`]) ++- spring-security-cas ({security-api-url}org/springframework/security/cas/jackson2/CasJackson2Module.html[`CasJackson2Module`]) + ==== +diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/jsp-taglibs.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/jsp-taglibs.adoc +index 3f31683258..b0c1e3a5d9 100644 +--- a/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/jsp-taglibs.adoc ++++ b/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/jsp-taglibs.adoc +@@ -1,26 +1,30 @@ + [[taglibs]] + == JSP Tag Libraries +-Spring Security has its own taglib which provides basic support for accessing security information and applying security constraints in JSPs. ++Spring Security has its own taglib, which provides basic support for accessing security information and applying security constraints in JSPs. + + + === Declaring the Taglib + To use any of the tags, you must have the security taglib declared in your JSP: + ++==== + [source,xml] + ---- + <%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags" %> + ---- ++==== + + [[taglibs-authorize]] + === 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. +-]. +-The first approach uses a <>, specified in the `access` attribute of the tag. +-The expression evaluation will be delegated to the `SecurityExpressionHandler` defined in the application context (you should have web expressions enabled in your `` namespace configuration to make sure this service is available). +-So, for example, you might have ++In Spring Security 3.0, it can be used in two ways. + ++NOTE: The legacy options from Spring Security 2.0 are also supported, but discouraged. ++ ++The first approach uses a <>, which is specified in the `access` attribute of the tag. ++The expression evaluation is delegated to the `SecurityExpressionHandler` defined in the application context (you should have web expressions enabled in your `` namespace configuration to make sure this service is available). ++So, for example, you might have: ++ ++==== + [source,xml] + ---- + +@@ -29,10 +33,11 @@ This content will only be visible to users who have the "supervisor" authority i + + + ---- ++==== + +-When used in conjunction with Spring Security's PermissionEvaluator, the tag can also be used to check permissions. +-For example: ++When used in conjunction with Spring Security's `PermissionEvaluator`, the tag can also be used to check permissions: + ++==== + [source,xml] + ---- + +@@ -41,12 +46,14 @@ This content will only be visible to users who have read or write permission to + + + ---- ++==== + +-A common requirement is to only show a particular link, if the user is actually allowed to click it. +-How can we determine in advance whether something will be allowed? This tag can also operate in an alternative mode which allows you to define a particular URL as an attribute. +-If the user is allowed to invoke that URL, then the tag body will be evaluated, otherwise it will be skipped. +-So you might have something like ++A common requirement is to show only a particular link, assuming the user is actually allowed to click it. ++How can we determine in advance whether something is allowed? This tag can also operate in an alternative mode that lets you define a particular URL as an attribute. ++If the user is allowed to invoke that URL, the tag body is evaluated. Otherwise, it is skipped. ++So you might have something like: + ++==== + [source,xml] + ---- + +@@ -55,60 +62,64 @@ This content will only be visible to users who are authorized to send requests t + + + ---- ++==== + +-To use this tag there must also be an instance of `WebInvocationPrivilegeEvaluator` in your application context. +-If you are using the namespace, one will automatically be registered. ++To use this tag, you must also have an instance of `WebInvocationPrivilegeEvaluator` in your application context. ++If you are using the namespace, one is automatically registered. + This is an instance of `DefaultWebInvocationPrivilegeEvaluator`, which creates a dummy web request for the supplied URL and invokes the security interceptor to see whether the request would succeed or fail. +-This allows you to delegate to the access-control setup you defined using `intercept-url` declarations within the `` namespace configuration and saves having to duplicate the information (such as the required roles) within your JSPs. +-This approach can also be combined with a `method` attribute, supplying the HTTP method, for a more specific match. ++This lets you delegate to the access-control setup you defined by using `intercept-url` declarations within the `` namespace configuration and saves having to duplicate the information (such as the required roles) within your JSPs. ++You can also combine this approach with a `method` attribute (supplying the HTTP method, such as `POST`) for a more specific match. + +-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. ++You can store the Boolean result of evaluating the tag (whether it grants or denies access) 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 +-Hiding a link in a page for unauthorized users doesn't prevent them from accessing the URL. ++Hiding a link in a page for unauthorized users does not 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. +-If you set the system property `spring.security.disableUISecurity` to `true`, the `authorize` tag will still run but will not hide its contents. +-By default it will also surround the content with `...` tags. +-This allows you to display "hidden" content with a particular CSS style such as a different background colour. +-Try running the "tutorial" sample application with this property enabled, for example. ++As part of your testing process, you may want to reveal the hidden areas, to check that links really are secured at the back end. ++If you set the `spring.security.disableUISecurity` system property to `true`, the `authorize` tag still runs but does not hide its contents. ++By default, it also surrounds the content with `...` tags. ++This lets you to display "`hidden`" content with a particular CSS style, such as a different background color. ++Try running the "`tutorial`" sample application, for example, with this property enabled. + +-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). ++You can also set the `spring.security.securedUIPrefix` and `spring.security.securedUISuffix` properties if you want to change surrounding text from the default `span` tags (or use empty strings to remove it completely). + + + === 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 `` will render the name of the current user. ++So, for example, if the `principal` property of the `Authentication` is an instance of Spring Security's `UserDetails` object, then using `` renders the name of the current user. + +-Of course, it isn't necessary to use JSP tags for this kind of thing and some people prefer to keep as little logic as possible in the view. ++Of course, it is not necessary to use JSP tags for this kind of thing, and some people prefer to keep as little logic as possible in the view. + 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 + 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. +-If they don't, it will be skipped. +-An example might be ++If the current user has all of those permissions, the tag body is evaluated. ++If they do not, it is skipped. + + CAUTION: In general this tag should be considered deprecated. + Instead use the <>. + ++The following listing shows an example: ++ ++==== + [source,xml] + ---- + + +-This will be shown if the user has all of the permissions represented by the values "1" or "2" on the given object. ++ + + + ---- ++==== + +-The permissions are passed to the `PermissionFactory` defined in the application context, converting them to ACL `Permission` instances, so they may be any format which is supported by the factory - they don't have to be integers, they could be strings like `READ` or `WRITE`. +-If no `PermissionFactory` is found, an instance of `DefaultPermissionFactory` will be used. +-The `AclService` from the application context will be used to load the `Acl` instance for the supplied object. +-The `Acl` will be invoked with the required permissions to check if all of them are granted. ++The permissions are passed to the `PermissionFactory` defined in the application context, converting them to ACL `Permission` instances, so they may be any format that is supported by the factory. They do not have to be integers. They could be strings such as `READ` or `WRITE`. ++If no `PermissionFactory` is found, an instance of `DefaultPermissionFactory` is used. ++The `AclService` from the application context is used to load the `Acl` instance for the supplied object. ++The `Acl` is invoked with the required permissions to check if all of them are granted. + + This tag also supports the `var` attribute, in the same way as the `authorize` tag. + +@@ -117,12 +128,14 @@ This tag also supports the `var` attribute, in the same way as the `authorize` t + 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. + +-Normally Spring Security automatically inserts a CSRF form field for any `` tags you use, but if for some reason you cannot use ``, `csrfInput` is a handy replacement. ++Normally, Spring Security automatically inserts a CSRF form field for any `` tags you use, but if for some reason you cannot use ``, `csrfInput` is a handy replacement. + + You should place this tag within an HTML `
` block, where you would normally place other input fields. + Do NOT place this tag within a Spring `` block. + Spring Security handles Spring forms automatically. ++The following listing shows an example: + ++==== + [source,xml] + ---- +
+@@ -132,16 +145,19 @@ Spring Security handles Spring forms automatically. + ... +
+ ---- ++==== + + [[taglibs-csrfmeta]] + === 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. ++If CSRF protection is enabled, this tag inserts meta tags that contain 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. + + You should place `csrfMetaTags` within an HTML ` ` block, where you would normally place other meta tags. +-Once you use this tag, you can access the form field name, header name, and token value easily using JavaScript. ++Once you use this tag, you can access the form field name, header name, and token value by using JavaScript. + JQuery is used in this example to make the task easier. ++The following listing shows an example: + ++==== + [source,xml] + ---- + +@@ -197,6 +213,6 @@ JQuery is used in this example to make the task easier. + + + ---- ++==== + + If CSRF protection is not enabled, `csrfMetaTags` outputs nothing. +- +diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/localization.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/localization.adoc +index 0f8f9b402e..d7bff6a279 100644 +--- a/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/localization.adoc ++++ b/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/localization.adoc +@@ -1,17 +1,18 @@ + [[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. ++If your application is designed for English-speaking users, you need not do anything as, by default, all Security messages are in English. ++If you need to support other locales, this section contains everything you need to know. + +-All exception messages can be localized, including messages related to authentication failures and access being denied (authorization failures). +-Exceptions and logging messages that are focused on developers or system deplopers (including incorrect attributes, interface contract violations, using incorrect constructors, startup time validation, debug-level logging) are not localized and instead are hard-coded in English within Spring Security's code. ++All exception messages, including messages related to authentication failures and access being denied (authorization failures), can be localized. ++Exceptions and logging messages that are focused on developers or system deployers (including incorrect attributes, interface contract violations, using incorrect constructors, startup time validation, debug-level logging) are not localized and instead are hard-coded in English within Spring Security's code. + +-Shipping in the `spring-security-core-xx.jar` you will find an `org.springframework.security` package that in turn contains a `messages.properties` file, as well as localized versions for some common languages. +-This should be referred to by your `ApplicationContext`, as Spring Security classes implement Spring's `MessageSourceAware` interface and expect the message resolver to be dependency injected at application context startup time. +-Usually all you need to do is register a bean inside your application context to refer to the messages. +-An example is shown below: ++In the `spring-security-core-xx.jar`, you find an `org.springframework.security` package that, in turn, contains a `messages.properties` file as well as localized versions for some common languages. ++Your `ApplicationContext` should refer to this, as Spring Security classes implement Spring's `MessageSourceAware` interface and expect the message resolver to be dependency injected at application context startup time. ++Usually, all you need to do is register a bean inside your application context to refer to the messages. ++The following listing shows an example: + ++==== + [source,xml] + ---- + + + ---- ++==== + + The `messages.properties` is named in accordance with standard resource bundles and represents the default language supported by Spring Security messages. + This default file is in English. + +-If you wish to customize the `messages.properties` file, or support other languages, you should copy the file, rename it accordingly, and register it inside the above bean definition. ++To customize the `messages.properties` file or support other languages, you should copy the file, rename it accordingly, and register it inside the preceding bean definition. + There are not a large number of message keys inside this file, so localization should not be considered a major initiative. +-If you do perform localization of this file, please consider sharing your work with the community by logging a JIRA task and attaching your appropriately-named localized version of `messages.properties`. ++If you do perform localization of this file, consider sharing your work with the community by logging a JIRA task and attaching your appropriately-named localized version of `messages.properties`. + +-Spring Security relies on Spring's localization support in order to actually lookup the appropriate message. +-In order for this to work, you have to make sure that the locale from the incoming request is stored in Spring's `org.springframework.context.i18n.LocaleContextHolder`. +-Spring MVC's `DispatcherServlet` does this for your application automatically, but since Spring Security's filters are invoked before this, the `LocaleContextHolder` needs to be set up to contain the correct `Locale` before the filters are called. ++Spring Security relies on Spring's localization support in order to actually look up the appropriate message. ++For this to work, you have to make sure that the locale from the incoming request is stored in Spring's `org.springframework.context.i18n.LocaleContextHolder`. ++Spring MVC's `DispatcherServlet` does this for your application automatically. However, since Spring Security's filters are invoked before this, the `LocaleContextHolder` needs to be set up to contain the correct `Locale` before the filters are called. + You can either do this in a filter yourself (which must come before the Spring Security filters in `web.xml`) or you can use Spring's `RequestContextFilter`. +-Please refer to the Spring Framework documentation for further details on using localization with Spring. ++See the Spring Framework documentation for further details on using localization with Spring. + +-The "contacts" sample application is set up to use localized messages. ++The `contacts` sample application is set up to use localized messages. +diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/mvc.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/mvc.adoc +index fe34eb8e29..020e209adf 100644 +--- a/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/mvc.adoc ++++ b/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/mvc.adoc +@@ -8,24 +8,25 @@ This section covers the integration in further detail. + === @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. ++The replacement is `@EnableWebSecurity`, which adds the Spring MVC features, based upon the classpath. + +-To enable Spring Security integration with Spring MVC add the `@EnableWebSecurity` annotation to your configuration. ++To enable Spring Security integration with Spring MVC, add the `@EnableWebSecurity` annotation to your configuration. + +-NOTE: Spring Security provides the configuration using Spring MVC's https://docs.spring.io/spring/docs/5.0.0.RELEASE/spring-framework-reference/web.html#mvc-config-customize[WebMvcConfigurer]. +-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. ++NOTE: Spring Security provides the configuration by using Spring MVC's https://docs.spring.io/spring/docs/5.0.0.RELEASE/spring-framework-reference/web.html#mvc-config-customize[`WebMvcConfigurer`]. ++This means that, if you use more advanced options, such as integrating with `WebMvcConfigurationSupport` directly, you need to manually provide the Spring Security configuration. + + [[mvc-requestmatcher]] + === 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. ++This is helpful to ensure that your Security rules match the logic used to handle your requests. + +-In order to use `MvcRequestMatcher` you must place the Spring Security Configuration in the same `ApplicationContext` as your `DispatcherServlet`. ++To use `MvcRequestMatcher`, you must place the Spring Security Configuration in the same `ApplicationContext` as your `DispatcherServlet`. + This is necessary because Spring Security's `MvcRequestMatcher` expects a `HandlerMappingIntrospector` bean with the name of `mvcHandlerMappingIntrospector` to be registered by your Spring MVC configuration that is used to perform the matching. + +-For a `web.xml` this means that you should place your configuration in the `DispatcherServlet.xml`. ++For a `web.xml` file, this means that you should place your configuration in the `DispatcherServlet.xml`: + ++==== + [source,xml] + ---- + +@@ -53,9 +54,11 @@ For a `web.xml` this means that you should place your configuration in the `Disp + / + + ---- ++==== + +-Below `WebSecurityConfiguration` in placed in the ``DispatcherServlet``s `ApplicationContext`. ++The following `WebSecurityConfiguration` in placed in the `ApplicationContext` of the `DispatcherServlet`. + ++==== + [source,java] + ---- + public class SecurityInitializer extends +@@ -78,26 +81,32 @@ public class SecurityInitializer extends + } + } + ---- ++==== + + [NOTE] + ==== +-It is always recommended to provide authorization rules by matching on the `HttpServletRequest` and method security. ++We always recommend that you provide authorization rules by matching on the `HttpServletRequest` and method security. + +-Providing authorization rules by matching on `HttpServletRequest` is good because it happens very early in the code path and helps reduce the https://en.wikipedia.org/wiki/Attack_surface[attack surface]. +-Method security ensures that if someone has bypassed the web authorization rules, that your application is still secured. +-This is what is known as https://en.wikipedia.org/wiki/Defense_in_depth_(computing)[Defence in Depth] ++Providing authorization rules by matching on `HttpServletRequest` is good, because it happens very early in the code path and helps reduce the https://en.wikipedia.org/wiki/Attack_surface[attack surface]. ++Method security ensures that, if someone has bypassed the web authorization rules, your application is still secured. ++This is known as https://en.wikipedia.org/wiki/Defense_in_depth_(computing)[Defense in Depth] + ==== + + Consider a controller that is mapped as follows: + ++==== + [source,java] + ---- + @RequestMapping("/admin") + public String admin() { ++ ... ++} + ---- ++==== + +-If we wanted to restrict access to this controller method to admin users, a developer can provide authorization rules by matching on the `HttpServletRequest` with the following: ++To restrict access to this controller method to admin users, you can provide authorization rules by matching on the `HttpServletRequest` with the following: + ++==== + [source,java] + ---- + protected configure(HttpSecurity http) throws Exception { +@@ -107,27 +116,30 @@ protected configure(HttpSecurity http) throws Exception { + ); + } + ---- ++==== + +-or in XML ++The following listing does the same thing in XML: + ++==== + [source,xml] + ---- + + + + ---- ++==== + +-With either configuration, the URL `/admin` will require the authenticated user to be an admin user. +-However, depending on our Spring MVC configuration, the URL `/admin.html` will also map to our `admin()` method. +-Additionally, depending on our Spring MVC configuration, the URL `/admin/` will also map to our `admin()` method. ++With either configuration, the `/admin` URL requires the authenticated user to be an admin user. ++However, depending on our Spring MVC configuration, the `/admin.html` URL also maps to our `admin()` method. ++Additionally, depending on our Spring MVC configuration, the `/admin` URL also maps to our `admin()` method. + +-The problem is that our security rule is only protecting `/admin`. ++The problem is that our security rule protects only `/admin`. + We could add additional rules for all the permutations of Spring MVC, but this would be quite verbose and tedious. + +-Instead, we can leverage Spring Security's `MvcRequestMatcher`. +-The following configuration will protect the same URLs that Spring MVC will match on by using Spring MVC to match on the URL. +- ++Instead, we can use Spring Security's `MvcRequestMatcher`. ++The following configuration protects the same URLs that Spring MVC matches on by using Spring MVC to match on the URL. + ++==== + [source,java] + ---- + protected configure(HttpSecurity http) throws Exception { +@@ -137,24 +149,27 @@ protected configure(HttpSecurity http) throws Exception { + ); + } + ---- ++==== + +-or in XML ++The following XML has the same effect: + ++==== + [source,xml] + ---- + + + + ---- ++==== + + [[mvc-authentication-principal]] + === @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. +-If you use XML based configuration, you must add this yourself. +-For example: ++Spring Security provides `AuthenticationPrincipalArgumentResolver`, which can automatically resolve the current `Authentication.getPrincipal()` for Spring MVC arguments. ++By using `@EnableWebSecurity`, you automatically have this added to your Spring MVC configuration. ++If you use XML-based configuration, you must add this yourself: + ++==== + [source,xml] + ---- + +@@ -163,11 +178,13 @@ For example: + + + ---- ++==== + +-Once `AuthenticationPrincipalArgumentResolver` is properly configured, you can be entirely decoupled from Spring Security in your Spring MVC layer. ++Once you have properly configured `AuthenticationPrincipalArgumentResolver`, you can entirely decouple from Spring Security in your Spring MVC layer. + +-Consider a situation where a custom `UserDetailsService` that returns an `Object` that implements `UserDetails` and your own `CustomUser` `Object`. The `CustomUser` of the currently authenticated user could be accessed using the following code: ++Consider a situation where a custom `UserDetailsService` returns an `Object` that implements `UserDetails` and your own `CustomUser` `Object`. The `CustomUser` of the currently authenticated user could be accessed by using the following code: + ++==== + [source,java] + ---- + @RequestMapping("/messages/inbox") +@@ -179,9 +196,11 @@ public ModelAndView findMessagesForUser() { + // .. find messages for this user and return them ... + } + ---- ++==== + +-As of Spring Security 3.2 we can resolve the argument more directly by adding an annotation. For example: ++As of Spring Security 3.2, we can resolve the argument more directly by adding an annotation: + ++==== + [source,java] + ---- + import org.springframework.security.core.annotation.AuthenticationPrincipal; +@@ -194,12 +213,13 @@ public ModelAndView findMessagesForUser(@AuthenticationPrincipal CustomUser cust + // .. find messages for this user and return them ... + } + ---- ++==== + +-Sometimes it may be necessary to transform the principal in some way. +-For example, if `CustomUser` needed to be final it could not be extended. +-In this situation the `UserDetailsService` might returns an `Object` that implements `UserDetails` and provides a method named `getCustomUser` to access `CustomUser`. +-For example, it might look like: ++Sometimes, you may need to transform the principal in some way. ++For example, if `CustomUser` needed to be final, it could not be extended. ++In this situation, the `UserDetailsService` might return an `Object` that implements `UserDetails` and provides a method named `getCustomUser` to access `CustomUser`: + ++==== + [source,java] + ---- + public class CustomUserUserDetails extends User { +@@ -209,9 +229,11 @@ public class CustomUserUserDetails extends User { + } + } + ---- ++==== + +-We could then access the `CustomUser` using a https://docs.spring.io/spring/docs/current/spring-framework-reference/html/expressions.html[SpEL expression] that uses `Authentication.getPrincipal()` as the root object: ++We could then access the `CustomUser` by using a https://docs.spring.io/spring/docs/current/spring-framework-reference/html/expressions.html[SpEL expression] that uses `Authentication.getPrincipal()` as the root object: + ++==== + [source,java] + ---- + import org.springframework.security.core.annotation.AuthenticationPrincipal; +@@ -224,10 +246,12 @@ public ModelAndView findMessagesForUser(@AuthenticationPrincipal(expression = "c + // .. find messages for this user and return them ... + } + ---- ++==== + +-We can also refer to Beans in our SpEL expressions. +-For example, the following could be used if we were using JPA to manage our Users and we wanted to modify and save a property on the current user. ++We can also refer to beans in our SpEL expressions. ++For example, we could use the following if we were using JPA to manage our users and if we wanted to modify and save a property on the current user: + ++==== + [source,java] + ---- + import org.springframework.security.core.annotation.AuthenticationPrincipal; +@@ -244,13 +268,15 @@ public ModelAndView updateName(@AuthenticationPrincipal(expression = "@jpaEntity + // ... + } + ---- ++==== + +-We can further remove our dependency on Spring Security by making `@AuthenticationPrincipal` a meta annotation on our own annotation. +-Below we demonstrate how we could do this on an annotation named `@CurrentUser`. ++We can further remove our dependency on Spring Security by making `@AuthenticationPrincipal` a meta-annotation on our own annotation. ++The next example demonstrates how we could do so on an annotation named `@CurrentUser`. + +-NOTE: It is important to realize that in order to remove the dependency on Spring Security, it is the consuming application that would create `@CurrentUser`. +-This step is not strictly required, but assists in isolating your dependency to Spring Security to a more central location. ++NOTE: To remove the dependency on Spring Security, it is the consuming application that would create `@CurrentUser`. ++This step is not strictly required but assists in isolating your dependency to Spring Security to a more central location. + ++==== + [source,java] + ---- + @Target({ElementType.PARAMETER, ElementType.TYPE}) +@@ -259,10 +285,12 @@ This step is not strictly required, but assists in isolating your dependency to + @AuthenticationPrincipal + public @interface CurrentUser {} + ---- ++==== + +-Now that `@CurrentUser` has been specified, we can use it to signal to resolve our `CustomUser` of the currently authenticated user. +-We have also isolated our dependency on Spring Security to a single file. ++We have isolated our dependency on Spring Security to a single file. ++Now that `@CurrentUser` has been specified, we can use it to signal to resolve our `CustomUser` of the currently authenticated user: + ++==== + [source,java] + ---- + @RequestMapping("/messages/inbox") +@@ -271,15 +299,16 @@ public ModelAndView findMessagesForUser(@CurrentUser CustomUser customUser) { + // .. find messages for this user and return them ... + } + ---- +- ++==== + + [[mvc-async]] + === 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. +-For example, the following method will automatically have its `Callable` invoked with the `SecurityContext` that was available when the `Callable` was created: ++With no additional configuration, Spring Security automatically sets up the `SecurityContext` to the `Thread` that invokes a `Callable` returned by your controllers. ++For example, the following method automatically has its `Callable` invoked with the `SecurityContext` that was available when the `Callable` was created: + ++==== + [source,java] + ---- + @RequestMapping(method=RequestMethod.POST) +@@ -293,26 +322,27 @@ return new Callable() { + }; + } + ---- ++==== + +-[NOTE] + .Associating SecurityContext to Callable's +-==== +-More technically speaking, Spring Security integrates with `WebAsyncManager`. +-The `SecurityContext` that is used to process the `Callable` is the `SecurityContext` that exists on the `SecurityContextHolder` at the time `startCallableProcessing` is invoked. +-==== ++NOTE: More technically speaking, Spring Security integrates with `WebAsyncManager`. ++The `SecurityContext` that is used to process the `Callable` is the `SecurityContext` that exists on the `SecurityContextHolder` when `startCallableProcessing` is invoked. + + There is no automatic integration with a `DeferredResult` that is returned by controllers. +-This is because `DeferredResult` is processed by the users and thus there is no way of automatically integrating with it. ++This is because `DeferredResult` is processed by the users and, thus, there is no way of automatically integrating with it. + However, you can still use <> to provide transparent integration with Spring Security. + + [[mvc-csrf]] + === Spring MVC and CSRF Integration + ++Spring Security integrates with Spring MVC to add CSRF protection. ++ + ==== Automatic Token Inclusion + +-Spring Security will automatically <> 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: ++Spring Security automatically <> within forms that use the https://docs.spring.io/spring-framework/docs/current/reference/html/web.html#mvc-view-jsp-formtaglib[Spring MVC form tag]. ++Consider the following JSP: + ++==== + [source,xml] + ---- + + + ---- ++==== + +-Will output HTML that is similar to the following: ++The preceding example output HTMLs that is similar to the following: + ++==== + [source,xml] + ---- + +@@ -350,16 +382,18 @@ Will output HTML that is similar to the following: + + + ---- ++==== + + [[mvc-csrf-resolver]] + ==== Resolving the CsrfToken + +-Spring Security provides `CsrfTokenArgumentResolver` which can automatically resolve the current `CsrfToken` for Spring MVC arguments. +-By using <> you will automatically have this added to your Spring MVC configuration. +-If you use XML based configuration, you must add this yourself. ++Spring Security provides `CsrfTokenArgumentResolver`, which can automatically resolve the current `CsrfToken` for Spring MVC arguments. ++By using <>, you automatically have this added to your Spring MVC configuration. ++If you use XML-based configuration, you must add this yourself. + +-Once `CsrfTokenArgumentResolver` is properly configured, you can expose the `CsrfToken` to your static HTML based application. ++Once `CsrfTokenArgumentResolver` is properly configured, you can expose the `CsrfToken` to your static HTML based application: + ++==== + [source,java] + ---- + @RestController +@@ -371,6 +405,7 @@ public class CsrfController { + } + } + ---- ++==== + + It is important to keep the `CsrfToken` a secret from other domains. +-This means if you are using https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS[Cross Origin Sharing (CORS)], you should **NOT** expose the `CsrfToken` to any external domains. ++This means that, if you use https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS[Cross Origin Sharing (CORS)], you should *NOT* expose the `CsrfToken` to any external domains. +diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/servlet-api.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/servlet-api.adoc +index 5e4077c3f9..c2a4f0a47e 100644 +--- a/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/servlet-api.adoc ++++ b/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/servlet-api.adoc +@@ -6,24 +6,26 @@ This section describes how Spring Security is integrated with the Servlet API. + [[servletapi-25]] + === Servlet 2.5+ Integration + ++This section describes how Spring Security integrates with the Servlet 2.5 specification. ++ + + [[servletapi-remote-user]] + ==== 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. ++https://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletRequest.html#getRemoteUser()[`HttpServletRequest.getRemoteUser()`] returns 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. +-Knowing if the user is authenticated or not can be useful for determining if certain UI elements should be shown or not (i.e. a log out link should only be displayed if the user is authenticated). ++Additionally, you can check this for null to determine whether a user has authenticated or is anonymous. ++Knowing whether the user is authenticated or not can be useful for determining if certain UI elements should be shown or not (for example, a logout link that should be displayed only if the user is authenticated). + + + [[servletapi-user-principal]] + ==== 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. ++https://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletRequest.html#getUserPrincipal()[`HttpServletRequest.getUserPrincipal()`] returns the result of `SecurityContextHolder.getContext().getAuthentication()`. ++This means that 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. + For example, you might have created a custom `UserDetailsService` that returns a custom `UserDetails` containing a first and last name for your user. + You could obtain this information with the following: + +- ++==== + [source,java] + ---- + Authentication auth = httpServletRequest.getUserPrincipal(); +@@ -33,43 +35,44 @@ MyCustomUserDetails userDetails = (MyCustomUserDetails) auth.getPrincipal(); + String firstName = userDetails.getFirstName(); + String lastName = userDetails.getLastName(); + ---- +- +-[NOTE] +-==== +-It should be noted that it is typically bad practice to perform so much logic throughout your application. +-Instead, one should centralize it to reduce any coupling of Spring Security and the Servlet API's. + ==== + ++NOTE: It is typically bad practice to perform logic throughout your application. ++Instead, you should centralize it to reduce any coupling of Spring Security and the Servlet API. ++ + [[servletapi-user-in-role]] + ==== 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. ++https://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletRequest.html#isUserInRole(java.lang.String)[`HttpServletRequest.isUserInRole(String)`] determines if `SecurityContextHolder.getContext().getAuthentication().getAuthorities()` contains a `GrantedAuthority` with the role passed into `isUserInRole(String)`. ++Typically, users should not pass the `ROLE_` prefix to 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: + ++==== + [source,java] + ---- + boolean isAdmin = httpServletRequest.isUserInRole("ADMIN"); + ---- ++==== + + 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 +-The following section describes the Servlet 3 methods that Spring Security integrates with. ++The following section describes the Servlet 3 methods with which Spring Security integrates. + + + [[servletapi-authenticate]] + ==== 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). ++You can use the https://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletRequest.html#authenticate%28javax.servlet.http.HttpServletResponse%29[`HttpServletRequest.authenticate(HttpServletRequest,HttpServletResponse)`] method to ensure that a user is authenticated. ++If they are not authenticated, the configured `AuthenticationEntryPoint` is used to request the user to authenticate (redirect to the login page). + + + [[servletapi-login]] + ==== 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": ++You can use 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 to authenticate the user with the current `AuthenticationManager`. ++For example, the following would attempt to authenticate with a username of `user` and a password of `password`: + ++==== + [source,java] + ---- + try { +@@ -78,27 +81,26 @@ httpServletRequest.login("user","password"); + // fail to authenticate + } + ---- +- +-[NOTE] +-==== +-It is not necessary to catch the ServletException if you want Spring Security to process the failed authentication attempt. + ==== + ++NOTE: You need not catch the `ServletException` if you want Spring Security to process the failed authentication attempt. ++ + [[servletapi-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. ++You can use the https://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletRequest.html#logout%28%29[`HttpServletRequest.logout()`] method to log out the current user. + +-Typically this means that the SecurityContextHolder will be cleared out, the HttpSession will be invalidated, any "Remember Me" authentication will be cleaned up, etc. +-However, the configured LogoutHandler implementations will vary depending on your Spring Security configuration. +-It is important to note that after HttpServletRequest.logout() has been invoked, you are still in charge of writing a response out. +-Typically this would involve a redirect to the welcome page. ++Typically, this means that the `SecurityContextHolder` is cleared out, the `HttpSession` is invalidated, any "`Remember Me`" authentication is cleaned up, and so on. ++However, the configured `LogoutHandler` implementations vary, depending on your Spring Security configuration. ++Note that, after `HttpServletRequest.logout()` has been invoked, you are still in charge of writing out a response. ++Typically, this would involve a redirect to the welcome page. + + [[servletapi-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: ++The https://docs.oracle.com/javaee/6/api/javax/servlet/AsyncContext.html#start%28java.lang.Runnable%29[`AsyncContext.start(Runnable)`] method ensures your credentials are propagated to the new `Thread`. ++By using Spring Security's concurrency support, Spring Security overrides `AsyncContext.start(Runnable)` to ensure that the current `SecurityContext` is used when processing the Runnable. ++The following example outputs the current user's Authentication: + ++==== + [source,java] + ---- + final AsyncContext async = httpServletRequest.startAsync(); +@@ -116,13 +118,15 @@ async.start(new Runnable() { + } + }); + ---- ++==== + + [[servletapi-async]] + ==== 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: ++If you use Java-based configuration, you are ready to go. ++If you use XML configuration, a few updates are necessary. ++The first step is to ensure that you have updated your `web.xml` file to use at least the 3.0 schema: + ++==== + [source,xml] + ---- + + + + ---- ++==== + +-Next you need to ensure that your springSecurityFilterChain is setup for processing asynchronous requests. ++Next, you need to ensure that your `springSecurityFilterChain` is set up for processing asynchronous requests: + ++==== + [source,xml] + ---- + +@@ -151,16 +157,17 @@ Next you need to ensure that your springSecurityFilterChain is setup for process + ASYNC +
+ ---- ++==== + +-That's it! +-Now Spring Security will ensure that your SecurityContext is propagated on asynchronous requests too. ++Now Spring Security ensures that your `SecurityContext` is propagated on asynchronous requests, too. + +-So how does it work? If you are not really interested, feel free to skip the remainder of this section, otherwise read on. +-Most of this is built into the Servlet specification, but there is a little bit of tweaking that Spring Security does to ensure things work with asynchronous requests properly. +-Prior to Spring Security 3.2, the SecurityContext from the SecurityContextHolder was automatically saved as soon as the HttpServletResponse was committed. +-This can cause issues in an Async environment. +-For example, consider the following: ++So how does it work? If you are not really interested, feel free to skip the remainder of this section ++Most of this is built into the Servlet specification, but there is a little bit of tweaking that Spring Security does to ensure things work properly with asynchronous requests. ++Prior to Spring Security 3.2, the `SecurityContext` from the `SecurityContextHolder` was automatically saved as soon as the `HttpServletResponse` was committed. ++This can cause issues in an asynchronous environment. ++Consider the following example: + ++==== + [source,java] + ---- + httpServletRequest.startAsync(); +@@ -179,12 +186,13 @@ new Thread("AsyncThread") { + } + }.start(); + ---- ++==== + +-The issue is that this Thread is not known to Spring Security, so the SecurityContext is not propagated to it. +-This means when we commit the HttpServletResponse there is no SecurityContext. +-When Spring Security automatically saved the SecurityContext on committing the HttpServletResponse it would lose our logged in user. ++The issue is that this `Thread` is not known to Spring Security, so the `SecurityContext` is not propagated to it. ++This means that, when we commit the `HttpServletResponse`, there is no `SecurityContext`. ++When Spring Security automatically saved the `SecurityContext` on committing the `HttpServletResponse`, it would lose a logged in user. + +-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. ++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 +@@ -192,4 +200,4 @@ The following section describes the Servlet 3.1 methods that Spring Security int + + [[servletapi-change-session-id]] + ==== 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 <> attacks in Servlet 3.1 and higher. ++https://docs.oracle.com/javaee/7/api/javax/servlet/http/HttpServletRequest.html#changeSessionId()[`HttpServletRequest.changeSessionId()`] is the default method for protecting against <> attacks in Servlet 3.1 and higher. +diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/websocket.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/websocket.adoc +index ffcf46b5a4..b785fe5f8c 100644 +--- a/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/websocket.adoc ++++ b/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/websocket.adoc +@@ -6,18 +6,18 @@ This section describes how to use Spring Security's WebSocket support. + + .Direct JSR-356 Support + **** +-Spring Security does not provide direct JSR-356 support because doing so would provide little value. +-This is because the format is unknown, so there is https://docs.spring.io/spring/docs/current/spring-framework-reference/html/websocket.html#websocket-intro-sub-protocol[little Spring can do to secure an unknown format]. +-Additionally, JSR-356 does not provide a way to intercept messages, so security would be rather invasive. ++Spring Security does not provide direct JSR-356 support, because doing so would provide little value. ++This is because the format is unknown, and there is https://docs.spring.io/spring/docs/current/spring-framework-reference/html/websocket.html#websocket-intro-sub-protocol[little Spring can do to secure an unknown format]. ++Additionally, JSR-356 does not provide a way to intercept messages, so security would be invasive. + **** + + [[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`. +-For example: ++To configure authorization by using Java Configuration, extend the `AbstractSecurityWebSocketMessageBrokerConfigurer` and configure the `MessageSecurityMetadataSourceRegistry`: + ++==== + [source,java] + ---- + @Configuration +@@ -30,16 +30,15 @@ public class WebSocketSecurityConfig + } + } + ---- +- +-This will ensure that: +- +-<1> Any inbound CONNECT message requires a valid CSRF token to enforce <> +-<2> The SecurityContextHolder is populated with the user within the simpUser header attribute for any inbound request. +-<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 <> ++<1> Any inbound CONNECT message requires a valid CSRF token to enforce the <>. ++<2> The `SecurityContextHolder` is populated with the user within the `simpUser` header attribute for any inbound request. ++<3> Our messages require the proper authorization. Specifically, any inbound message that starts with `/user/` will requires `ROLE_USER`. You can find additional details on authorization in <> ++==== + + Spring Security also provides <> support for securing WebSockets. + A comparable XML based configuration looks like the following: + ++==== + [source,xml] + ---- + +@@ -47,29 +46,27 @@ A comparable XML based configuration looks like the following: + + + ---- +- +-This will ensure that: +- +-<1> Any inbound CONNECT message requires a valid CSRF token to enforce <> +-<2> The SecurityContextHolder is populated with the user within the simpUser header attribute for any inbound request. +-<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 <> ++<1> Any inbound CONNECT message requires a valid CSRF token to enforce the <>. ++<2> The `SecurityContextHolder` is populated with the user within the `simpUser` header attribute for any inbound request. ++<3> Our messages require the proper authorization. Specifically, any inbound message that starts with `/user/` require `ROLE_USER`. You can find additional details on authorization in <>. ++==== + + [[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. +-If you are using Spring Security, the `Principal` on the `HttpServletRequest` is overridden automatically. ++This means that the `Principal` on the `HttpServletRequest` is handed off to WebSockets. ++If you use Spring Security, the `Principal` on the `HttpServletRequest` is overridden automatically. + +-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. ++More concretely, to ensure a user has authenticated to your WebSocket application, all you need to do is ensure that you set up Spring Security to authenticate your HTTP based web application. + + [[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`. +-For example: ++To configure authorization by using Java configuration, extend the `AbstractSecurityWebSocketMessageBrokerConfigurer` and configure the `MessageSecurityMetadataSourceRegistry`: + ++==== + [source,java] + ---- + @Configuration +@@ -88,19 +85,18 @@ public class WebSocketSecurityConfig extends AbstractSecurityWebSocketMessageBro + } + } + ---- +- +-This will ensure that: +- +-<1> Any message without a destination (i.e. anything other than Message type of MESSAGE or SUBSCRIBE) will require the user to be authenticated +-<2> Anyone can subscribe to /user/queue/errors +-<3> Any message that has a destination starting with "/app/" will be require the user to have the role ROLE_USER +-<4> Any message that starts with "/user/" or "/topic/friends/" that is of type SUBSCRIBE will require ROLE_USER +-<5> Any other message of type MESSAGE or SUBSCRIBE is rejected. Due to 6 we do not need this step, but it illustrates how one can match on specific message types. +-<6> Any other Message is rejected. This is a good idea to ensure that you do not miss any messages. ++<1> Any message without a destination (anything other than message type of `MESSAGE` or `SUBSCRIBE`) requires the user to be authenticated. ++<2> Anyone can subscribe to `/user/queue/errors`. ++<3> Any message that has a destination starting with `/app/` requires the user to have a role of `ROLE_USER`. ++<4> Any message that starts with `/user/` or `/topic/friends/` that is of type `SUBSCRIBE` requires `ROLE_USER`. ++<5> Any other message of type `MESSAGE` or `SUBSCRIBE` is rejected. Due to 6, we do not need this step, but it illustrates how you can match on specific message types. ++<6> Any other message is rejected. This is a good idea to ensure that you do not miss any messages. ++==== + + Spring Security also provides <> support for securing WebSockets. + A comparable XML based configuration looks like the following: + ++==== + [source,xml] + ---- + +@@ -123,115 +119,117 @@ A comparable XML based configuration looks like the following: + + + ---- +- +-This will ensure that: +- +-<1> Any message of type CONNECT, UNSUBSCRIBE, or DISCONNECT will require the user to be authenticated ++<1> Any message of type `CONNECT`, `UNSUBSCRIBE`, or `DISCONNECT` requires the user to be authenticated. + <2> Anyone can subscribe to /user/queue/errors + <3> Any message that has a destination starting with "/app/" will be require the user to have the role ROLE_USER + <4> Any message that starts with "/user/" or "/topic/friends/" that is of type SUBSCRIBE will require ROLE_USER + <5> Any other message of type MESSAGE or SUBSCRIBE is rejected. Due to 6 we do not need this step, but it illustrates how one can match on specific message types. + <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 + +-In order to properly secure your application it is important to understand Spring's WebSocket support. ++To properly secure your application, you need to understand Spring's WebSocket support. + + [[websocket-authorization-notes-messagetypes]] + ===== 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. ++You need to understand the distinction between `SUBSCRIBE` and `MESSAGE` types of messages and how they work within Spring. + +-Consider a chat application. ++Consider a chat application: + +-* The system can send notifications MESSAGE to all users through a destination of "/topic/system/notifications" +-* Clients can receive notifications by SUBSCRIBE to the "/topic/system/notifications". ++* The system can send a notification `MESSAGE` to all users through a destination of `/topic/system/notifications`. ++* Clients can receive notifications by `SUBSCRIBE` to the `/topic/system/notifications`. + +-While we want clients to be able to SUBSCRIBE to "/topic/system/notifications", we do not want to enable them to send a MESSAGE to that destination. +-If we allowed sending a MESSAGE to "/topic/system/notifications", then clients could send a message directly to that endpoint and impersonate the system. ++While we want clients to be able to `SUBSCRIBE` to `/topic/system/notifications`, we do not want to enable them to send a `MESSAGE` to that destination. ++If we allowed sending a `MESSAGE` to `/topic/system/notifications`, clients could send a message directly to that endpoint and impersonate the system. + +-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/"). ++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] (`/topic/` or `/queue/`). + + [[websocket-authorization-notes-destinations]] + ===== WebSocket Authorization on Destinations + +-It is also is important to understand how destinations are transformed. ++You should also understand how destinations are transformed. + +-Consider a chat application. ++Consider a chat application: + +-* Users can send messages to a specific user by sending a message to the destination of "/app/chat". +-* The application sees the message, ensures that the "from" attribute is specified as the current user (we cannot trust the client). +-* The application then sends the message to the recipient using `SimpMessageSendingOperations.convertAndSendToUser("toUser", "/queue/messages", message)`. +-* The message gets turned into the destination of "/queue/user/messages-" ++* Users can send messages to a specific user by sending a message to the `/app/chat` destination. ++* The application sees the message, ensures that the `from` attribute is specified as the current user (we cannot trust the client). ++* The application then sends the message to the recipient by using `SimpMessageSendingOperations.convertAndSendToUser("toUser", "/queue/messages", message)`. ++* The message gets turned into the destination of `/queue/user/messages-`. + +-With the application above, we want to allow our client to listen to "/user/queue" which is transformed into "/queue/user/messages-". +-However, we do not want the client to be able to listen to "/queue/*" because that would allow the client to see messages for every user. ++With this chat application, we want to let our client to listen `/user/queue`, which is transformed into `/queue/user/messages-`. ++However, we do not want the client to be able to listen to `/queue/*`, because that would let the client see messages for every user. + +-In general, it is common for applications to deny any SUBSCRIBE sent to a message 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/"). +-Of course we may provide exceptions to account for things like ++In general, it is common for applications to deny any `SUBSCRIBE` sent to a message that starts with the https://docs.spring.io/spring/docs/current/spring-framework-reference/html/websocket.html#websocket-stomp[broker prefix] (`/topic/` or `/queue/`). ++We may provide exceptions to account for things like ++//FIXME: Like what? + + [[websocket-authorization-notes-outbound]] + ==== 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`. ++The Spring Framework reference documentation 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. ++Note that Spring Security secures only the `clientInboundChannel`. + Spring Security does not attempt to secure the `clientOutboundChannel`. + + The most important reason for this is performance. +-For every message that goes in, there are typically many more that go out. ++For every message that goes in, typically many more go out. + Instead of securing the outbound messages, we encourage securing the subscription to the endpoints. + + [[websocket-sameorigin]] + === 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. ++Note 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? + + Consider the following scenario. +-A user visits bank.com and authenticates to their account. +-The same user opens another tab in their browser and visits evil.com. +-The Same Origin Policy ensures that evil.com cannot read or write data to bank.com. ++A user visits `bank.com` and authenticates to their account. ++The same user opens another tab in their browser and visits `evil.com`. ++The Same Origin Policy ensures that `evil.com` cannot read data from or write data to `bank.com`. + +-With WebSockets the Same Origin Policy does not apply. +-In fact, unless bank.com explicitly forbids it, evil.com can read and write data on behalf of the user. +-This means that anything the user can do over the webSocket (i.e. transfer money), evil.com can do on that users behalf. ++With WebSockets, the Same Origin Policy does not apply. ++In fact, unless `bank.com` explicitly forbids it, `evil.com` can read and write data on behalf of the user. ++This means that anything the user can do over the webSocket (such as transferring money), `evil.com` can do on that user's behalf. + +-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. ++Since SockJS tries to emulate WebSockets, it also bypasses the Same Origin Policy. ++This means that developers need to explicitly protect their applications from external domains when they use SockJS. + + [[websocket-sameorigin-spring]] + ==== 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_%2528computing%2529[defence in depth]. ++Spring Security adds an additional layer of protection to provide https://en.wikipedia.org/wiki/Defence_in_depth_(non-military)#Information_security[defense in depth]. + + [[websocket-sameorigin-csrf]] + ==== Adding CSRF to Stomp Headers + +-By default Spring Security requires the <> in any CONNECT message type. ++By default, Spring Security requires the <> in any `CONNECT` message type. + This ensures that only a site that has access to the CSRF token can connect. +-Since only the *Same Origin* can access the CSRF token, external domains are not allowed to make a connection. ++Since only the *same origin* can access the CSRF token, external domains are not allowed to make a connection. + + Typically we need to include the CSRF token in an HTTP header or an HTTP parameter. + However, SockJS does not allow for these options. +-Instead, we must include the token in the Stomp headers ++Instead, we must include the token in the Stomp headers. + +-Applications can <> by accessing the request attribute named _csrf. +-For example, the following will allow accessing the `CsrfToken` in a JSP: ++Applications can <> by accessing the request attribute named `_csrf`. ++For example, the following allows accessing the `CsrfToken` in a JSP: + ++==== + [source,javascript] + ---- + var headerName = "${_csrf.headerName}"; + var token = "${_csrf.token}"; + ---- ++==== + +-If you are using static HTML, you can expose the `CsrfToken` on a REST endpoint. +-For example, the following would expose the `CsrfToken` on the URL /csrf ++If you use static HTML, you can expose the `CsrfToken` on a REST endpoint. ++For example, the following would expose the `CsrfToken` on the `/csrf` URL: + ++==== + [source,java] + ---- + @RestController +@@ -243,29 +241,30 @@ public class CsrfController { + } + } + ---- ++==== + +-The JavaScript can make a REST call to the endpoint and use the response to populate the headerName and the token. ++The JavaScript can make a REST call to the endpoint and use the response to populate the `headerName` and the token. + +-We can now include the token in our Stomp client. +-For example: ++We can now include the token in our Stomp client: + ++==== + [source,javascript] + ---- +-... + var headers = {}; + headers[headerName] = token; + stompClient.connect(headers, function(frame) { + ... +- +-} ++}) + ---- ++==== + + [[websocket-sameorigin-disable]] + ==== 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: ++If you want to let other domains access your site, you can disable Spring Security's protection. ++For example, in Java configuration you can use the following: + ++==== + [source,java] + ---- + @Configuration +@@ -279,24 +278,25 @@ public class WebSocketSecurityConfig extends AbstractSecurityWebSocketMessageBro + } + } + ---- +- ++==== + + [[websocket-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. ++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 may use an https://github.com/sockjs/sockjs-client/tree/v0.3.4[transport that leverages an iframe]. +-By default Spring Security will <> the site from being framed to prevent Clickjacking attacks. +-To allow SockJS frame based transports to work, we need to configure Spring Security to allow the same origin to frame the content. ++SockJS may use a https://github.com/sockjs/sockjs-client/tree/v0.3.4[transport that leverages an iframe]. ++By default, Spring Security <> the site from being framed to prevent clickjacking attacks. ++To allow SockJS frame-based transports to work, we need to configure Spring Security to let the same origin frame the content. + +-You can customize X-Frame-Options with the <> element. +-For example, the following will instruct Spring Security to use "X-Frame-Options: SAMEORIGIN" which allows iframes within the same domain: ++You can customize `X-Frame-Options` with the <> element. ++For example, the following instructs Spring Security to use `X-Frame-Options: SAMEORIGIN`, which allows iframes within the same domain: + ++==== + [source,xml] + ---- + +@@ -308,9 +308,11 @@ For example, the following will instruct Spring Security to use "X-Frame-Options + + + ---- ++==== + +-Similarly, you can customize frame options to use the same origin within Java Configuration using the following: ++Similarly, you can customize frame options to use the same origin within Java Configuration by using the following: + ++==== + [source,java] + ---- + @EnableWebSecurity +@@ -329,24 +331,26 @@ public class WebSecurityConfig extends + } + } + ---- ++==== + + [[websocket-sockjs-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. ++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. + However, SockJS does not allow for these options. + Instead, we must include the token in the Stomp headers as described in <>. + +-It also means we need to relax our CSRF protection with the web layer. ++It also means that we need to relax our CSRF protection with the web layer. + Specifically, we want to disable CSRF protection for our connect URLs. + We do NOT want to disable CSRF protection for every URL. +-Otherwise our site will be vulnerable to CSRF attacks. ++Otherwise, our site is vulnerable to CSRF attacks. + +-We can easily achieve this by providing a CSRF RequestMatcher. +-Our Java Configuration makes this extremely easy. +-For example, if our stomp endpoint is "/chat" we can disable CSRF protection for only URLs that start with "/chat/" using the following configuration: ++We can easily achieve this by providing a CSRF `RequestMatcher`. ++Our Java configuration makes this easy. ++For example, if our stomp endpoint is `/chat`, we can disable CSRF protection only for URLs that start with `/chat/` by using the following configuration: + ++==== + [source,java] + ---- + @Configuration +@@ -371,11 +375,14 @@ public class WebSecurityConfig + ... + ) + ... ++ } ++ } + ---- ++==== + +-If we are using XML based configuration, we can use the <>. +-For example: ++If we use XML-based configuration, we can use the <>: + ++==== + [source,xml] + ---- + +@@ -400,3 +407,4 @@ For example: + + + ---- ++==== +diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/java-configuration/index.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/java-configuration/index.adoc +index 3ba5432ddc..56cff5437a 100644 +--- a/docs/manual/src/docs/asciidoc/_includes/servlet/java-configuration/index.adoc ++++ b/docs/manual/src/docs/asciidoc/_includes/servlet/java-configuration/index.adoc +@@ -1,21 +1,21 @@ +- + [[jc]] + = Java Configuration + +-General support for https://docs.spring.io/spring/docs/3.1.x/spring-framework-reference/html/beans.html#beans-java[Java Configuration] was added to Spring Framework in Spring 3.1. +-Since Spring Security 3.2 there has been Spring Security Java Configuration support which enables users to easily configure Spring Security without the use of any XML. ++General support for https://docs.spring.io/spring/docs/3.1.x/spring-framework-reference/html/beans.html#beans-java[Java configuration] was added to Spring Framework in Spring 3.1. ++Spring Security 3.2 introduced Java configuration to let users configure Spring Security without the use of any XML. + +-If you are familiar with the <> then you should find quite a few similarities between it and the Security Java Configuration support. ++If you are familiar with the <>, you should find quite a few similarities between it and Spring Security Java configuration. + + NOTE: Spring Security provides https://github.com/spring-projects/spring-security-samples/tree/main/servlet/java-configuration[lots of sample applications] which demonstrate the use of Spring Security Java Configuration. + + == Hello Web Security Java Configuration + + The first step is to create our Spring Security Java Configuration. +-The configuration creates a Servlet Filter known as the `springSecurityFilterChain` which is responsible for all the security (protecting the application URLs, validating submitted username and passwords, redirecting to the log in form, etc) within your application. +-You can find the most basic example of a Spring Security Java Configuration below: ++The configuration creates a Servlet Filter known as the `springSecurityFilterChain`, which is responsible for all the security (protecting the application URLs, validating submitted username and passwords, redirecting to the log in form, and so on) within your application. ++The following example shows the most basic example of a Spring Security Java Configuration: + + [[jc-hello-wsca]] ++==== + [source,java] + ---- + import org.springframework.beans.factory.annotation.Autowired; +@@ -35,44 +35,44 @@ public class WebSecurityConfig { + } + } + ---- ++==== + +-There really isn't much to this configuration, but it does a lot. +-You can find a summary of the features below: ++This configuration is not complex or extensive, but it does a lot: + + * Require authentication to every URL in your application + * Generate a login form for you +-* Allow the user with the *Username* _user_ and the *Password* _password_ to authenticate with form based authentication +-* Allow the user to logout ++* Let the user with a *Username* of `user` and a *Password* of `password` authenticate with form based authentication ++* Let the user logout + * https://en.wikipedia.org/wiki/Cross-site_request_forgery[CSRF attack] prevention + * https://en.wikipedia.org/wiki/Session_fixation[Session Fixation] protection +-* Security Header integration ++* Security Header integration: + ** https://en.wikipedia.org/wiki/HTTP_Strict_Transport_Security[HTTP Strict Transport Security] for secure requests + ** https://msdn.microsoft.com/en-us/library/ie/gg622941(v=vs.85).aspx[X-Content-Type-Options] integration +-** Cache Control (can be overridden later by your application to allow caching of your static resources) ++** Cache Control (which you can override later in your application to allow caching of your static resources) + ** https://msdn.microsoft.com/en-us/library/dd565647(v=vs.85).aspx[X-XSS-Protection] integration + ** X-Frame-Options integration to help prevent https://en.wikipedia.org/wiki/Clickjacking[Clickjacking] +-* Integrate with the following Servlet API methods +-** https://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletRequest.html#getRemoteUser()[HttpServletRequest#getRemoteUser()] +-** https://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletRequest.html#getUserPrincipal()[HttpServletRequest#getUserPrincipal()] +-** https://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletRequest.html#isUserInRole(java.lang.String)[HttpServletRequest#isUserInRole(java.lang.String)] +-** https://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletRequest.html#login(java.lang.String,%20java.lang.String)[HttpServletRequest#login(java.lang.String, java.lang.String)] +-** https://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletRequest.html#logout()[HttpServletRequest#logout()] ++* Integration with the following Servlet API methods: ++** https://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletRequest.html#getRemoteUser()[`HttpServletRequest#getRemoteUser()`] ++** https://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletRequest.html#getUserPrincipal()[`HttpServletRequest#getUserPrincipal()`] ++** https://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletRequest.html#isUserInRole(java.lang.String)[`HttpServletRequest#isUserInRole(java.lang.String)`] ++** https://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletRequest.html#login(java.lang.String,%20java.lang.String)[`HttpServletRequest#login(java.lang.String, java.lang.String)`] ++** https://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletRequest.html#logout()[`HttpServletRequest#logout()`] + + === AbstractSecurityWebApplicationInitializer + +-The next step is to register the `springSecurityFilterChain` with the war. +-This can be done in Java Configuration with https://docs.spring.io/spring/docs/3.2.x/spring-framework-reference/html/mvc.html#mvc-container-config[Spring's WebApplicationInitializer support] in a Servlet 3.0+ environment. +-Not suprisingly, Spring Security provides a base class `AbstractSecurityWebApplicationInitializer` that will ensure the `springSecurityFilterChain` gets registered for you. ++The next step is to register the `springSecurityFilterChain` with the WAR file. ++You can do so in Java configuration with https://docs.spring.io/spring/docs/3.2.x/spring-framework-reference/html/mvc.html#mvc-container-config[Spring's `WebApplicationInitializer` support] in a Servlet 3.0+ environment. ++Not surprisingly, Spring Security provides a base class (`AbstractSecurityWebApplicationInitializer`) to ensure that the `springSecurityFilterChain` gets registered for you. + The way in which we use `AbstractSecurityWebApplicationInitializer` differs depending on if we are already using Spring or if Spring Security is the only Spring component in our application. + +-* <> - Use these instructions if you are not using Spring already ++* <> - Use these instructions if you are not already using Spring + * <> - Use these instructions if you are already using Spring + + === AbstractSecurityWebApplicationInitializer without Existing Spring + +-If you are not using Spring or Spring MVC, you will need to pass in the `WebSecurityConfig` into the superclass to ensure the configuration is picked up. +-You can find an example below: ++If you are not using Spring or Spring MVC, you need to pass the `WebSecurityConfig` to the superclass to ensure the configuration is picked up: + ++==== + [source,java] + ---- + import org.springframework.security.web.context.*; +@@ -85,19 +85,21 @@ public class SecurityWebApplicationInitializer + } + } + ---- ++==== + +-The `SecurityWebApplicationInitializer` will do the following things: ++The `SecurityWebApplicationInitializer`: + +-* Automatically register the springSecurityFilterChain Filter for every URL in your application +-* Add a ContextLoaderListener that loads the <>. ++* Automatically registers the `springSecurityFilterChain` Filter for every URL in your application. ++* Add a `ContextLoaderListener` that loads the <>. + + === AbstractSecurityWebApplicationInitializer with Spring MVC + +-If we were using Spring elsewhere in our application we probably already had a `WebApplicationInitializer` that is loading our Spring Configuration. +-If we use the previous configuration we would get an error. ++If we use Spring elsewhere in our application, we probably already have a `WebApplicationInitializer` that is loading our Spring Configuration. ++If we use the previous configuration, we would get an error. + Instead, we should register Spring Security with the existing `ApplicationContext`. +-For example, if we were using Spring MVC our `SecurityWebApplicationInitializer` would look something like the following: ++For example, if we use Spring MVC, our `SecurityWebApplicationInitializer` could look something like the following: + ++==== + [source,java] + ---- + import org.springframework.security.web.context.*; +@@ -107,12 +109,14 @@ public class SecurityWebApplicationInitializer + + } + ---- ++==== + +-This would simply only register the springSecurityFilterChain Filter for every URL in your application. +-After that we would ensure that `WebSecurityConfig` was loaded in our existing ApplicationInitializer. +-For example, if we were using Spring MVC it would be added in the `getRootConfigClasses()` ++This onlys register the `springSecurityFilterChain` for every URL in your application. ++After that, we need to ensure that `WebSecurityConfig` was loaded in our existing `ApplicationInitializer`. ++For example, if we use Spring MVC it is added in the `getRootConfigClasses()`: + + [[message-web-application-inititializer-java]] ++==== + [source,java] + ---- + public class MvcWebApplicationInitializer extends +@@ -126,16 +130,18 @@ public class MvcWebApplicationInitializer extends + // ... other overrides ... + } + ---- ++==== + + [[jc-httpsecurity]] + == HttpSecurity + +-Thus far our <> only contains information about how to authenticate our users. ++Thus far, our <> contains only information about how to authenticate our users. + How does Spring Security know that we want to require all users to be authenticated? +-How does Spring Security know we want to support form based authentication? +-Actually, there is a configuration class that is being invoked behind the scenes called `WebSecurityConfigurerAdapter`. ++How does Spring Security know we want to support form-based authentication? ++Actually, there is a configuration class (called `WebSecurityConfigurerAdapter`) that is being invoked behind the scenes. + It has a method called `configure` with the following default implementation: + ++==== + [source,java] + ---- + protected void configure(HttpSecurity http) throws Exception { +@@ -147,15 +153,17 @@ protected void configure(HttpSecurity http) throws Exception { + .httpBasic(withDefaults()); + } + ---- ++==== + +-The default configuration above: ++The default configuration (shown in the preceding example): + + * Ensures that any request to our application requires the user to be authenticated +-* Allows users to authenticate with form based login +-* Allows users to authenticate with HTTP Basic authentication ++* Lets users authenticate with form based login ++* Lets users authenticate with HTTP Basic authentication + +-You will notice that this configuration is quite similar the XML Namespace configuration: ++Note that this configuration is parallels the XML Namespace configuration: + ++==== + [source,xml] + ---- + +@@ -164,13 +172,15 @@ You will notice that this configuration is quite similar the XML Namespace confi + + + ---- ++==== + +-== Multiple HttpSecurity ++== Multiple HttpSecurity Instances + +-We can configure multiple HttpSecurity instances just as we can have multiple `` blocks. ++We can configure multiple `HttpSecurity` instances just as we can have multiple `` blocks in XML. + The key is to extend the `WebSecurityConfigurerAdapter` multiple times. +-For example, the following is an example of having a different configuration for URL's that start with `/api/`. ++The following example has a different configuration for URL's that start with `/api/`. + ++==== + [source,java] + ---- + @EnableWebSecurity +@@ -213,19 +223,20 @@ public class MultiHttpSecurityConfig { + } + ---- + +-<1> Configure Authentication as normal ++<1> Configure Authentication as usual. + <2> Create an instance of `WebSecurityConfigurerAdapter` that contains `@Order` to specify which `WebSecurityConfigurerAdapter` should be considered first. +-<3> The `http.antMatcher` states that this `HttpSecurity` will only be applicable to URLs that start with `/api/` ++<3> The `http.antMatcher` states that this `HttpSecurity` is applicable only to URLs that start with `/api/`. + <4> Create another instance of `WebSecurityConfigurerAdapter`. +-If the URL does not start with `/api/` this configuration will be used. +-This configuration is considered after `ApiWebSecurityConfigurationAdapter` since it has an `@Order` value after `1` (no `@Order` defaults to last). ++If the URL does not start with `/api/`, this configuration is used. ++This configuration is considered after `ApiWebSecurityConfigurationAdapter`, since it has an `@Order` value after `1` (no `@Order` defaults to last). ++==== + + [[jc-custom-dsls]] + == Custom DSLs + +-You can provide your own custom DSLs in Spring Security. +-For example, you might have something that looks like this: ++You can provide your own custom DSLs in Spring Security: + ++==== + [source,java] + ---- + public class MyCustomDsl extends AbstractHttpConfigurer { +@@ -258,11 +269,13 @@ public class MyCustomDsl extends AbstractHttpConfigurer +@@ -43,14 +46,17 @@ You will notice that this configuration is quite similar the XML Namespace confi + + + ---- ++==== + +-== Multiple HttpSecurity ++== Multiple HttpSecurity Instances + +-We can configure multiple HttpSecurity instances just as we can have multiple `` blocks. ++We can configure multiple HttpSecurity instances, just as we can have multiple `` blocks. + The key is to extend the `WebSecurityConfigurerAdapter` multiple times. +-For example, the following is an example of having a different configuration for URL's that start with `/api/`. ++The following example has a different configuration for URL's that start with `/api/`: + +-[source,kotlin] ++// The source is Kotlin, but we specify Java to get code formatting. At present, Asciidoctor doesnt' have a Kotlin formatter. ++==== ++[source,java] + ---- + @EnableWebSecurity + class MultiHttpSecurityConfig { +@@ -91,9 +97,10 @@ class MultiHttpSecurityConfig { + } + ---- + +-<1> Configure Authentication as normal ++<1> Configure Authentication as usual. + <2> Create an instance of `WebSecurityConfigurerAdapter` that contains `@Order` to specify which `WebSecurityConfigurerAdapter` should be considered first. +-<3> The `http.antMatcher` states that this `HttpSecurity` will only be applicable to URLs that start with `/api/` ++<3> The `http.antMatcher` states that this `HttpSecurity` is applicable only to URLs that start with `/api/` + <4> Create another instance of `WebSecurityConfigurerAdapter`. +-If the URL does not start with `/api/` this configuration will be used. +-This configuration is considered after `ApiWebSecurityConfigurationAdapter` since it has an `@Order` value after `1` (no `@Order` defaults to last). ++If the URL does not start with `/api/`, this configuration is used. ++This configuration is considered after `ApiWebSecurityConfigurationAdapter`, since it has an `@Order` value after `1` (no `@Order` defaults to last). ++==== +diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/namespace/index.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/namespace/index.adoc +index 58c7687cc9..fc427d14cc 100644 +--- a/docs/manual/src/docs/asciidoc/_includes/servlet/namespace/index.adoc ++++ b/docs/manual/src/docs/asciidoc/_includes/servlet/namespace/index.adoc +@@ -2,30 +2,30 @@ + [[ns-config]] + = Security Namespace Configuration + +- +-== Introduction + Namespace configuration has been available since version 2.0 of the Spring Framework. +-It allows you to supplement the traditional Spring beans application context syntax with elements from additional XML schema. ++It lets you supplement the traditional Spring beans application context syntax with elements from additional XML schema. + You can find more information in the Spring https://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/[Reference Documentation]. +-A namespace element can be used simply to allow a more concise way of configuring an individual bean or, more powerfully, to define an alternative configuration syntax which more closely matches the problem domain and hides the underlying complexity from the user. +-A simple element may conceal the fact that multiple beans and processing steps are being added to the application context. +-For example, adding the following element from the security namespace to an application context will start up an embedded LDAP server for testing use within the application: ++You can use a namespace element to more concisely configure an individual bean or, more powerfully, to define an alternative configuration syntax that more closely matches the problem domain and hides the underlying complexity from the user. ++A simple element can conceal the fact that multiple beans and processing steps are being added to the application context. ++For example, adding the following element from the `security` namespace to an application context starts up an embedded LDAP server for testing use within the application: + ++==== + [source,xml] + ---- + + ---- ++==== + + This is much simpler than wiring up the equivalent Apache Directory Server beans. +-The most common alternative configuration requirements are supported by attributes on the `ldap-server` element and the user is isolated from worrying about which beans they need to create and what the bean property names are. +-footnote:[You can find out more about the use of the `ldap-server` element in the chapter on pass:specialcharacters,macros[<>].]. +-Use of a good XML editor while editing the application context file should provide information on the attributes and elements that are available. +-We would recommend that you try out the https://spring.io/tools/sts[Spring Tool Suite] as it has special features for working with standard Spring namespaces. ++The most common alternative configuration requirements are supported by attributes on the `ldap-server` element, and the user is isolated from worrying about which beans they need to create and what the bean property names are. ++You can find out more about the use of the `ldap-server` element in the chapter on <>. ++A good XML editor while editing the application context file should provide information on the attributes and elements that are available. ++We recommend that you try the https://spring.io/tools/sts[Spring Tool Suite], as it has special features for working with standard Spring namespaces. + ++To start using the `security` namespace in your application context, add the `spring-security-config` jar to your classpath. ++Then, all you need to do is add the schema declaration to your application context file: + +-To start using the security namespace in your application context, you need to have the `spring-security-config` jar on your classpath. +-Then all you need to do is add the schema declaration to your application context file: +- ++==== + [source,xml] + ---- + ` element. ++Once you have added this bean to your `web.xml`, you are ready to start editing your application context file. ++Web security services are configured by the `` element. + + [[ns-minimal]] + === A Minimal Configuration +-All you need to enable web security to begin with is + ++To enable web security, you need the following configuration: ++ ++==== + [source,xml] + ---- + +@@ -123,31 +130,33 @@ All you need to enable web security to begin with is + + + ---- ++==== ++ ++That listing says that we want: ++ ++* All URLs within our application to be secured, requiring the role `ROLE_USER` to access them ++* To log in to the application using a form with username and password ++* A logout URL registered which will allow us to log out of the application + +-Which says that we want all URLs within our application to be secured, requiring the role `ROLE_USER` to access them, we want to log in to the application using a form with username and password, and that we want a logout URL registered which will allow us to log out of the application. +-`` element is the parent for all web-related namespace functionality. +-The `` element defines a `pattern` which is matched against the URLs of incoming requests using an ant path style syntax footnote:[See the section on pass:specialcharacters,macros[<>] for more details on how matches are actually performed.]. ++The `` element is the parent for all web-related namespace functionality. ++The `` element defines a `pattern`, which is matched against the URLs of incoming requests using Ant path syntax. See the section on <> for more details on how matches are actually performed. + You can also use regular-expression matching as an alternative (see the namespace appendix for more details). +-The `access` attribute defines the access requirements for requests matching the given pattern. ++The `access` attribute defines the access requirements for requests that match the given pattern. + With the default configuration, this is typically a comma-separated list of roles, one of which a user must have to be allowed to make the request. +-The prefix "ROLE_" is a marker which indicates that a simple comparison with the user's authorities should be made. ++The `ROLE_` prefix is a marker that indicates that a simple comparison with the user's authorities should be made. + In other words, a normal role-based check should be used. + Access-control in Spring Security is not limited to the use of simple roles (hence the use of the prefix to differentiate between different types of security attributes). +-We'll see later how the interpretation can vary footnote:[The interpretation of the comma-separated values in the `access` attribute depends on the implementation of the <> which is used.]. +-In Spring Security 3.0, the attribute can also be populated with an <>. ++We see later how the interpretation can vary. The interpretation of the comma-separated values in the `access` attribute depends on the which implementation of the <> is used. ++Since Spring Security 3.0, you can also populate the attribute with an <>. + + +-[NOTE] +-==== +- +-You can use multiple `` elements to define different access requirements for different sets of URLs, but they will be evaluated in the order listed and the first match will be used. ++NOTE: You can use multiple `` elements to define different access requirements for different sets of URLs, but they are evaluated in the order listed and the first match is used. + So you must put the most specific matches at the top. +-You can also add a `method` attribute to limit the match to a particular HTTP method (`GET`, `POST`, `PUT` etc.). +- +-==== ++You can also add a `method` attribute to limit the match to a particular HTTP method (`GET`, `POST`, `PUT`, and so on). + +-To add some users, you can define a set of test data directly in the namespace: ++To add users, you can define a set of test data directly in the namespace: + ++==== + [source,xml,attrs="-attributes"] + ---- + +@@ -162,10 +171,12 @@ To add some users, you can define a set of test data directly in the namespace: + + + ---- ++==== + +-This is an example of a secure way of storing the same passwords. ++The preceding listing shows an example of a secure way to store the same passwords. + The password is prefixed with `+{bcrypt}+` to instruct `DelegatingPasswordEncoder`, which supports any configured `PasswordEncoder` for matching, that the passwords are hashed using BCrypt: + ++==== + [source,xml,attrs="-attributes"] + ---- + +@@ -181,37 +192,36 @@ The password is prefixed with `+{bcrypt}+` to instruct `DelegatingPasswordEncode + + + ---- +- +- ++==== + + [subs="quotes"] + **** +-If you are familiar with pre-namespace versions of the framework, you can probably already guess roughly what's going on here. +-The `` element is responsible for creating a `FilterChainProxy` and the filter beans which it uses. +-Common problems like incorrect filter ordering are no longer an issue as the filter positions are predefined. ++The `` element is responsible for creating a `FilterChainProxy` and the filter beans that it uses. ++Previously common problems, such as incorrect filter ordering, are no longer an issue, as the filter positions are predefined. + +-The `` element creates a `DaoAuthenticationProvider` bean and the `` element creates an `InMemoryDaoImpl`. ++The `` element creates a `DaoAuthenticationProvider` bean, and the `` element creates an `InMemoryDaoImpl`. + All `authentication-provider` elements must be children of the `` element, which creates a `ProviderManager` and registers the authentication providers with it. + You can find more detailed information on the beans that are created in the <>. +-It's worth cross-checking this if you want to start understanding what the important classes in the framework are and how they are used, particularly if you want to customise things later. ++You should cross-check this appendix if you want to start understanding what the important classes in the framework are and how they are used, particularly if you want to customize things later. + **** + +-The configuration above defines two users, their passwords and their roles within the application (which will be used for access control). +-It is also possible to load user information from a standard properties file using the `properties` attribute on `user-service`. ++The preceding configuration defines two users, their passwords, and their roles within the application (which are used for access control). ++You can also possible load user information from a standard properties file by setting the `properties` attribute on the `user-service` element. + See the section on <> for more details on the file format. +-Using the `` element means that the user information will be used by the authentication manager to process authentication requests. +-You can have multiple `` elements to define different authentication sources and each will be consulted in turn. ++Using the `` element means that the user information is used by the authentication manager to process authentication requests. ++You can have multiple `` elements to define different authentication sources. Each is consulted in turn. + +-At this point you should be able to start up your application and you will be required to log in to proceed. +-Try it out, or try experimenting with the "tutorial" sample application that comes with the project. ++At this point, you should be able to start up your application, and you should be required to log in to proceed. ++Try it out, or try experimenting with the "`tutorial`" sample application that comes with the project. + + [[ns-form-target]] + ==== Setting a Default Post-Login Destination +-If a form login isn't prompted by an attempt to access a protected resource, the `default-target-url` option comes into play. +-This is the URL the user will be taken to after successfully logging in, and defaults to "/". +-You can also configure things so that the user __always__ ends up at this page (regardless of whether the login was "on-demand" or they explicitly chose to log in) by setting the `always-use-default-target` attribute to "true". +-This is useful if your application always requires that the user starts at a "home" page, for example: ++If a form login is not prompted by an attempt to access a protected resource, the `default-target-url` option comes into play. ++This is the URL to which the user is taken after successfully logging in. it defaults to `/`. ++You can also configure things so that the user _always_ ends up at this page (regardless of whether the login was "`on-demand`" or they explicitly chose to log in) by setting the `always-use-default-target` attribute to `true`. ++This is useful if your application always requires that the user starts at a "`home`" page, for example: + ++==== + [source,xml] + ---- + +@@ -221,6 +231,7 @@ This is useful if your application always requires that the user starts at a "ho + always-use-default-target='true' /> + + ---- ++==== + + For even more control over the destination, you can use the `authentication-success-handler-ref` attribute as an alternative to `default-target-url`. + The referenced bean should be an instance of `AuthenticationSuccessHandler`. +@@ -228,25 +239,24 @@ The referenced bean should be an instance of `AuthenticationSuccessHandler`. + [[ns-web-advanced]] + == Advanced Web Features + ++This section covers various features that go beyond the basics. ++ + [[ns-custom-filters]] +-=== Adding in Your Own Filters +-If you've used Spring Security before, you'll know that the framework maintains a chain of filters in order to apply its services. +-You may want to add your own filters to the stack at particular locations or use a Spring Security filter for which there isn't currently a namespace configuration option (CAS, for example). +-Or you might want to use a customized version of a standard namespace filter, such as the `UsernamePasswordAuthenticationFilter` which is created by the `` element, taking advantage of some of the extra configuration options which are available by using the bean explicitly. ++=== Adding Your Own Filters ++If you have used Spring Security before, you know that the framework maintains a chain of filters that it uses to apply its services. ++You may want to add your own filters to the stack at particular locations or use a Spring Security filter for which there is not currently a namespace configuration option (CAS, for example). ++// FIXME: Is it still true that there is no CAS filter? ++Alternatively, you might want to use a customized version of a standard namespace filter, such as the `UsernamePasswordAuthenticationFilter` (which is created by the `` element) to take advantage of some of the extra configuration options that are available when you use the bean explicitly. + How can you do this with namespace configuration, since the filter chain is not directly exposed? + +-The order of the filters is always strictly enforced when using the namespace. +-When the application context is being created, the filter beans are sorted by the namespace handling code and the standard Spring Security filters each have an alias in the namespace and a well-known position. ++The order of the filters is always strictly enforced when you use the namespace. ++When the application context is being created, the filter beans are sorted by the namespace handling code, and the standard Spring Security filters each have an alias in the namespace and a well-known position. + +-[NOTE] +-==== +-In previous versions, the sorting took place after the filter instances had been created, during post-processing of the application context. +-In version 3.0+ the sorting is now done at the bean metadata level, before the classes have been instantiated. +-This has implications for how you add your own filters to the stack as the entire filter list must be known during the parsing of the `` element, so the syntax has changed slightly in 3.0. +-==== ++NOTE: In previous versions, the sorting took place after the filter instances had been created, during post-processing of the application context. ++In version 3.0+, the sorting is now done at the bean metadata level, before the classes have been instantiated. ++This has implications for how you add your own filters to the stack, as the entire filter list must be known during the parsing of the `` element. As a result, the syntax changed slightly in version 3.0. + +-The filters, aliases and namespace elements/attributes which create the filters are shown in <>. +-The filters are listed in the order in which they occur in the filter chain. ++The filters, aliases, and namespace elements and attributes that create the filters are shown in the following table, in the order in which they occur in the filter chain: + + [[filter-stack]] + .Standard Filter Aliases and Ordering +@@ -330,8 +340,9 @@ The filters are listed in the order in which they occur in the filter chain. + | N/A + |=== + +-You can add your own filter to the stack, using the `custom-filter` element and one of these names to specify the position your filter should appear at: ++You can add your own filter to the stack by using the `custom-filter` element and one of these names to specify the position at which your filter should appear: + ++==== + [source,xml] + ---- + +@@ -340,40 +351,39 @@ You can add your own filter to the stack, using the `custom-filter` element and + + + ---- ++==== + + You can also use the `after` or `before` attributes if you want your filter to be inserted before or after another filter in the stack. +-The names "FIRST" and "LAST" can be used with the `position` attribute to indicate that you want your filter to appear before or after the entire stack, respectively. ++You can use `FIRST` and `LAST` with the `position` attribute to indicate that you want your filter to appear before or after the entire stack, respectively. + + .Avoiding filter position conflicts + [TIP] + ==== ++If you insert a custom filter that may occupy the same position as one of the standard filters created by the namespace, you should not include the namespace versions by mistake. ++Remove any elements that create filters whose functionality you want to replace. + +-If you are inserting a custom filter which may occupy the same position as one of the standard filters created by the namespace then it's important that you don't include the namespace versions by mistake. +-Remove any elements which create filters whose functionality you want to replace. +- +-Note that you can't replace filters which are created by the use of the `` element itself - `SecurityContextPersistenceFilter`, `ExceptionTranslationFilter` or `FilterSecurityInterceptor`. ++Note that you cannot replace filters that are created by the use of the `` element itself: `SecurityContextPersistenceFilter`, `ExceptionTranslationFilter`, or `FilterSecurityInterceptor`. + Some other filters are added by default, but you can disable them. +-An `AnonymousAuthenticationFilter` is added by default and unless you have <> disabled, a `SessionManagementFilter` will also be added to the filter chain. ++By default, an `AnonymousAuthenticationFilter` is added and unless you have <> disabled, a `SessionManagementFilter` is also added to the filter chain. + + ==== + +-If you're replacing a namespace filter which requires an authentication entry point (i.e. where the authentication process is triggered by an attempt by an unauthenticated user to access to a secured resource), you will need to add a custom entry point bean too. +- ++If you replace a namespace filter that requires an authentication entry point (that is, where the authentication process is triggered by an unauthenticated user's attempt to access to a secured resource), you need to add a custom entry-point bean too. + + + [[ns-method-security]] + == Method Security +-From version 2.0 onwards Spring Security has improved support substantially for adding security to your service layer methods. ++Since version 2.0, Spring Security has substantial support 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 <>. +-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. ++Since version 3.0, you can also make use of <>. ++You can apply security to a single bean (by 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. + + [[ns-access-manager]] + == The Default AccessDecisionManager +-This section assumes you have some knowledge of the underlying architecture for access-control within Spring Security. +-If you don't you can skip it and come back to it later, as this section is only really relevant for people who need to do some customization in order to use more than simple role-based security. ++This section assumes that you have some knowledge of the underlying architecture for access-control within Spring Security. ++If you do not, you can skip it and come back to it later, as this section is relevant only for people who need to do some customization to use more than simple role-based security. + +-When you use a namespace configuration, a default instance of `AccessDecisionManager` is automatically registered for you and will be used for making access decisions for method invocations and web URL access, based on the access attributes you specify in your `intercept-url` and `protect-pointcut` declarations (and in annotations if you are using annotation secured methods). ++When you use a namespace configuration, a default instance of `AccessDecisionManager` is automatically registered for you and is used to make access decisions for method invocations and web URL access, based on the access attributes you specify in your `intercept-url` and `protect-pointcut` declarations (and in annotations, if you use annotations to secure methods). + + The default strategy is to use an `AffirmativeBased` `AccessDecisionManager` with a `RoleVoter` and an `AuthenticatedVoter`. + You can find out more about these in the chapter on <>. +@@ -381,22 +391,26 @@ You can find out more about these in the chapter on <> + + [[ns-custom-access-mgr]] + === Customizing the AccessDecisionManager +-If you need to use a more complicated access control strategy then it is easy to set an alternative for both method and web security. ++If you need to use a more complicated access control strategy, you can set an alternative for both method and web security. + +-For method security, you do this by setting the `access-decision-manager-ref` attribute on `global-method-security` to the `id` of the appropriate `AccessDecisionManager` bean in the application context: ++For method security, you do so by setting the `access-decision-manager-ref` attribute on `global-method-security` to the `id` of the appropriate `AccessDecisionManager` bean in the application context: + ++==== + [source,xml] + ---- + + ... + + ---- ++==== + +-The syntax for web security is the same, but on the `http` element: ++The syntax for web security is the same, but the attribute is on the `http` element: + ++==== + [source,xml] + ---- + + ... + + ---- ++==== +diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/oauth2/index.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/oauth2/index.adoc +index 99ed0947d9..a26601205d 100644 +--- a/docs/manual/src/docs/asciidoc/_includes/servlet/oauth2/index.adoc ++++ b/docs/manual/src/docs/asciidoc/_includes/servlet/oauth2/index.adoc +@@ -1,5 +1,7 @@ + = OAuth2 + ++This section describes how Spring Security enables OAuth2. ++ + include::oauth2-login.adoc[] + + include::oauth2-client.adoc[] +diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/oauth2/oauth2-client.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/oauth2/oauth2-client.adoc +index 8b1a61f71d..ab5f8c0d61 100644 +--- a/docs/manual/src/docs/asciidoc/_includes/servlet/oauth2/oauth2-client.adoc ++++ b/docs/manual/src/docs/asciidoc/_includes/servlet/oauth2/oauth2-client.adoc +@@ -91,7 +91,7 @@ The following code shows the complete configuration options available in the <> +-** <> +-** <> +-** <> +-** <> +-** <> ++** <> ++** <> ++** <> ++** <> ++** <> + * <> +-** <> +-** <> +-** <> +-** <> ++** <> ++** <> ++** <> ++** <> + * <> +-** <> ++** <> + * <> + + + [[oauth2Client-core-interface-class]] +-=== Core Interfaces / Classes ++=== Core Interfaces and Classes ++ ++This section describes the OAuth2 core interfaces and classes that Spring Security offers. + + + [[oauth2Client-client-registration]] +@@ -167,10 +169,11 @@ The following sections will go into more detail on the core components used by O + + `ClientRegistration` is a representation of a client registered with an OAuth 2.0 or OpenID Connect 1.0 Provider. + +-A client registration holds information, such as client id, client secret, authorization grant type, redirect URI, scope(s), authorization URI, token URI, and other details. ++A `ClientRegistration` object holds information, such as client id, client secret, authorization grant type, redirect URI, scope(s), authorization URI, token URI, and other details. + + `ClientRegistration` and its properties are defined as follows: + ++==== + [source,java] + ---- + public final class ClientRegistration { +@@ -205,29 +208,30 @@ public final class ClientRegistration { + <2> `clientId`: The client identifier. + <3> `clientSecret`: The client secret. + <4> `clientAuthenticationMethod`: The method used to authenticate the Client with the Provider. +-The supported values are *client_secret_basic*, *client_secret_post* and *none* https://tools.ietf.org/html/rfc6749#section-2.1[(public clients)]. ++The supported values are *client_secret_basic*, *client_secret_post*, and *none* https://tools.ietf.org/html/rfc6749#section-2.1[(public clients)]. + <5> `authorizationGrantType`: The OAuth 2.0 Authorization Framework defines four https://tools.ietf.org/html/rfc6749#section-1.3[Authorization Grant] types. +- The supported values are `authorization_code`, `client_credentials` and `password`. +-<6> `redirectUri`: The client's registered redirect URI that the _Authorization Server_ redirects the end-user's user-agent +- to after the end-user has authenticated and authorized access to the client. ++Spring Security support `authorization_code`, `client_credentials` and `password`. ++<6> `redirectUri`: The client's registered redirect URI to which the _Authorization Server_ redirects the end-user's user-agent ++after the end-user has authenticated and authorized access to the client. + <7> `scopes`: The scope(s) requested by the client during the Authorization Request flow, such as openid, email, or profile. + <8> `clientName`: A descriptive name used for the client. + The name may be used in certain scenarios, such as when displaying the name of the client in the auto-generated login page. + <9> `authorizationUri`: The Authorization Endpoint URI for the Authorization Server. + <10> `tokenUri`: The Token Endpoint URI for the Authorization Server. + <11> `jwkSetUri`: The URI used to retrieve the https://tools.ietf.org/html/rfc7517[JSON Web Key (JWK)] Set from the Authorization Server, +- which contains the cryptographic key(s) used to verify the https://tools.ietf.org/html/rfc7515[JSON Web Signature (JWS)] of the ID Token and optionally the UserInfo Response. +-<12> `issuerUri`: Returns the issuer identifier uri for the OpenID Connect 1.0 provider or the OAuth 2.0 Authorization Server. ++which contains the cryptographic key(s) used to verify the https://tools.ietf.org/html/rfc7515[JSON Web Signature (JWS)] of the ID Token and (optionally) the UserInfo Response. ++<12> `issuerUri`: Returns the issuer identifier URI for the OpenID Connect 1.0 provider or the OAuth 2.0 Authorization Server. + <13> `configurationMetadata`: The https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfig[OpenID Provider Configuration Information]. +- This information will only be available if the Spring Boot 2.x property `spring.security.oauth2.client.provider.[providerId].issuerUri` is configured. +-<14> `(userInfoEndpoint)uri`: The UserInfo Endpoint URI used to access the claims/attributes of the authenticated end-user. ++ This information is available only if the Spring Boot 2.x property `spring.security.oauth2.client.provider.[providerId].issuerUri` is configured. ++<14> `(userInfoEndpoint)uri`: The UserInfo Endpoint URI used to access the claims and attributes of the authenticated end-user. + <15> `(userInfoEndpoint)authenticationMethod`: The authentication method used when sending the access token to the UserInfo Endpoint. +-The supported values are *header*, *form* and *query*. ++The supported values are *header*, *form*, and *query*. + <16> `userNameAttributeName`: The name of the attribute returned in the UserInfo Response that references the Name or Identifier of the end-user. ++==== + +-A `ClientRegistration` can be initially configured using discovery of an OpenID Connect Provider's https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfig[Configuration endpoint] or an Authorization Server's https://tools.ietf.org/html/rfc8414#section-3[Metadata endpoint]. ++You can initially configure a `ClientRegistration` by using discovery of an OpenID Connect Provider's https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfig[Configuration endpoint] or an Authorization Server's https://tools.ietf.org/html/rfc8414#section-3[Metadata endpoint]. + +-`ClientRegistrations` provides convenience methods for configuring a `ClientRegistration` in this way, as can be seen in the following example: ++`ClientRegistrations` provides convenience methods for configuring a `ClientRegistration` in this way, as follows: + + ==== + .Java +@@ -244,25 +248,23 @@ val clientRegistration = ClientRegistrations.fromIssuerLocation("https://idp.exa + ---- + ==== + +-The above code will query in series `https://idp.example.com/issuer/.well-known/openid-configuration`, and then `https://idp.example.com/.well-known/openid-configuration/issuer`, and finally `https://idp.example.com/.well-known/oauth-authorization-server/issuer`, stopping at the first to return a 200 response. ++The preceding code queries, in series, `https://idp.example.com/issuer/.well-known/openid-configuration`, `https://idp.example.com/.well-known/openid-configuration/issuer`, and `https://idp.example.com/.well-known/oauth-authorization-server/issuer`, stopping at the first to return a 200 response. + +-As an alternative, you can use `ClientRegistrations.fromOidcIssuerLocation()` to only query the OpenID Connect Provider's Configuration endpoint. ++As an alternative, you can use `ClientRegistrations.fromOidcIssuerLocation()` to query only the OpenID Connect Provider's Configuration endpoint. + + [[oauth2Client-client-registration-repo]] + ==== ClientRegistrationRepository + + The `ClientRegistrationRepository` serves as a repository for OAuth 2.0 / OpenID Connect 1.0 `ClientRegistration`(s). + +-[NOTE] +-Client registration information is ultimately stored and owned by the associated Authorization Server. +-This repository provides the ability to retrieve a sub-set of the primary client registration information, which is stored with the Authorization Server. ++NOTE: Client registration information is ultimately stored and owned by the associated Authorization Server. ++This repository provides the ability to retrieve a subset of the primary client registration information, which is stored with the Authorization Server. + + Spring Boot 2.x auto-configuration binds each of the properties under `spring.security.oauth2.client.registration._[registrationId]_` to an instance of `ClientRegistration` and then composes each of the `ClientRegistration` instance(s) within a `ClientRegistrationRepository`. + +-[NOTE] +-The default implementation of `ClientRegistrationRepository` is `InMemoryClientRegistrationRepository`. ++NOTE: The default implementation of `ClientRegistrationRepository` is `InMemoryClientRegistrationRepository`. + +-The auto-configuration also registers the `ClientRegistrationRepository` as a `@Bean` in the `ApplicationContext` so that it is available for dependency-injection, if needed by the application. ++The auto-configuration also registers the `ClientRegistrationRepository` as a `@Bean` in the `ApplicationContext` so that it is available for dependency injection, if needed by the application. + + The following listing shows an example: + +@@ -314,18 +316,18 @@ class OAuth2ClientController { + ==== OAuth2AuthorizedClient + + `OAuth2AuthorizedClient` is a representation of an Authorized Client. +-A client is considered to be authorized when the end-user (Resource Owner) has granted authorization to the client to access its protected resources. ++A client is considered to be authorized when the end-user (the Resource Owner) has granted authorization to the client to access its protected resources. + + `OAuth2AuthorizedClient` serves the purpose of associating an `OAuth2AccessToken` (and optional `OAuth2RefreshToken`) to a `ClientRegistration` (client) and resource owner, who is the `Principal` end-user that granted the authorization. + + + [[oauth2Client-authorized-repo-service]] +-==== OAuth2AuthorizedClientRepository / OAuth2AuthorizedClientService ++==== OAuth2AuthorizedClientRepository and OAuth2AuthorizedClientService + +-`OAuth2AuthorizedClientRepository` is responsible for persisting `OAuth2AuthorizedClient`(s) between web requests. +-Whereas, the primary role of `OAuth2AuthorizedClientService` is to manage `OAuth2AuthorizedClient`(s) at the application-level. ++`OAuth2AuthorizedClientRepository` is responsible for persisting `OAuth2AuthorizedClient`(s) between web requests, ++whereas the primary role of `OAuth2AuthorizedClientService` is to manage `OAuth2AuthorizedClient`(s) at the application-level. + +-From a developer perspective, the `OAuth2AuthorizedClientRepository` or `OAuth2AuthorizedClientService` provides the capability to lookup an `OAuth2AccessToken` associated with a client so that it may be used to initiate a protected resource request. ++From a developer perspective, the `OAuth2AuthorizedClientRepository` or `OAuth2AuthorizedClientService` provides the ability to look up an `OAuth2AccessToken` associated with a client so that it can be used to initiate a protected resource request. + + The following listing shows an example: + +@@ -376,37 +378,35 @@ class OAuth2ClientController { + ---- + ==== + +-[NOTE] +-Spring Boot 2.x auto-configuration registers an `OAuth2AuthorizedClientRepository` and/or `OAuth2AuthorizedClientService` `@Bean` in the `ApplicationContext`. +-However, the application may choose to override and register a custom `OAuth2AuthorizedClientRepository` or `OAuth2AuthorizedClientService` `@Bean`. ++NOTE: Spring Boot 2.x auto-configuration registers an `OAuth2AuthorizedClientRepository` or an `OAuth2AuthorizedClientService` `@Bean` in the `ApplicationContext`. ++However, the application can override and register a custom `OAuth2AuthorizedClientRepository` or `OAuth2AuthorizedClientService` `@Bean`. + +-The default implementation of `OAuth2AuthorizedClientService` is `InMemoryOAuth2AuthorizedClientService`, which stores `OAuth2AuthorizedClient`(s) in-memory. ++The default implementation of `OAuth2AuthorizedClientService` is `InMemoryOAuth2AuthorizedClientService`, which stores `OAuth2AuthorizedClient` objects in-memory. + +-Alternatively, the JDBC implementation `JdbcOAuth2AuthorizedClientService` may be configured for persisting `OAuth2AuthorizedClient`(s) in a database. ++Alternatively, you can configure the JDBC implementation `JdbcOAuth2AuthorizedClientService` to persist `OAuth2AuthorizedClient` instances in a database. + +-[NOTE] +-`JdbcOAuth2AuthorizedClientService` depends on the table definition described in <>. ++NOTE: `JdbcOAuth2AuthorizedClientService` depends on the table definition described in <>. + + + [[oauth2Client-authorized-manager-provider]] +-==== OAuth2AuthorizedClientManager / OAuth2AuthorizedClientProvider ++==== OAuth2AuthorizedClientManager and OAuth2AuthorizedClientProvider + + The `OAuth2AuthorizedClientManager` is responsible for the overall management of `OAuth2AuthorizedClient`(s). + + The primary responsibilities include: + +-* Authorizing (or re-authorizing) an OAuth 2.0 Client, using an `OAuth2AuthorizedClientProvider`. +-* Delegating the persistence of an `OAuth2AuthorizedClient`, typically using an `OAuth2AuthorizedClientService` or `OAuth2AuthorizedClientRepository`. ++* Authorizing (or re-authorizing) an OAuth 2.0 Client, by using an `OAuth2AuthorizedClientProvider`. ++* Delegating the persistence of an `OAuth2AuthorizedClient`, typically by using an `OAuth2AuthorizedClientService` or `OAuth2AuthorizedClientRepository`. + * Delegating to an `OAuth2AuthorizationSuccessHandler` when an OAuth 2.0 Client has been successfully authorized (or re-authorized). + * Delegating to an `OAuth2AuthorizationFailureHandler` when an OAuth 2.0 Client fails to authorize (or re-authorize). + + An `OAuth2AuthorizedClientProvider` implements a strategy for authorizing (or re-authorizing) an OAuth 2.0 Client. +-Implementations will typically implement an authorization grant type, eg. `authorization_code`, `client_credentials`, etc. ++Implementations typically implement an authorization grant type, such as `authorization_code`, `client_credentials`, and others. + + The default implementation of `OAuth2AuthorizedClientManager` is `DefaultOAuth2AuthorizedClientManager`, which is associated with an `OAuth2AuthorizedClientProvider` that may support multiple authorization grant types using a delegation-based composite. +-The `OAuth2AuthorizedClientProviderBuilder` may be used to configure and build the delegation-based composite. ++You can use `OAuth2AuthorizedClientProviderBuilder` to configure and build the delegation-based composite. + +-The following code shows an example of how to configure and build an `OAuth2AuthorizedClientProvider` composite that provides support for the `authorization_code`, `refresh_token`, `client_credentials` and `password` authorization grant types: ++The following code shows an example of how to configure and build an `OAuth2AuthorizedClientProvider` composite that provides support for the `authorization_code`, `refresh_token`, `client_credentials`, and `password` authorization grant types: + + ==== + .Java +@@ -455,12 +455,12 @@ fun authorizedClientManager( + ---- + ==== + +-When an authorization attempt succeeds, the `DefaultOAuth2AuthorizedClientManager` will delegate to the `OAuth2AuthorizationSuccessHandler`, which (by default) will save the `OAuth2AuthorizedClient` via the `OAuth2AuthorizedClientRepository`. +-In the case of a re-authorization failure, eg. a refresh token is no longer valid, the previously saved `OAuth2AuthorizedClient` will be removed from the `OAuth2AuthorizedClientRepository` via the `RemoveAuthorizedClientOAuth2AuthorizationFailureHandler`. +-The default behaviour may be customized via `setAuthorizationSuccessHandler(OAuth2AuthorizationSuccessHandler)` and `setAuthorizationFailureHandler(OAuth2AuthorizationFailureHandler)`. ++When an authorization attempt succeeds, the `DefaultOAuth2AuthorizedClientManager` delegates to the `OAuth2AuthorizationSuccessHandler`, which (by default) saves the `OAuth2AuthorizedClient` through the `OAuth2AuthorizedClientRepository`. ++In the case of a re-authorization failure (for example, a refresh token is no longer valid), the previously saved `OAuth2AuthorizedClient` is removed from the `OAuth2AuthorizedClientRepository` through the `RemoveAuthorizedClientOAuth2AuthorizationFailureHandler`. ++You can customize the default behavior through `setAuthorizationSuccessHandler(OAuth2AuthorizationSuccessHandler)` and `setAuthorizationFailureHandler(OAuth2AuthorizationFailureHandler)`. + + The `DefaultOAuth2AuthorizedClientManager` is also associated with a `contextAttributesMapper` of type `Function>`, which is responsible for mapping attribute(s) from the `OAuth2AuthorizeRequest` to a `Map` of attributes to be associated to the `OAuth2AuthorizationContext`. +-This can be useful when you need to supply an `OAuth2AuthorizedClientProvider` with required (supported) attribute(s), eg. the `PasswordOAuth2AuthorizedClientProvider` requires the resource owner's `username` and `password` to be available in `OAuth2AuthorizationContext.getAttributes()`. ++This can be useful when you need to supply an `OAuth2AuthorizedClientProvider` with required (supported) attribute(s). For example, the `PasswordOAuth2AuthorizedClientProvider` requires the resource owner's `username` and `password` to be available in `OAuth2AuthorizationContext.getAttributes()`. + + The following code shows an example of the `contextAttributesMapper`: + +@@ -549,10 +549,10 @@ private fun contextAttributesMapper(): Function>. +-This ensures that the `X-Forwarded-*` headers are used when expanding the `redirect-uri`. ++Doing so ensures that the `X-Forwarded-*` headers are used when expanding the `redirect-uri`. + + ===== Customizing the Authorization Request + +@@ -705,8 +709,7 @@ One of the primary use cases an `OAuth2AuthorizationRequestResolver` can realize + For example, OpenID Connect defines additional OAuth 2.0 request parameters for the https://openid.net/specs/openid-connect-core-1_0.html#AuthRequest[Authorization Code Flow] extending from the standard parameters defined in the https://tools.ietf.org/html/rfc6749#section-4.1.1[OAuth 2.0 Authorization Framework]. + One of those extended parameters is the `prompt` parameter. + +-[NOTE] +-OPTIONAL. Space delimited, case sensitive list of ASCII string values that specifies whether the Authorization Server prompts the End-User for reauthentication and consent. The defined values are: none, login, consent, select_account ++NOTE: The `prompt` parameter is optional. Space delimited, case sensitive list of ASCII string values that specifies whether the Authorization Server prompts the End-User for re-authentication and consent. The defined values are: `none`, `login`, `consent`, and `select_account`. + + The following example shows how to configure the `DefaultOAuth2AuthorizationRequestResolver` with a `Consumer` that customizes the Authorization Request for `oauth2Login()`, by including the request parameter `prompt=consent`. + +@@ -795,10 +798,11 @@ class SecurityConfig : WebSecurityConfigurerAdapter() { + ---- + ==== + +-For the simple use case, where the additional request parameter is always the same for a specific provider, it may be added directly in the `authorization-uri` property. ++For the simple use case where the additional request parameter is always the same for a specific provider, you can add it directly in the `authorization-uri` property. + +-For example, if the value for the request parameter `prompt` is always `consent` for the provider `okta`, than simply configure as follows: ++For example, if the value for the request parameter `prompt` is always `consent` for the provider `okta`, you can configure it as follows: + ++==== + [source,yaml] + ---- + spring: +@@ -809,14 +813,14 @@ spring: + okta: + authorization-uri: https://dev-1234.oktapreview.com/oauth2/v1/authorize?prompt=consent + ---- ++==== + + The preceding example shows the common use case of adding a custom parameter on top of the standard parameters. +-Alternatively, if your requirements are more advanced, you can take full control in building the Authorization Request URI by simply overriding the `OAuth2AuthorizationRequest.authorizationRequestUri` property. ++Alternatively, if your requirements are more advanced, you can take full control in building the Authorization Request URI by overriding the `OAuth2AuthorizationRequest.authorizationRequestUri` property. + +-[TIP] +-`OAuth2AuthorizationRequest.Builder.build()` constructs the `OAuth2AuthorizationRequest.authorizationRequestUri`, which represents the Authorization Request URI including all query parameters using the `application/x-www-form-urlencoded` format. ++TIP: `OAuth2AuthorizationRequest.Builder.build()` constructs the `OAuth2AuthorizationRequest.authorizationRequestUri`, which represents the Authorization Request URI that includes all query parameters that use the `application/x-www-form-urlencoded` format. + +-The following example shows a variation of `authorizationRequestCustomizer()` from the preceding example, and instead overrides the `OAuth2AuthorizationRequest.authorizationRequestUri` property. ++The following example shows a variation of `authorizationRequestCustomizer()` from the preceding example and instead overrides the `OAuth2AuthorizationRequest.authorizationRequestUri` property: + + ==== + .Java +@@ -849,12 +853,11 @@ private fun authorizationRequestCustomizer(): Consumer>`. +-The default implementation `OAuth2AuthorizationCodeGrantRequestEntityConverter` builds a `RequestEntity` representation of a standard https://tools.ietf.org/html/rfc6749#section-4.1.3[OAuth 2.0 Access Token Request]. +-However, providing a custom `Converter`, would allow you to extend the standard Token Request and add custom parameter(s). ++The default implementation (`OAuth2AuthorizationCodeGrantRequestEntityConverter`) builds a `RequestEntity` representation of a standard https://tools.ietf.org/html/rfc6749#section-4.1.3[OAuth 2.0 Access Token Request]. ++However, providing a custom `Converter` would let you extend the standard Token Request and add custom parameter(s). + + IMPORTANT: The custom `Converter` must return a valid `RequestEntity` representation of an OAuth 2.0 Access Token Request that is understood by the intended OAuth 2.0 Provider. + + + ===== Customizing the Access Token Response + +-On the other end, if you need to customize the post-handling of the Token Response, you will need to provide `DefaultAuthorizationCodeTokenResponseClient.setRestOperations()` with a custom configured `RestOperations`. ++On the other end, if you need to customize the post-handling of the Token Response, you need to provide `DefaultAuthorizationCodeTokenResponseClient.setRestOperations()` with a custom configured `RestOperations`. + The default `RestOperations` is configured as follows: + + ==== +@@ -952,15 +954,15 @@ restTemplate.errorHandler = OAuth2ErrorResponseErrorHandler() + ---- + ==== + +-TIP: Spring MVC `FormHttpMessageConverter` is required as it's used when sending the OAuth 2.0 Access Token Request. ++TIP: Spring MVC `FormHttpMessageConverter` is required, as it is used when sending the OAuth 2.0 Access Token Request. + +-`OAuth2AccessTokenResponseHttpMessageConverter` is a `HttpMessageConverter` for an OAuth 2.0 Access Token Response. ++`OAuth2AccessTokenResponseHttpMessageConverter` is an `HttpMessageConverter` for an OAuth 2.0 Access Token Response. + You can provide `OAuth2AccessTokenResponseHttpMessageConverter.setTokenResponseConverter()` with a custom `Converter, OAuth2AccessTokenResponse>` that is used for converting the OAuth 2.0 Access Token Response parameters to an `OAuth2AccessTokenResponse`. + +-`OAuth2ErrorResponseErrorHandler` is a `ResponseErrorHandler` that can handle an OAuth 2.0 Error, eg. 400 Bad Request. ++`OAuth2ErrorResponseErrorHandler` is a `ResponseErrorHandler` that can handle an OAuth 2.0 Error, such as `400 Bad Request`. + It uses an `OAuth2ErrorHttpMessageConverter` for converting the OAuth 2.0 Error parameters to an `OAuth2Error`. + +-Whether you customize `DefaultAuthorizationCodeTokenResponseClient` or provide your own implementation of `OAuth2AccessTokenResponseClient`, you'll need to configure it as shown in the following example: ++Whether you customize `DefaultAuthorizationCodeTokenResponseClient` or provide your own implementation of `OAuth2AccessTokenResponseClient`, you need to configure it as follows: + + .Access Token Response Configuration + ==== +@@ -1016,32 +1018,30 @@ class OAuth2ClientSecurityConfig : WebSecurityConfigurerAdapter() { + [[oauth2Client-refresh-token-grant]] + ==== Refresh Token + +-[NOTE] +-Please refer to the OAuth 2.0 Authorization Framework for further details on the https://tools.ietf.org/html/rfc6749#section-1.5[Refresh Token]. ++NOTE: See the OAuth 2.0 Authorization Framework for further details on the https://tools.ietf.org/html/rfc6749#section-1.5[Refresh Token]. + + + ===== Refreshing an Access Token + +-[NOTE] +-Please refer to the https://tools.ietf.org/html/rfc6749#section-6[Access Token Request/Response] protocol flow for the Refresh Token grant. ++NOTE: See the https://tools.ietf.org/html/rfc6749#section-6[Access Token Request/Response] protocol flow for the Refresh Token grant. + + The default implementation of `OAuth2AccessTokenResponseClient` for the Refresh Token grant is `DefaultRefreshTokenTokenResponseClient`, which uses a `RestOperations` when refreshing an access token at the Authorization Server’s Token Endpoint. + +-The `DefaultRefreshTokenTokenResponseClient` is quite flexible as it allows you to customize the pre-processing of the Token Request and/or post-handling of the Token Response. ++The `DefaultRefreshTokenTokenResponseClient` is flexible, as it lets you customize the pre-processing of the Token Request or post-handling of the Token Response. + + + ===== Customizing the Access Token Request + + If you need to customize the pre-processing of the Token Request, you can provide `DefaultRefreshTokenTokenResponseClient.setRequestEntityConverter()` with a custom `Converter>`. +-The default implementation `OAuth2RefreshTokenGrantRequestEntityConverter` builds a `RequestEntity` representation of a standard https://tools.ietf.org/html/rfc6749#section-6[OAuth 2.0 Access Token Request]. +-However, providing a custom `Converter`, would allow you to extend the standard Token Request and add custom parameter(s). ++The default implementation (`OAuth2RefreshTokenGrantRequestEntityConverter`) builds a `RequestEntity` representation of a standard https://tools.ietf.org/html/rfc6749#section-6[OAuth 2.0 Access Token Request]. ++However, providing a custom `Converter` would let you extend the standard Token Request and add custom parameter(s). + + IMPORTANT: The custom `Converter` must return a valid `RequestEntity` representation of an OAuth 2.0 Access Token Request that is understood by the intended OAuth 2.0 Provider. + + + ===== Customizing the Access Token Response + +-On the other end, if you need to customize the post-handling of the Token Response, you will need to provide `DefaultRefreshTokenTokenResponseClient.setRestOperations()` with a custom configured `RestOperations`. ++On the other end, if you need to customize the post-handling of the Token Response, you need to provide `DefaultRefreshTokenTokenResponseClient.setRestOperations()` with a custom configured `RestOperations`. + The default `RestOperations` is configured as follows: + + ==== +@@ -1066,15 +1066,15 @@ restTemplate.errorHandler = OAuth2ErrorResponseErrorHandler() + ---- + ==== + +-TIP: Spring MVC `FormHttpMessageConverter` is required as it's used when sending the OAuth 2.0 Access Token Request. ++TIP: Spring MVC `FormHttpMessageConverter` is required, as it is used when sending the OAuth 2.0 Access Token Request. + + `OAuth2AccessTokenResponseHttpMessageConverter` is a `HttpMessageConverter` for an OAuth 2.0 Access Token Response. + You can provide `OAuth2AccessTokenResponseHttpMessageConverter.setTokenResponseConverter()` with a custom `Converter, OAuth2AccessTokenResponse>` that is used for converting the OAuth 2.0 Access Token Response parameters to an `OAuth2AccessTokenResponse`. + +-`OAuth2ErrorResponseErrorHandler` is a `ResponseErrorHandler` that can handle an OAuth 2.0 Error, eg. 400 Bad Request. ++`OAuth2ErrorResponseErrorHandler` is a `ResponseErrorHandler` that can handle an OAuth 2.0 Error, such as `400 Bad Request`. + It uses an `OAuth2ErrorHttpMessageConverter` for converting the OAuth 2.0 Error parameters to an `OAuth2Error`. + +-Whether you customize `DefaultRefreshTokenTokenResponseClient` or provide your own implementation of `OAuth2AccessTokenResponseClient`, you'll need to configure it as shown in the following example: ++Whether you customize `DefaultRefreshTokenTokenResponseClient` or provide your own implementation of `OAuth2AccessTokenResponseClient`, you need to configure it as follows: + + ==== + .Java +@@ -1115,39 +1115,37 @@ authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider) + `OAuth2AuthorizedClientProviderBuilder.builder().refreshToken()` configures a `RefreshTokenOAuth2AuthorizedClientProvider`, + which is an implementation of an `OAuth2AuthorizedClientProvider` for the Refresh Token grant. + +-The `OAuth2RefreshToken` may optionally be returned in the Access Token Response for the `authorization_code` and `password` grant types. +-If the `OAuth2AuthorizedClient.getRefreshToken()` is available and the `OAuth2AuthorizedClient.getAccessToken()` is expired, it will automatically be refreshed by the `RefreshTokenOAuth2AuthorizedClientProvider`. ++The `OAuth2RefreshToken` can optionally be returned in the Access Token Response for the `authorization_code` and `password` grant types. ++If the `OAuth2AuthorizedClient.getRefreshToken()` is available and the `OAuth2AuthorizedClient.getAccessToken()` is expired, it is automatically refreshed by the `RefreshTokenOAuth2AuthorizedClientProvider`. + + + [[oauth2Client-client-creds-grant]] + ==== Client Credentials + +-[NOTE] +-Please refer to the OAuth 2.0 Authorization Framework for further details on the https://tools.ietf.org/html/rfc6749#section-1.3.4[Client Credentials] grant. ++NOTE: See the OAuth 2.0 Authorization Framework for further details on the https://tools.ietf.org/html/rfc6749#section-1.3.4[Client Credentials] grant. + + + ===== Requesting an Access Token + +-[NOTE] +-Please refer to the https://tools.ietf.org/html/rfc6749#section-4.4.2[Access Token Request/Response] protocol flow for the Client Credentials grant. ++NOTE: See the https://tools.ietf.org/html/rfc6749#section-4.4.2[Access Token Request/Response] protocol flow for the Client Credentials grant. + + The default implementation of `OAuth2AccessTokenResponseClient` for the Client Credentials grant is `DefaultClientCredentialsTokenResponseClient`, which uses a `RestOperations` when requesting an access token at the Authorization Server’s Token Endpoint. + +-The `DefaultClientCredentialsTokenResponseClient` is quite flexible as it allows you to customize the pre-processing of the Token Request and/or post-handling of the Token Response. ++The `DefaultClientCredentialsTokenResponseClient` is flexible, as it lets you customize the pre-processing of the Token Request or post-handling of the Token Response. + + + ===== Customizing the Access Token Request + + If you need to customize the pre-processing of the Token Request, you can provide `DefaultClientCredentialsTokenResponseClient.setRequestEntityConverter()` with a custom `Converter>`. +-The default implementation `OAuth2ClientCredentialsGrantRequestEntityConverter` builds a `RequestEntity` representation of a standard https://tools.ietf.org/html/rfc6749#section-4.4.2[OAuth 2.0 Access Token Request]. +-However, providing a custom `Converter`, would allow you to extend the standard Token Request and add custom parameter(s). ++The default implementation (`OAuth2ClientCredentialsGrantRequestEntityConverter`) builds a `RequestEntity` representation of a standard https://tools.ietf.org/html/rfc6749#section-4.4.2[OAuth 2.0 Access Token Request]. ++However, providing a custom `Converter` would let you extend the standard Token Request and add custom parameter(s). + + IMPORTANT: The custom `Converter` must return a valid `RequestEntity` representation of an OAuth 2.0 Access Token Request that is understood by the intended OAuth 2.0 Provider. + + + ===== Customizing the Access Token Response + +-On the other end, if you need to customize the post-handling of the Token Response, you will need to provide `DefaultClientCredentialsTokenResponseClient.setRestOperations()` with a custom configured `RestOperations`. ++On the other end, if you need to customize the post-handling of the Token Response, you need to provide `DefaultClientCredentialsTokenResponseClient.setRestOperations()` with a custom configured `RestOperations`. + The default `RestOperations` is configured as follows: + + ==== +@@ -1172,15 +1170,15 @@ restTemplate.errorHandler = OAuth2ErrorResponseErrorHandler() + ---- + ==== + +-TIP: Spring MVC `FormHttpMessageConverter` is required as it's used when sending the OAuth 2.0 Access Token Request. ++TIP: Spring MVC `FormHttpMessageConverter` is required, as it is used when sending the OAuth 2.0 Access Token Request. + + `OAuth2AccessTokenResponseHttpMessageConverter` is a `HttpMessageConverter` for an OAuth 2.0 Access Token Response. + You can provide `OAuth2AccessTokenResponseHttpMessageConverter.setTokenResponseConverter()` with a custom `Converter, OAuth2AccessTokenResponse>` that is used for converting the OAuth 2.0 Access Token Response parameters to an `OAuth2AccessTokenResponse`. + +-`OAuth2ErrorResponseErrorHandler` is a `ResponseErrorHandler` that can handle an OAuth 2.0 Error, eg. 400 Bad Request. +-It uses an `OAuth2ErrorHttpMessageConverter` for converting the OAuth 2.0 Error parameters to an `OAuth2Error`. ++`OAuth2ErrorResponseErrorHandler` is a `ResponseErrorHandler` that can handle an OAuth 2.0 Error, such as `400 Bad Request`. ++It uses an `OAuth2ErrorHttpMessageConverter` to convert the OAuth 2.0 Error parameters to an `OAuth2Error`. + +-Whether you customize `DefaultClientCredentialsTokenResponseClient` or provide your own implementation of `OAuth2AccessTokenResponseClient`, you'll need to configure it as shown in the following example: ++Whether you customize `DefaultClientCredentialsTokenResponseClient` or provide your own implementation of `OAuth2AccessTokenResponseClient`, you need to configure it as follows: + + ==== + .Java +@@ -1215,14 +1213,14 @@ authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider) + ---- + ==== + +-[NOTE] +-`OAuth2AuthorizedClientProviderBuilder.builder().clientCredentials()` configures a `ClientCredentialsOAuth2AuthorizedClientProvider`, ++NOTE: `OAuth2AuthorizedClientProviderBuilder.builder().clientCredentials()` configures a `ClientCredentialsOAuth2AuthorizedClientProvider`, + which is an implementation of an `OAuth2AuthorizedClientProvider` for the Client Credentials grant. + + ===== Using the Access Token + +-Given the following Spring Boot 2.x properties for an OAuth 2.0 Client registration: ++Consider the following Spring Boot 2.x properties for an OAuth 2.0 Client registration: + ++==== + [source,yaml] + ---- + spring: +@@ -1239,8 +1237,9 @@ spring: + okta: + token-uri: https://dev-1234.oktapreview.com/oauth2/v1/token + ---- ++==== + +-...and the `OAuth2AuthorizedClientManager` `@Bean`: ++Further consider the following `OAuth2AuthorizedClientManager` `@Bean`: + + ==== + .Java +@@ -1283,7 +1282,7 @@ fun authorizedClientManager( + ---- + ==== + +-You may obtain the `OAuth2AccessToken` as follows: ++Given the preceding properties and bean, you can obtain the `OAuth2AccessToken` as follows: + + ==== + .Java +@@ -1348,40 +1347,37 @@ class OAuth2ClientController { + ---- + ==== + +-[NOTE] +-`HttpServletRequest` and `HttpServletResponse` are both OPTIONAL attributes. +-If not provided, it will default to `ServletRequestAttributes` using `RequestContextHolder.getRequestAttributes()`. ++NOTE: `HttpServletRequest` and `HttpServletResponse` are both OPTIONAL attributes. ++If not provided, they default to `ServletRequestAttributes` by using `RequestContextHolder.getRequestAttributes()`. + + + [[oauth2Client-password-grant]] + ==== Resource Owner Password Credentials + +-[NOTE] +-Please refer to the OAuth 2.0 Authorization Framework for further details on the https://tools.ietf.org/html/rfc6749#section-1.3.3[Resource Owner Password Credentials] grant. ++NOTE: See the OAuth 2.0 Authorization Framework for further details on the https://tools.ietf.org/html/rfc6749#section-1.3.3[Resource Owner Password Credentials] grant. + + + ===== Requesting an Access Token + +-[NOTE] +-Please refer to the https://tools.ietf.org/html/rfc6749#section-4.3.2[Access Token Request/Response] protocol flow for the Resource Owner Password Credentials grant. ++NOTE: See the https://tools.ietf.org/html/rfc6749#section-4.3.2[Access Token Request/Response] protocol flow for the Resource Owner Password Credentials grant. + + The default implementation of `OAuth2AccessTokenResponseClient` for the Resource Owner Password Credentials grant is `DefaultPasswordTokenResponseClient`, which uses a `RestOperations` when requesting an access token at the Authorization Server’s Token Endpoint. + +-The `DefaultPasswordTokenResponseClient` is quite flexible as it allows you to customize the pre-processing of the Token Request and/or post-handling of the Token Response. ++The `DefaultPasswordTokenResponseClient` is flexible, as it lets you customize the pre-processing of the Token Request or post-handling of the Token Response. + + + ===== Customizing the Access Token Request + + If you need to customize the pre-processing of the Token Request, you can provide `DefaultPasswordTokenResponseClient.setRequestEntityConverter()` with a custom `Converter>`. +-The default implementation `OAuth2PasswordGrantRequestEntityConverter` builds a `RequestEntity` representation of a standard https://tools.ietf.org/html/rfc6749#section-4.3.2[OAuth 2.0 Access Token Request]. +-However, providing a custom `Converter`, would allow you to extend the standard Token Request and add custom parameter(s). ++The default implementation (`OAuth2PasswordGrantRequestEntityConverter`) builds a `RequestEntity` representation of a standard https://tools.ietf.org/html/rfc6749#section-4.3.2[OAuth 2.0 Access Token Request]. ++However, providing a custom `Converter` would let you extend the standard Token Request and add custom parameter(s). + + IMPORTANT: The custom `Converter` must return a valid `RequestEntity` representation of an OAuth 2.0 Access Token Request that is understood by the intended OAuth 2.0 Provider. + + + ===== Customizing the Access Token Response + +-On the other end, if you need to customize the post-handling of the Token Response, you will need to provide `DefaultPasswordTokenResponseClient.setRestOperations()` with a custom configured `RestOperations`. ++On the other end, if you need to customize the post-handling of the Token Response, you need to provide `DefaultPasswordTokenResponseClient.setRestOperations()` with a custom configured `RestOperations`. + The default `RestOperations` is configured as follows: + + ==== +@@ -1406,15 +1402,15 @@ restTemplate.errorHandler = OAuth2ErrorResponseErrorHandler() + ---- + ==== + +-TIP: Spring MVC `FormHttpMessageConverter` is required as it's used when sending the OAuth 2.0 Access Token Request. ++TIP: Spring MVC `FormHttpMessageConverter` is required, as it is used when sending the OAuth 2.0 Access Token Request. + + `OAuth2AccessTokenResponseHttpMessageConverter` is a `HttpMessageConverter` for an OAuth 2.0 Access Token Response. +-You can provide `OAuth2AccessTokenResponseHttpMessageConverter.setTokenResponseConverter()` with a custom `Converter, OAuth2AccessTokenResponse>` that is used for converting the OAuth 2.0 Access Token Response parameters to an `OAuth2AccessTokenResponse`. ++You can provide `OAuth2AccessTokenResponseHttpMessageConverter.setTokenResponseConverter()` with a custom `Converter, OAuth2AccessTokenResponse>` that is used to convert the OAuth 2.0 Access Token Response parameters to an `OAuth2AccessTokenResponse`. + +-`OAuth2ErrorResponseErrorHandler` is a `ResponseErrorHandler` that can handle an OAuth 2.0 Error, eg. 400 Bad Request. +-It uses an `OAuth2ErrorHttpMessageConverter` for converting the OAuth 2.0 Error parameters to an `OAuth2Error`. ++`OAuth2ErrorResponseErrorHandler` is a `ResponseErrorHandler` that can handle an OAuth 2.0 Error, such as `400 Bad Request`. ++It uses an `OAuth2ErrorHttpMessageConverter` to convert the OAuth 2.0 Error parameters to an `OAuth2Error`. + +-Whether you customize `DefaultPasswordTokenResponseClient` or provide your own implementation of `OAuth2AccessTokenResponseClient`, you'll need to configure it as shown in the following example: ++Whether you customize `DefaultPasswordTokenResponseClient` or provide your own implementation of `OAuth2AccessTokenResponseClient`, you need to configure it as follows: + + ==== + .Java +@@ -1456,7 +1452,7 @@ which is an implementation of an `OAuth2AuthorizedClientProvider` for the Resour + + ===== Using the Access Token + +-Given the following Spring Boot 2.x properties for an OAuth 2.0 Client registration: ++Consider the following Spring Boot 2.x properties for an OAuth 2.0 Client registration: + + [source,yaml] + ---- +@@ -1475,7 +1471,7 @@ spring: + token-uri: https://dev-1234.oktapreview.com/oauth2/v1/token + ---- + +-...and the `OAuth2AuthorizedClientManager` `@Bean`: ++Further consider the `OAuth2AuthorizedClientManager` `@Bean`: + + ==== + .Java +@@ -1561,7 +1557,7 @@ private fun contextAttributesMapper(): Function> and therefore inherits it's capabilities. ++The `@RegisteredOAuth2AuthorizedClient` annotation is handled by `OAuth2AuthorizedClientArgumentResolver`, which directly uses an <> and, therefore, inherits its capabilities. + + + [[oauth2Client-webclient-servlet]] +-=== WebClient integration for Servlet Environments ++=== WebClient Integration for Servlet Environments + +-The OAuth 2.0 Client support integrates with `WebClient` using an `ExchangeFilterFunction`. ++The OAuth 2.0 Client support integrates with `WebClient` by using an `ExchangeFilterFunction`. + +-The `ServletOAuth2AuthorizedClientExchangeFilterFunction` provides a simple mechanism for requesting protected resources by using an `OAuth2AuthorizedClient` and including the associated `OAuth2AccessToken` as a Bearer Token. +-It directly uses an <> and therefore inherits the following capabilities: ++The `ServletOAuth2AuthorizedClientExchangeFilterFunction` provides a mechanism for requesting protected resources by using an `OAuth2AuthorizedClient` and including the associated `OAuth2AccessToken` as a Bearer Token. ++It directly uses an <> and, therefore, inherits the following capabilities: + +-* An `OAuth2AccessToken` will be requested if the client has not yet been authorized. +-** `authorization_code` - triggers the Authorization Request redirect to initiate the flow +-** `client_credentials` - the access token is obtained directly from the Token Endpoint +-** `password` - the access token is obtained directly from the Token Endpoint +-* If the `OAuth2AccessToken` is expired, it will be refreshed (or renewed) if an `OAuth2AuthorizedClientProvider` is available to perform the authorization ++* An `OAuth2AccessToken` is requested if the client has not yet been authorized. ++** `authorization_code`: Triggers the Authorization Request redirect to initiate the flow. ++** `client_credentials`: The access token is obtained directly from the Token Endpoint. ++** `password`: The access token is obtained directly from the Token Endpoint. ++* If the `OAuth2AccessToken` is expired, it is refreshed (or renewed) if an `OAuth2AuthorizedClientProvider` is available to perform the authorization + + The following code shows an example of how to configure `WebClient` with OAuth 2.0 Client support: + +@@ -1769,9 +1767,8 @@ fun index(@RegisteredOAuth2AuthorizedClient("okta") authorizedClient: OAuth2Auth + return "index" + } + ---- +-==== +- + <1> `oauth2AuthorizedClient()` is a `static` method in `ServletOAuth2AuthorizedClientExchangeFilterFunction`. ++==== + + The following code shows how to set the `ClientRegistration.getRegistrationId()` as a request attribute: + +@@ -1817,15 +1814,14 @@ fun index(): String { + return "index" + } + ---- +-==== + <1> `clientRegistrationId()` is a `static` method in `ServletOAuth2AuthorizedClientExchangeFilterFunction`. +- ++==== + + ==== Defaulting the Authorized Client + +-If neither `OAuth2AuthorizedClient` or `ClientRegistration.getRegistrationId()` is provided as a request attribute, the `ServletOAuth2AuthorizedClientExchangeFilterFunction` can determine the _default_ client to use depending on it's configuration. ++If neither `OAuth2AuthorizedClient` or `ClientRegistration.getRegistrationId()` is provided as a request attribute, the `ServletOAuth2AuthorizedClientExchangeFilterFunction` can determine the _default_ client to use, depending on its configuration. + +-If `setDefaultOAuth2AuthorizedClient(true)` is configured and the user has authenticated using `HttpSecurity.oauth2Login()`, the `OAuth2AccessToken` associated with the current `OAuth2AuthenticationToken` is used. ++If `setDefaultOAuth2AuthorizedClient(true)` is configured and the user has authenticated by using `HttpSecurity.oauth2Login()`, the `OAuth2AccessToken` associated with the current `OAuth2AuthenticationToken` is used. + + The following code shows the specific configuration: + +@@ -1858,8 +1854,7 @@ fun webClient(authorizedClientManager: OAuth2AuthorizedClientManager?): WebClien + ---- + ==== + +-[WARNING] +-It is recommended to be cautious with this feature since all HTTP requests will receive the access token. ++WARNING: Be cautious with this feature, since all HTTP requests receive the access token. + + Alternatively, if `setDefaultClientRegistrationId("okta")` is configured with a valid `ClientRegistration`, the `OAuth2AccessToken` associated with the `OAuth2AuthorizedClient` is used. + +@@ -1894,5 +1889,4 @@ fun webClient(authorizedClientManager: OAuth2AuthorizedClientManager?): WebClien + ---- + ==== + +-[WARNING] +-It is recommended to be cautious with this feature since all HTTP requests will receive the access token. ++WARNING: Be cautious with this feature, since all HTTP requests receive the access token. +diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/oauth2/oauth2-login.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/oauth2/oauth2-login.adoc +index 24cac1e45b..b8fc76df6e 100644 +--- a/docs/manual/src/docs/asciidoc/_includes/servlet/oauth2/oauth2-login.adoc ++++ b/docs/manual/src/docs/asciidoc/_includes/servlet/oauth2/oauth2-login.adoc +@@ -1,8 +1,8 @@ + [[oauth2login]] + == OAuth 2.0 Login + +-The OAuth 2.0 Login feature provides an application with the capability to have users log in to the application by using their existing account at an OAuth 2.0 Provider (e.g. GitHub) or OpenID Connect 1.0 Provider (such as Google). +-OAuth 2.0 Login implements the use cases: "Login with Google" or "Login with GitHub". ++The OAuth 2.0 Login feature lets an application have users log in to the application by using their existing account at an OAuth 2.0 Provider (such as GitHub) or OpenID Connect 1.0 Provider (such as Google). ++OAuth 2.0 Login implements two use cases: "`Login with Google`" or "`Login with GitHub`". + + NOTE: OAuth 2.0 Login is implemented by using the *Authorization Code Grant*, as specified in the https://tools.ietf.org/html/rfc6749#section-4.1[OAuth 2.0 Authorization Framework] and https://openid.net/specs/openid-connect-core-1_0.html#CodeFlowAuth[OpenID Connect Core 1.0]. + +@@ -12,38 +12,38 @@ NOTE: OAuth 2.0 Login is implemented by using the *Authorization Code Grant*, as + + Spring Boot 2.x brings full auto-configuration capabilities for OAuth 2.0 Login. + +-This section shows how to configure the {gh-samples-url}/boot/oauth2login[*OAuth 2.0 Login sample*] using _Google_ as the _Authentication Provider_ and covers the following topics: ++This section shows how to configure the {gh-samples-url}/boot/oauth2login[*OAuth 2.0 Login sample*] by using _Google_ as the _Authentication Provider_ and covers the following topics: + +-* <> +-* <> +-* <> +-* <> ++* <> ++* <> ++* <> ++* <> + + + [[oauth2login-sample-initial-setup]] +-==== Initial setup ++==== Initial Setup + + To use Google's OAuth 2.0 authentication system for login, you must set up a project in the Google API Console to obtain OAuth 2.0 credentials. + +-NOTE: https://developers.google.com/identity/protocols/OpenIDConnect[Google's OAuth 2.0 implementation] for authentication conforms to the https://openid.net/connect/[OpenID Connect 1.0] specification and is https://openid.net/certification/[OpenID Certified]. ++NOTE: https://developers.google.com/identity/protocols/OpenIDConnect[Google's OAuth 2.0 implementation] for authentication conforms to the https://openid.net/connect/[OpenID Connect 1.0] specification and is https://openid.net/certification/[OpenID certified]. + +-Follow the instructions on the https://developers.google.com/identity/protocols/OpenIDConnect[OpenID Connect] page, starting in the section, "Setting up OAuth 2.0". ++Follow the instructions on the https://developers.google.com/identity/protocols/OpenIDConnect[OpenID Connect] page, starting in the "`Setting up OAuth 2.0`" section. + +-After completing the "Obtain OAuth 2.0 credentials" instructions, you should have a new OAuth Client with credentials consisting of a Client ID and a Client Secret. ++After completing the "`Obtain OAuth 2.0 credentials`" instructions, you should have new OAuth Client with credentials consisting of a Client ID and a Client Secret. + + + [[oauth2login-sample-redirect-uri]] +-==== Setting the redirect URI ++==== Setting the Redirect URI + +-The redirect URI is the path in the application that the end-user's user-agent is redirected back to after they have authenticated with Google and have granted access to the OAuth Client _(<>)_ on the Consent page. ++The redirect URI is the path in the application that the end-user's user-agent is redirected back to after they have authenticated with Google and have granted access to the OAuth Client (<>) on the Consent page. + +-In the "Set a redirect URI" sub-section, ensure that the *Authorized redirect URIs* field is set to `http://localhost:8080/login/oauth2/code/google`. ++In the "`Set a redirect URI`" subsection, ensure that the *Authorized redirect URIs* field is set to `http://localhost:8080/login/oauth2/code/google`. + + TIP: The default redirect URI template is `+{baseUrl}/login/oauth2/code/{registrationId}+`. +-The *_registrationId_* is a unique identifier for the <>. ++The `registrationId` is a unique identifier for the <>. + +-IMPORTANT: If the OAuth Client is running behind a proxy server, it is recommended to check <> to ensure the application is correctly configured. +-Also, see the supported <> for `redirect-uri`. ++IMPORTANT: If the OAuth Client runs behind a proxy server, you should check the <> to ensure the application is correctly configured. ++Also, see the supported <> for `redirect-uri`. + + + [[oauth2login-sample-application-config]] +@@ -69,21 +69,21 @@ spring: + .OAuth Client properties + ==== + <1> `spring.security.oauth2.client.registration` is the base property prefix for OAuth Client properties. +-<2> Following the base property prefix is the ID for the <>, such as google. ++<2> Following the base property prefix is the ID for the <>, such as Google. + ==== + + . Replace the values in the `client-id` and `client-secret` property with the OAuth 2.0 credentials you created earlier. + + + [[oauth2login-sample-boot-application]] +-==== Boot up the application ++==== Boot up the Application + + Launch the Spring Boot 2.x sample and go to `http://localhost:8080`. + You are then redirected to the default _auto-generated_ login page, which displays a link for Google. + + Click on the Google link, and you are then redirected to Google for authentication. + +-After authenticating with your Google account credentials, the next page presented to you is the Consent screen. ++After authenticating with your Google account credentials, you see the Consent screen. + The Consent screen asks you to either allow or deny access to the OAuth Client you created earlier. + Click *Allow* to authorize the OAuth Client to access your email address and basic profile information. + +@@ -144,8 +144,7 @@ The following table outlines the mapping of the Spring Boot 2.x OAuth Client pro + |`providerDetails.userInfoEndpoint.userNameAttributeName` + |=== + +-[TIP] +-A `ClientRegistration` can be initially configured using discovery of an OpenID Connect Provider's https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfig[Configuration endpoint] or an Authorization Server's https://tools.ietf.org/html/rfc8414#section-3[Metadata endpoint], by specifying the `spring.security.oauth2.client.provider._[providerId]_.issuer-uri` property. ++TIP: You can initially configure a `ClientRegistration` by using discovery of an OpenID Connect Provider's https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfig[Configuration endpoint] or an Authorization Server's https://tools.ietf.org/html/rfc8414#section-3[Metadata endpoint], by specifying the `spring.security.oauth2.client.provider._[providerId]_.issuer-uri` property. + + + [[oauth2login-common-oauth2-provider]] +@@ -153,13 +152,14 @@ A `ClientRegistration` can be initially configured using discovery of an OpenID + + `CommonOAuth2Provider` pre-defines a set of default client properties for a number of well known providers: Google, GitHub, Facebook, and Okta. + +-For example, the `authorization-uri`, `token-uri`, and `user-info-uri` do not change often for a Provider. +-Therefore, it makes sense to provide default values in order to reduce the required configuration. ++For example, the `authorization-uri`, `token-uri`, and `user-info-uri` do not change often for a provider. ++Therefore, it makes sense to provide default values, to reduce the required configuration. + + As demonstrated previously, when we <>, only the `client-id` and `client-secret` properties are required. + + The following listing shows an example: + ++==== + [source,yaml] + ---- + spring: +@@ -171,6 +171,7 @@ spring: + client-id: google-client-id + client-secret: google-client-secret + ---- ++==== + + [TIP] + The auto-defaulting of client properties works seamlessly here because the `registrationId` (`google`) matches the `GOOGLE` `enum` (case-insensitive) in `CommonOAuth2Provider`. +@@ -179,6 +180,7 @@ For cases where you may want to specify a different `registrationId`, such as `g + + The following listing shows an example: + ++==== + [source,yaml] + ---- + spring: +@@ -192,8 +194,8 @@ spring: + client-secret: google-client-secret + ---- + <1> The `registrationId` is set to `google-login`. +-<2> The `provider` property is set to `google`, which will leverage the auto-defaulting of client properties set in `CommonOAuth2Provider.GOOGLE.getBuilder()`. +- ++<2> The `provider` property is set to `google`, which uses the auto-defaulting of client properties set in `CommonOAuth2Provider.GOOGLE.getBuilder()`. ++==== + + [[oauth2login-custom-provider-properties]] + === Configuring Custom Provider Properties +@@ -206,6 +208,7 @@ For these cases, Spring Boot 2.x provides the following base property for config + + The following listing shows an example: + ++==== + [source,yaml] + ---- + spring: +@@ -224,9 +227,8 @@ spring: + user-name-attribute: sub + jwk-set-uri: https://your-subdomain.oktapreview.com/oauth2/v1/keys + ---- +- + <1> The base property (`spring.security.oauth2.client.provider.okta`) allows for custom configuration of protocol endpoint locations. +- ++==== + + [[oauth2login-override-boot-autoconfig]] + === Overriding Spring Boot 2.x Auto-configuration +@@ -240,9 +242,9 @@ It performs the following tasks: + + If you need to override the auto-configuration based on your specific requirements, you may do so in the following ways: + +-* <> +-* <> +-* <> ++* <> ++* <> ++* <> + + + [[oauth2login-register-clientregistrationrepository-bean]] +@@ -600,14 +602,14 @@ The main goal of the `oauth2Login()` DSL was to closely align with the naming, a + + The OAuth 2.0 Authorization Framework defines the https://tools.ietf.org/html/rfc6749#section-3[Protocol Endpoints] as follows: + +-The authorization process utilizes two authorization server endpoints (HTTP resources): ++The authorization process uses two authorization server endpoints (HTTP resources): + +-* Authorization Endpoint: Used by the client to obtain authorization from the resource owner via user-agent redirection. ++* Authorization Endpoint: Used by the client to obtain authorization from the resource owner through user-agent redirection. + * Token Endpoint: Used by the client to exchange an authorization grant for an access token, typically with client authentication. + +-As well as one client endpoint: ++The authorization process also uses one client endpoint: + +-* Redirection Endpoint: Used by the authorization server to return responses containing authorization credentials to the client via the resource owner user-agent. ++* Redirection Endpoint: Used by the authorization server to return responses that contain authorization credentials to the client through the resource owner user-agent. + + The OpenID Connect Core 1.0 specification defines the https://openid.net/specs/openid-connect-core-1_0.html#UserInfo[UserInfo Endpoint] as follows: + +@@ -719,9 +721,9 @@ The following code shows the complete configuration options available in the <> +-* <> +-* <> ++* <> ++* <> ++* <> + + + [[oauth2login-advanced-login-page]] +@@ -730,8 +732,7 @@ The following sections go into more detail on each of the configuration options + By default, the OAuth 2.0 Login Page is auto-generated by the `DefaultLoginPageGeneratingFilter`. + The default login page shows each configured OAuth Client with its `ClientRegistration.clientName` as a link, which is capable of initiating the Authorization Request (or OAuth 2.0 Login). + +-[NOTE] +-In order for `DefaultLoginPageGeneratingFilter` to show links for configured OAuth Clients, the registered `ClientRegistrationRepository` needs to also implement `Iterable`. ++NOTE: For `DefaultLoginPageGeneratingFilter` to show links for configured OAuth Clients, the registered `ClientRegistrationRepository` needs to also implement `Iterable`. + See `InMemoryClientRegistrationRepository` for reference. + + The link's destination for each OAuth Client defaults to the following: +@@ -740,10 +741,12 @@ The link's destination for each OAuth Client defaults to the following: + + The following line shows an example: + ++==== + [source,html] + ---- + Google + ---- ++==== + + To override the default login page, configure `oauth2Login().loginPage()` and (optionally) `oauth2Login().authorizationEndpoint().baseUri()`. + +@@ -802,35 +805,35 @@ class OAuth2LoginSecurityConfig : WebSecurityConfigurerAdapter() { + ---- + ==== + +-[IMPORTANT] +-You need to provide a `@Controller` with a `@RequestMapping("/login/oauth2")` that is capable of rendering the custom login page. ++IMPORTANT: You need to provide a `@Controller` with a `@RequestMapping("/login/oauth2")` that is capable of rendering the custom login page. + + [TIP] +-==== ++===== + As noted earlier, configuring `oauth2Login().authorizationEndpoint().baseUri()` is optional. + However, if you choose to customize it, ensure the link to each OAuth Client matches the `authorizationEndpoint().baseUri()`. + + The following line shows an example: + ++==== + [source,html] + ---- + Google + ---- + ==== ++===== + + + [[oauth2login-advanced-redirection-endpoint]] + ==== Redirection Endpoint + +-The Redirection Endpoint is used by the Authorization Server for returning the Authorization Response (which contains the authorization credentials) to the client via the Resource Owner user-agent. ++The Redirection Endpoint is used by the Authorization Server for returning the Authorization Response (which contains the authorization credentials) to the client through the Resource Owner user-agent. + +-[TIP] +-OAuth 2.0 Login leverages the Authorization Code Grant. ++TIP: OAuth 2.0 Login leverages the Authorization Code Grant. + Therefore, the authorization credential is the authorization code. + + The default Authorization Response `baseUri` (redirection endpoint) is `*/login/oauth2/code/**`, which is defined in `OAuth2LoginAuthenticationFilter.DEFAULT_FILTER_PROCESSES_URI`. + +-If you would like to customize the Authorization Response `baseUri`, configure it as shown in the following example: ++If you would like to customize the Authorization Response `baseUri`, configure it as follows: + + .Redirection Endpoint Configuration + ==== +@@ -883,11 +886,12 @@ class OAuth2LoginSecurityConfig : WebSecurityConfigurerAdapter() { + ==== + + [IMPORTANT] +-==== ++===== + You also need to ensure the `ClientRegistration.redirectUri` matches the custom Authorization Response `baseUri`. + + The following listing shows an example: + ++==== + .Java + [source,java,role="primary",attrs="-attributes"] + ---- +@@ -908,36 +912,36 @@ return CommonOAuth2Provider.GOOGLE.getBuilder("google") + .build() + ---- + ==== +- ++===== + + [[oauth2login-advanced-userinfo-endpoint]] + ==== UserInfo Endpoint + + The UserInfo Endpoint includes a number of configuration options, as described in the following sub-sections: + +-* <> +-* <> +-* <> ++* <> ++* <> ++* <> + + + [[oauth2login-advanced-map-authorities]] + ===== Mapping User Authorities + +-After the user successfully authenticates with the OAuth 2.0 Provider, the `OAuth2User.getAuthorities()` (or `OidcUser.getAuthorities()`) may be mapped to a new set of `GrantedAuthority` instances, which will be supplied to `OAuth2AuthenticationToken` when completing the authentication. ++After the user successfully authenticates with the OAuth 2.0 Provider, the `OAuth2User.getAuthorities()` (or `OidcUser.getAuthorities()`) can be mapped to a new set of `GrantedAuthority` instances, which are supplied to `OAuth2AuthenticationToken` when completing the authentication. + + [TIP] + `OAuth2AuthenticationToken.getAuthorities()` is used for authorizing requests, such as in `hasRole('USER')` or `hasRole('ADMIN')`. + + There are a couple of options to choose from when mapping user authorities: + +-* <> +-* <> ++* <> ++* <> + + + [[oauth2login-advanced-map-authorities-grantedauthoritiesmapper]] + ====== Using a GrantedAuthoritiesMapper + +-Provide an implementation of `GrantedAuthoritiesMapper` and configure it as shown in the following example: ++Provide an implementation of `GrantedAuthoritiesMapper` and configure it, as follows: + + .Granted Authorities Mapper Configuration + ==== +@@ -1037,7 +1041,7 @@ class OAuth2LoginSecurityConfig : WebSecurityConfigurerAdapter() { + ---- + ==== + +-Alternatively, you may register a `GrantedAuthoritiesMapper` `@Bean` to have it automatically applied to the configuration, as shown in the following example: ++Alternatively, you can register a `GrantedAuthoritiesMapper` `@Bean` to have it automatically applied to the configuration, as follows: + + .Granted Authorities Mapper Bean Configuration + ==== +@@ -1081,11 +1085,11 @@ class OAuth2LoginSecurityConfig : WebSecurityConfigurerAdapter() { + ==== + + [[oauth2login-advanced-map-authorities-oauth2userservice]] +-====== Delegation-based strategy with OAuth2UserService ++====== Delegation-based Strategy with OAuth2UserService + +-This strategy is advanced compared to using a `GrantedAuthoritiesMapper`, however, it's also more flexible as it gives you access to the `OAuth2UserRequest` and `OAuth2User` (when using an OAuth 2.0 UserService) or `OidcUserRequest` and `OidcUser` (when using an OpenID Connect 1.0 UserService). ++This strategy is advanced compared to using a `GrantedAuthoritiesMapper`. However, it is also more flexible, as it gives you access to the `OAuth2UserRequest` and `OAuth2User` (when using an OAuth 2.0 UserService) or `OidcUserRequest` and `OidcUser` (when using an OpenID Connect 1.0 UserService). + +-The `OAuth2UserRequest` (and `OidcUserRequest`) provides you access to the associated `OAuth2AccessToken`, which is very useful in the cases where the _delegator_ needs to fetch authority information from a protected resource before it can map the custom authorities for the user. ++The `OAuth2UserRequest` (and `OidcUserRequest`) provides you access to the associated `OAuth2AccessToken`, which is very useful in cases where the _delegator_ needs to fetch authority information from a protected resource before it can map the custom authorities for the user. + + The following example shows how to implement and configure a delegation-based strategy using an OpenID Connect 1.0 UserService: + +@@ -1187,27 +1191,28 @@ class OAuth2LoginSecurityConfig : WebSecurityConfigurerAdapter() { + + `DefaultOAuth2UserService` is an implementation of an `OAuth2UserService` that supports standard OAuth 2.0 Provider's. + +-[NOTE] +-`OAuth2UserService` obtains the user attributes of the end-user (the resource owner) from the UserInfo Endpoint (by using the access token granted to the client during the authorization flow) and returns an `AuthenticatedPrincipal` in the form of an `OAuth2User`. ++NOTE: `OAuth2UserService` obtains the user attributes of the end-user (the resource owner) from the UserInfo Endpoint (by using the access token granted to the client during the authorization flow) and returns an `AuthenticatedPrincipal` in the form of an `OAuth2User`. + +-`DefaultOAuth2UserService` uses a `RestOperations` when requesting the user attributes at the UserInfo Endpoint. ++`DefaultOAuth2UserService` uses a `RestOperations` instance when requesting the user attributes at the UserInfo Endpoint. + + If you need to customize the pre-processing of the UserInfo Request, you can provide `DefaultOAuth2UserService.setRequestEntityConverter()` with a custom `Converter>`. + The default implementation `OAuth2UserRequestEntityConverter` builds a `RequestEntity` representation of a UserInfo Request that sets the `OAuth2AccessToken` in the `Authorization` header by default. + +-On the other end, if you need to customize the post-handling of the UserInfo Response, you will need to provide `DefaultOAuth2UserService.setRestOperations()` with a custom configured `RestOperations`. ++On the other end, if you need to customize the post-handling of the UserInfo Response, you need to provide `DefaultOAuth2UserService.setRestOperations()` with a custom configured `RestOperations`. + The default `RestOperations` is configured as follows: + ++==== + [source,java] + ---- + RestTemplate restTemplate = new RestTemplate(); + restTemplate.setErrorHandler(new OAuth2ErrorResponseErrorHandler()); + ---- ++==== + + `OAuth2ErrorResponseErrorHandler` is a `ResponseErrorHandler` that can handle an OAuth 2.0 Error (400 Bad Request). + It uses an `OAuth2ErrorHttpMessageConverter` for converting the OAuth 2.0 Error parameters to an `OAuth2Error`. + +-Whether you customize `DefaultOAuth2UserService` or provide your own implementation of `OAuth2UserService`, you'll need to configure it as shown in the following example: ++Whether you customize `DefaultOAuth2UserService` or provide your own implementation of `OAuth2UserService`, you need to configure it as follows: + + ==== + .Java +@@ -1265,9 +1270,9 @@ class OAuth2LoginSecurityConfig : WebSecurityConfigurerAdapter() { + + The `OidcUserService` leverages the `DefaultOAuth2UserService` when requesting the user attributes at the UserInfo Endpoint. + +-If you need to customize the pre-processing of the UserInfo Request and/or the post-handling of the UserInfo Response, you will need to provide `OidcUserService.setOauth2UserService()` with a custom configured `DefaultOAuth2UserService`. ++If you need to customize the pre-processing of the UserInfo Request or the post-handling of the UserInfo Response, you need to provide `OidcUserService.setOauth2UserService()` with a custom configured `DefaultOAuth2UserService`. + +-Whether you customize `OidcUserService` or provide your own implementation of `OAuth2UserService` for OpenID Connect 1.0 Provider's, you'll need to configure it as shown in the following example: ++Whether you customize `OidcUserService` or provide your own implementation of `OAuth2UserService` for OpenID Connect 1.0 Provider's, you need to configure it as follows: + + ==== + .Java +@@ -1323,14 +1328,14 @@ class OAuth2LoginSecurityConfig : WebSecurityConfigurerAdapter() { + + OpenID Connect 1.0 Authentication introduces the https://openid.net/specs/openid-connect-core-1_0.html#IDToken[ID Token], which is a security token that contains Claims about the Authentication of an End-User by an Authorization Server when used by a Client. + +-The ID Token is represented as a https://tools.ietf.org/html/rfc7519[JSON Web Token] (JWT) and MUST be signed using https://tools.ietf.org/html/rfc7515[JSON Web Signature] (JWS). ++The ID Token is represented as a https://tools.ietf.org/html/rfc7519[JSON Web Token] (JWT) and MUST be signed by using https://tools.ietf.org/html/rfc7515[JSON Web Signature] (JWS). + + The `OidcIdTokenDecoderFactory` provides a `JwtDecoder` used for `OidcIdToken` signature verification. The default algorithm is `RS256` but may be different when assigned during client registration. +-For these cases, a resolver may be configured to return the expected JWS algorithm assigned for a specific client. ++For these cases, you can configure a resolver to return the expected JWS algorithm assigned for a specific client. + +-The JWS algorithm resolver is a `Function` that accepts a `ClientRegistration` and returns the expected `JwsAlgorithm` for the client, eg. `SignatureAlgorithm.RS256` or `MacAlgorithm.HS256` ++The JWS algorithm resolver is a `Function` that accepts a `ClientRegistration` and returns the expected `JwsAlgorithm` for the client, such as `SignatureAlgorithm.RS256` or `MacAlgorithm.HS256` + +-The following code shows how to configure the `OidcIdTokenDecoderFactory` `@Bean` to default to `MacAlgorithm.HS256` for all `ClientRegistration`: ++The following code shows how to configure the `OidcIdTokenDecoderFactory` `@Bean` to default to `MacAlgorithm.HS256` for all `ClientRegistration` instances: + + ==== + .Java +@@ -1356,22 +1361,21 @@ fun idTokenDecoderFactory(): JwtDecoderFactory { + ---- + ==== + +-[NOTE] +-For MAC based algorithms such as `HS256`, `HS384` or `HS512`, the `client-secret` corresponding to the `client-id` is used as the symmetric key for signature verification. ++NOTE: For MAC-based algorithms (such as `HS256`, `HS384`, or `HS512`), the `client-secret` that corresponds to the `client-id` is used as the symmetric key for signature verification. + +-[TIP] +-If more than one `ClientRegistration` is configured for OpenID Connect 1.0 Authentication, the JWS algorithm resolver may evaluate the provided `ClientRegistration` to determine which algorithm to return. ++TIP: If more than one `ClientRegistration` is configured for OpenID Connect 1.0 Authentication, the JWS algorithm resolver may evaluate the provided `ClientRegistration` to determine which algorithm to return. + + + [[oauth2login-advanced-oidc-logout]] + ==== OpenID Connect 1.0 Logout + +-OpenID Connect Session Management 1.0 allows the ability to log out the End-User at the Provider using the Client. ++OpenID Connect Session Management 1.0 allows the ability to log out the end user at the Provider by using the Client. + One of the strategies available is https://openid.net/specs/openid-connect-session-1_0.html#RPLogout[RP-Initiated Logout]. + +-If the OpenID Provider supports both Session Management and https://openid.net/specs/openid-connect-discovery-1_0.html[Discovery], the client may obtain the `end_session_endpoint` `URL` from the OpenID Provider's https://openid.net/specs/openid-connect-session-1_0.html#OPMetadata[Discovery Metadata]. +-This can be achieved by configuring the `ClientRegistration` with the `issuer-uri`, as in the following example: ++If the OpenID Provider supports both Session Management and https://openid.net/specs/openid-connect-discovery-1_0.html[Discovery], the client can obtain the `end_session_endpoint` `URL` from the OpenID Provider's https://openid.net/specs/openid-connect-session-1_0.html#OPMetadata[Discovery Metadata]. ++You can do so by configuring the `ClientRegistration` with the `issuer-uri`, as follows: + ++==== + [source,yaml] + ---- + spring: +@@ -1387,8 +1391,9 @@ spring: + okta: + issuer-uri: https://dev-1234.oktapreview.com + ---- ++==== + +-...and the `OidcClientInitiatedLogoutSuccessHandler`, which implements RP-Initiated Logout, may be configured as follows: ++Also, you can configure `OidcClientInitiatedLogoutSuccessHandler`, which implements RP-Initiated Logout, as follows: + + ==== + .Java +@@ -1424,10 +1429,11 @@ public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter { + } + } + +-NOTE: `OidcClientInitiatedLogoutSuccessHandler` supports the `{baseUrl}` placeholder. +-If used, the application's base URL, like `https://app.example.org`, will replace it at request time. + ---- + ++NOTE: `OidcClientInitiatedLogoutSuccessHandler` supports the `{baseUrl}` placeholder. ++If used, the application's base URL, such as `https://app.example.org`, replaces it at request time. ++ + .Kotlin + [source,kotlin,role="secondary"] + ---- +@@ -1458,7 +1464,7 @@ class OAuth2LoginSecurityConfig : WebSecurityConfigurerAdapter() { + } + } + +-NOTE: `OidcClientInitiatedLogoutSuccessHandler` supports the `{baseUrl}` placeholder. +-If used, the application's base URL, like `https://app.example.org`, will replace it at request time. + ---- ++NOTE: `OidcClientInitiatedLogoutSuccessHandler` supports the `{baseUrl}` placeholder. ++If used, the application's base URL, such as `https://app.example.org`, replaces it at request time. + ==== +diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/oauth2/oauth2-resourceserver.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/oauth2/oauth2-resourceserver.adoc +index b4e520c767..43502bc971 100644 +--- a/docs/manual/src/docs/asciidoc/_includes/servlet/oauth2/oauth2-resourceserver.adoc ++++ b/docs/manual/src/docs/asciidoc/_includes/servlet/oauth2/oauth2-resourceserver.adoc +@@ -1,9 +1,9 @@ +-[[oauth2resourceserver]] ++NML.[[oauth2resourceserver]] + == OAuth 2.0 Resource Server + :figures: images/servlet/oauth2 + :icondir: images/icons + +-Spring Security supports protecting endpoints using two forms of OAuth 2.0 https://tools.ietf.org/html/rfc6750.html[Bearer Tokens]: ++Spring Security supports protecting endpoints BY using two forms of OAuth 2.0 https://tools.ietf.org/html/rfc6750.html[Bearer Tokens]: + + * https://tools.ietf.org/html/rfc7519[JWT] + * Opaque Tokens +@@ -11,42 +11,37 @@ Spring Security supports protecting endpoints using two forms of OAuth 2.0 https + This is handy in circumstances where an application has delegated its authority management to an https://tools.ietf.org/html/rfc6749[authorization server] (for example, Okta or Ping Identity). + This authorization server can be consulted by resource servers to authorize requests. + +-This section provides details on how Spring Security provides support for OAuth 2.0 https://tools.ietf.org/html/rfc6750.html[Bearer Tokens]. ++This section details how Spring Security provides support for OAuth 2.0 https://tools.ietf.org/html/rfc6750.html[Bearer Tokens]. + +-[NOTE] +-==== +-Working samples for both {gh-samples-url}/boot/oauth2resourceserver[JWTs] and {gh-samples-url}/boot/oauth2resourceserver-opaque[Opaque Tokens] are available in the {gh-samples-url}[Spring Security repository]. +-==== ++NOTE: Working samples for both {gh-samples-url}/boot/oauth2resourceserver[JWTs] and {gh-samples-url}/boot/oauth2resourceserver-opaque[Opaque Tokens] are available in the {gh-samples-url}[Spring Security repository]. + +-Let's take a look at how Bearer Token Authentication works within Spring Security. +-First, we see that, like <>, the https://tools.ietf.org/html/rfc7235#section-4.1[WWW-Authenticate] header is sent back to an unauthenticated client. ++Now we can consider how Bearer Token Authentication works within Spring Security. ++First, we see that, as with <>, the https://tools.ietf.org/html/rfc7235#section-4.1[WWW-Authenticate] header is sent back to an unauthenticated client: + + .Sending WWW-Authenticate Header + image::{figures}/bearerauthenticationentrypoint.png[] + +-The figure above builds off our <> diagram. ++image:{icondir}/number_1.png[] First, a user makes an unauthenticated request to the `/private` resource for which the user is not authorized. + +-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 <> indicates that the unauthenticated request is _Denied_ by throwing an `AccessDeniedException`. + +-image:{icondir}/number_2.png[] Spring Security's <> indicates that the unauthenticated request is __Denied__ by throwing an `AccessDeniedException`. ++image:{icondir}/number_3.png[] Since the user is not authenticated, <> initiates _Start Authentication_. ++The configured <> is an instance of {security-api-url}org/springframework/security/oauth2/server/resource/authentication/BearerTokenAuthenticationEntryPoint.html[`BearerTokenAuthenticationEntryPoint`], which sends a `WWW-Authenticate` header. ++The `RequestCache` is typically a `NullRequestCache` that does not save the request, since the client is capable of replaying the requests it originally requested. + +-image:{icondir}/number_3.png[] Since the user is not authenticated, <> initiates __Start Authentication__. +-The configured <> is an instance of {security-api-url}org/springframework/security/oauth2/server/resource/authentication/BearerTokenAuthenticationEntryPoint.html[`BearerTokenAuthenticationEntryPoint`] which sends a WWW-Authenticate header. +-The `RequestCache` is typically a `NullRequestCache` that does not save the request since the client is capable of replaying the requests it originally requested. ++NOTE: The preceding figure builds off of our <> diagram. + + When a client receives the `WWW-Authenticate: Bearer` header, it knows it should retry with a bearer token. +-Below is the flow for the bearer token being processed. ++The following image shows the flow for the bearer token being processed: + + [[oauth2resourceserver-authentication-bearertokenauthenticationfilter]] + .Authenticating Bearer Token + image::{figures}/bearertokenauthenticationfilter.png[] + +-The figure builds off our <> diagram. +- +-image:{icondir}/number_1.png[] When the user submits their bearer token, the `BearerTokenAuthenticationFilter` creates a `BearerTokenAuthenticationToken` which is a type of <> by extracting the token from the `HttpServletRequest`. ++image:{icondir}/number_1.png[] When the user submits their bearer token, the `BearerTokenAuthenticationFilter` creates a `BearerTokenAuthenticationToken`, which is a type of <>, by extracting the token from the `HttpServletRequest`. + + image:{icondir}/number_2.png[] Next, the `HttpServletRequest` is passed to the `AuthenticationManagerResolver`, which selects the `AuthenticationManager`. The `BearerTokenAuthenticationToken` is passed into the `AuthenticationManager` to be authenticated. +-The details of what `AuthenticationManager` looks like depends on whether you're configured for <> or <>. ++The details of what `AuthenticationManager` looks like depends on whether you configured for <> or an <>. + + image:{icondir}/number_3.png[] If authentication fails, then __Failure__ + +@@ -58,22 +53,27 @@ image:{icondir}/number_4.png[] If authentication is successful, then __Success__ + * The <> is set on the <>. + * The `BearerTokenAuthenticationFilter` invokes `FilterChain.doFilter(request,response)` to continue with the rest of the application logic. + ++NOTE: The preceding figure builds off our <> diagram. ++ + [[oauth2resourceserver-jwt-minimaldependencies]] + === Minimal Dependencies for JWT + + Most Resource Server support is collected into `spring-security-oauth2-resource-server`. +-However, the support for decoding and verifying JWTs is in `spring-security-oauth2-jose`, meaning that both are necessary in order to have a working resource server that supports JWT-encoded Bearer Tokens. ++However, the support for decoding and verifying JWTs is in `spring-security-oauth2-jose`, meaning that both are necessary to have a working resource server that supports JWT-encoded Bearer Tokens. + + [[oauth2resourceserver-jwt-minimalconfiguration]] + === Minimal Configuration for JWTs + + When using https://spring.io/projects/spring-boot[Spring Boot], configuring an application as a resource server consists of two basic steps. +-First, include the needed dependencies and second, indicate the location of the authorization server. ++ ++. Include the needed dependencies. ++. Indicate the location of the authorization server. + + ==== Specifying the Authorization Server + +-In a Spring Boot application, to specify which authorization server to use, simply do: ++In a Spring Boot application, to specify which authorization server to use, you can use a YAML file similar to the following: + ++==== + [source,yml] + ---- + spring: +@@ -81,94 +81,93 @@ spring: + oauth2: + resourceserver: + jwt: +- issuer-uri: https://idp.example.com/issuer ++ issuer-uri: https://idp.example.com/issuer <1> + ---- ++<1> `https://idp.example.com/issuer` is the value contained in the `iss` claim for JWT tokens that the authorization server issues. ++==== + +-Where `https://idp.example.com/issuer` is the value contained in the `iss` claim for JWT tokens that the authorization server will issue. +-Resource Server will use this property to further self-configure, discover the authorization server's public keys, and subsequently validate incoming JWTs. ++Resource Server uses this property to further self-configure, discover the authorization server's public keys, and, subsequently, validate incoming JWTs. + +-[NOTE] +-To use the `issuer-uri` property, it must also be true that one of `https://idp.example.com/issuer/.well-known/openid-configuration`, `https://idp.example.com/.well-known/openid-configuration/issuer`, or `https://idp.example.com/.well-known/oauth-authorization-server/issuer` is a supported endpoint for the authorization server. ++NOTE: To use the `issuer-uri` property, it must also be true that one of `https://idp.example.com/issuer/.well-known/openid-configuration`, `https://idp.example.com/.well-known/openid-configuration/issuer`, or `https://idp.example.com/.well-known/oauth-authorization-server/issuer` is a supported endpoint for the authorization server. + This endpoint is referred to as a https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfig[Provider Configuration] endpoint or a https://tools.ietf.org/html/rfc8414#section-3[Authorization Server Metadata] endpoint. + +-And that's it! +- + ==== Startup Expectations + +-When this property and these dependencies are used, Resource Server will automatically configure itself to validate JWT-encoded Bearer Tokens. ++When this property and these dependencies are used, Resource Server automatically configures itself to validate JWT-encoded Bearer Tokens. + + It achieves this through a deterministic startup process: + +-1. Query the Provider Configuration or Authorization Server Metadata endpoint for the `jwks_url` property +-2. Query the `jwks_url` endpoint for supported algorithms +-3. Configure the validation strategy to query `jwks_url` for valid public keys of the algorithms found +-4. Configure the validation strategy to validate each JWTs `iss` claim against `https://idp.example.com`. ++. Query the Provider Configuration or Authorization Server Metadata endpoint for the `jwks_url` property. ++. Query the `jwks_url` endpoint for supported algorithms. ++. Configure the validation strategy to query `jwks_url` for valid public keys of the algorithms found. ++. Configure the validation strategy to validate each JWTs `iss` claim against `https://idp.example.com`. + +-A consequence of this process is that the authorization server must be up and receiving requests in order for Resource Server to successfully start up. ++A consequence of this process is that the authorization server must be up and receiving requests for Resource Server to successfully start up. + +-[NOTE] +-If the authorization server is down when Resource Server queries it (given appropriate timeouts), then startup will fail. ++NOTE: If the authorization server is down when Resource Server queries it (given appropriate timeouts), startup fails. + + ==== Runtime Expectations + +-Once the application is started up, Resource Server will attempt to process any request containing an `Authorization: Bearer` header: ++Once the application has started, Resource Server tries to process any request containing an `Authorization: Bearer` header: + ++==== + [source,html] + ---- + GET / HTTP/1.1 + Authorization: Bearer some-token-value # Resource Server will process this + ---- ++==== + +-So long as this scheme is indicated, Resource Server will attempt to process the request according to the Bearer Token specification. ++So long as this scheme is indicated, Resource Server tries to process the request, according to the Bearer Token specification. + +-Given a well-formed JWT, Resource Server will: ++Given a well-formed JWT, Resource Server: + +-1. Validate its signature against a public key obtained from the `jwks_url` endpoint during startup and matched against the JWT +-2. Validate the JWT's `exp` and `nbf` timestamps and the JWT's `iss` claim, and +-3. Map each scope to an authority with the prefix `SCOPE_`. ++. Validates its signature against a public key obtained from the `jwks_url` endpoint during startup and matched against the JWT. ++. Validates the JWT's `exp` and `nbf` timestamps and the JWT's `iss` claim. ++. Maps each scope to an authority with the prefix `SCOPE_`. + +-[NOTE] +-As the authorization server makes available new keys, Spring Security will automatically rotate the keys used to validate JWTs. ++NOTE: As the authorization server makes available new keys, Spring Security automatically rotates the keys used to validate JWTs. + + The resulting `Authentication#getPrincipal`, by default, is a Spring Security `Jwt` object, and `Authentication#getName` maps to the JWT's `sub` property, if one is present. + + From here, consider jumping to: + +-* <> ++* <> + * <> + * <> + + [[oauth2resourceserver-jwt-architecture]] + === How JWT Authentication Works + +-Next, let's see the architectural components that Spring Security uses to support https://tools.ietf.org/html/rfc7519[JWT] Authentication in servlet-based applications, like the one we just saw. ++Next, we consider the architectural components that Spring Security uses to support https://tools.ietf.org/html/rfc7519[JWT] Authentication in servlet-based applications, like the one we just saw. + +-{security-api-url}org/springframework/security/oauth2/server/resource/authentication/JwtAuthenticationProvider.html[`JwtAuthenticationProvider`] is an <> implementation that leverages a <> and <> to authenticate a JWT. ++{security-api-url}org/springframework/security/oauth2/server/resource/authentication/JwtAuthenticationProvider.html[`JwtAuthenticationProvider`] is an <> implementation that uses a <> and <> to authenticate a JWT. + +-Let's take a look at how `JwtAuthenticationProvider` works within Spring Security. +-The figure explains details of how the <> in figures from <> works. ++Now we can examine how `JwtAuthenticationProvider` works within Spring Security. ++The following figure details how the <> in other figures (from <>) works. + + .`JwtAuthenticationProvider` Usage + image::{figures}/jwtauthenticationprovider.png[] + +-image:{icondir}/number_1.png[] The authentication `Filter` from <> passes a `BearerTokenAuthenticationToken` to the `AuthenticationManager` which is implemented by <>. ++image:{icondir}/number_1.png[] The authentication `Filter` from <> passes a `BearerTokenAuthenticationToken` to the `AuthenticationManager`, which is implemented by <>. + + image:{icondir}/number_2.png[] The `ProviderManager` is configured to use an <> of type `JwtAuthenticationProvider`. + + [[oauth2resourceserver-jwt-architecture-jwtdecoder]] +-image:{icondir}/number_3.png[] `JwtAuthenticationProvider` decodes, verifies, and validates the `Jwt` using a <>. ++image:{icondir}/number_3.png[] `JwtAuthenticationProvider` decodes, verifies, and validates the `Jwt` by using a <>. + + [[oauth2resourceserver-jwt-architecture-jwtauthenticationconverter]] + image:{icondir}/number_4.png[] `JwtAuthenticationProvider` then uses the <> to convert the `Jwt` into a `Collection` of granted authorities. + + image:{icondir}/number_5.png[] When authentication is successful, the <> that is returned is of type `JwtAuthenticationToken` and has a principal that is the `Jwt` returned by the configured `JwtDecoder`. +-Ultimately, the returned `JwtAuthenticationToken` will be set on the <> by the authentication `Filter`. ++Ultimately, the returned `JwtAuthenticationToken` is set on the <> by the authentication `Filter`. + + [[oauth2resourceserver-jwt-jwkseturi]] + === Specifying the Authorization Server JWK Set Uri Directly + +-If the authorization server doesn't support any configuration endpoints, or if Resource Server must be able to start up independently from the authorization server, then the `jwk-set-uri` can be supplied as well: ++If the authorization server does not support any configuration endpoints or if Resource Server must be able to start up independently from the authorization server, you can supply the `jwk-set-uri` as well: + ++==== + [source,yaml] + ---- + spring: +@@ -179,22 +178,21 @@ spring: + issuer-uri: https://idp.example.com + jwk-set-uri: https://idp.example.com/.well-known/jwks.json + ---- ++==== + +-[NOTE] +-The JWK Set uri is not standardized, but can typically be found in the authorization server's documentation ++NOTE: The JWK Set URI is not standardized, but you can typically find it in the authorization server's documentation. + +-Consequently, Resource Server will not ping the authorization server at startup. ++Consequently, Resource Server does not ping the authorization server at startup. + We still specify the `issuer-uri` so that Resource Server still validates the `iss` claim on incoming JWTs. + +-[NOTE] +-This property can also be supplied directly on the <>. ++NOTE: You can also supply this property directly on the <>. + + [[oauth2resourceserver-jwt-sansboot]] + === Overriding or Replacing Boot Auto Configuration + +-There are two `@Bean` s that Spring Boot generates on Resource Server's behalf. ++There are two `@Bean` instances that Spring Boot generates on Resource Server's behalf. + +-The first is a `WebSecurityConfigurerAdapter` that configures the app as a resource server. When including `spring-security-oauth2-jose`, this `WebSecurityConfigurerAdapter` looks like: ++The first is a `WebSecurityConfigurerAdapter` that configures the application as a resource server. When you include `spring-security-oauth2-jose`, this `WebSecurityConfigurerAdapter` looks like: + + .Default JWT Configuration + ==== +@@ -226,7 +224,7 @@ fun configure(http: HttpSecurity) { + ---- + ==== + +-If the application doesn't expose a `WebSecurityConfigurerAdapter` bean, then Spring Boot will expose the above default one. ++If the application does not expose a `WebSecurityConfigurerAdapter` bean, Spring Boot exposes the preceding default one. + + Replacing this is as simple as exposing the bean within the application: + +@@ -274,9 +272,9 @@ class MyCustomSecurityConfiguration : WebSecurityConfigurerAdapter() { + ---- + ==== + +-The above requires the scope of `message:read` for any URL that starts with `/messages/`. ++The preceding exmaple requires the scope of `message:read` for any URL that starts with `/messages/`. + +-Methods on the `oauth2ResourceServer` DSL will also override or replace auto configuration. ++Methods on the `oauth2ResourceServer` DSL also override or replace auto-configuration. + + [[oauth2resourceserver-jwt-decoder]] + For example, the second `@Bean` Spring Boot creates is a `JwtDecoder`, which <>: +@@ -302,16 +300,15 @@ fun jwtDecoder(): JwtDecoder { + ---- + ==== + +-[NOTE] +-Calling `{security-api-url}org/springframework/security/oauth2/jwt/JwtDecoders.html#fromIssuerLocation-java.lang.String-[JwtDecoders#fromIssuerLocation]` is what invokes the Provider Configuration or Authorization Server Metadata endpoint in order to derive the JWK Set Uri. ++NOTE: Calling `{security-api-url}org/springframework/security/oauth2/jwt/JwtDecoders.html#fromIssuerLocation-java.lang.String-[JwtDecoders#fromIssuerLocation]` invokes the Provider Configuration or Authorization Server Metadata endpoint, to derive the JWK Set URI. + +-If the application doesn't expose a `JwtDecoder` bean, then Spring Boot will expose the above default one. ++If the application does not expose a `JwtDecoder` bean, Spring Boot exposes the earlier default one. + +-And its configuration can be overridden using `jwkSetUri()` or replaced using `decoder()`. ++You can override its configuration by using `jwkSetUri()` or replaced using `decoder()`. + +-Or, if you're not using Spring Boot at all, then both of these components - the filter chain and a `JwtDecoder` can be specified in XML. ++Alternatively, if you do not use Spring Boot at all, you can specify both of these components (the filter chain and a `JwtDecoder`) in XML. + +-The filter chain is specified like so: ++The filter chain is specified as follows: + + .Default JWT Configuration + ==== +@@ -327,7 +324,7 @@ The filter chain is specified like so: + ---- + ==== + +-And the `JwtDecoder` like so: ++The `JwtDecoder` is specified as follows: + + .JWT Decoder + ==== +@@ -345,7 +342,7 @@ And the `JwtDecoder` like so: + [[oauth2resourceserver-jwt-jwkseturi-dsl]] + ==== Using `jwkSetUri()` + +-An authorization server's JWK Set Uri can be configured <> or it can be supplied in the DSL: ++You can configure an authorization server's JWK Set URI <>, or you can supply it in the DSL: + + .JWK Set Uri Configuration + ==== +@@ -405,7 +402,7 @@ Using `jwkSetUri()` takes precedence over any configuration property. + [[oauth2resourceserver-jwt-decoder-dsl]] + ==== Using `decoder()` + +-More powerful than `jwkSetUri()` is `decoder()`, which will completely replace any Boot auto configuration of <>: ++More powerful than `jwkSetUri()` is `decoder()`, which completely replaces any Boot auto configuration of <>: + + .JWT Decoder Configuration + ==== +@@ -460,12 +457,12 @@ class DirectlyConfiguredJwtDecoder : WebSecurityConfigurerAdapter() { + ---- + ==== + +-This is handy when deeper configuration, like <>, <>, or <>, is necessary. ++This is handy when deeper configuration (such as <>, <>, or <>) is necessary. + + [[oauth2resourceserver-jwt-decoder-bean]] + ==== Exposing a `JwtDecoder` `@Bean` + +-Or, exposing a <> `@Bean` has the same effect as `decoder()`: ++Alternatively, exposing a <> `@Bean` has the same effect as `decoder()`: + + ==== + .Java +@@ -490,15 +487,16 @@ fun jwtDecoder(): JwtDecoder { + [[oauth2resourceserver-jwt-decoder-algorithm]] + === Configuring Trusted Algorithms + +-By default, `NimbusJwtDecoder`, and hence Resource Server, will only trust and verify tokens using `RS256`. ++By default, `NimbusJwtDecoder` and, hence, Resource Server, trust and verify tokens only that use `RS256`. + +-You can customize this via <>, <>, or from the <>. ++You can customize this through <> or <> or from the <>. + + [[oauth2resourceserver-jwt-boot-algorithm]] + ==== Via Spring Boot + + The simplest way to set the algorithm is as a property: + ++==== + [source,yaml] + ---- + spring: +@@ -509,6 +507,7 @@ spring: + jws-algorithm: RS512 + jwk-set-uri: https://idp.example.org/.well-known/jwks.json + ---- ++==== + + [[oauth2resourceserver-jwt-decoder-builder]] + ==== Using a Builder +@@ -537,7 +536,7 @@ fun jwtDecoder(): JwtDecoder { + ---- + ==== + +-Calling `jwsAlgorithm` more than once will configure `NimbusJwtDecoder` to trust more than one algorithm, like so: ++Calling `jwsAlgorithm` more than once configures `NimbusJwtDecoder` to trust more than one algorithm, as follows: + + ==== + .Java +@@ -561,7 +560,7 @@ fun jwtDecoder(): JwtDecoder { + ---- + ==== + +-Or, you can call `jwsAlgorithms`: ++Alternatively, you can call `jwsAlgorithms`: + + ==== + .Java +@@ -594,10 +593,10 @@ fun jwtDecoder(): JwtDecoder { + [[oauth2resourceserver-jwt-decoder-jwk-response]] + ==== From JWK Set response + +-Since Spring Security's JWT support is based off of Nimbus, you can use all it's great features as well. ++Since Spring Security's JWT support is based off of Nimbus, you can use all its great features as well. + +-For example, Nimbus has a `JWSKeySelector` implementation that will select the set of algorithms based on the JWK Set URI response. +-You can use it to generate a `NimbusJwtDecoder` like so: ++For example, Nimbus has a `JWSKeySelector` implementation that selects the set of algorithms, based on the JWK Set URI response. ++You can use it to generate a `NimbusJwtDecoder`, as follows: + + ==== + .Java +@@ -634,15 +633,16 @@ fun jwtDecoder(): JwtDecoder { + [[oauth2resourceserver-jwt-decoder-public-key]] + === Trusting a Single Asymmetric Key + +-Simpler than backing a Resource Server with a JWK Set endpoint is to hard-code an RSA public key. +-The public key can be provided via <> or by <>. ++Simpler than backing a Resource Server with a JWK Set endpoint is to hard code an RSA public key. ++The public key can be provided through <> or by <>. + + [[oauth2resourceserver-jwt-decoder-public-key-boot]] +-==== Via Spring Boot ++==== Providing a Public Key through Spring Boot + +-Specifying a key via Spring Boot is quite simple. +-The key's location can be specified like so: ++With Spring Boot, ++you can specify the key's location: + ++==== + [source,yaml] + ---- + spring: +@@ -652,8 +652,9 @@ spring: + jwt: + public-key-location: classpath:my-key.pub + ---- ++==== + +-Or, to allow for a more sophisticated lookup, you can post-process the `RsaKeyConversionServicePostProcessor`: ++Alternatively, to allow for a more sophisticated lookup, you can post-process the `RsaKeyConversionServicePostProcessor`: + + ==== + .Java +@@ -680,13 +681,16 @@ fun conversionServiceCustomizer(): BeanFactoryPostProcessor { + ---- + ==== + +-Specify your key's location: ++To specify your key's location: + +-```yaml ++==== ++[source,yaml] ++---- + key.location: hfds://my-key.pub +-``` ++---- ++==== + +-And then autowire the value: ++Then autowire the value: + + ==== + .Java +@@ -705,9 +709,9 @@ val key: RSAPublicKey? = null + ==== + + [[oauth2resourceserver-jwt-decoder-public-key-builder]] +-==== Using a Builder ++==== Using a Builder to Provide a Public Key + +-To wire an `RSAPublicKey` directly, you can simply use the appropriate `NimbusJwtDecoder` builder, like so: ++To wire an `RSAPublicKey` directly, you can use the appropriate `NimbusJwtDecoder` builder: + + ==== + .Java +@@ -732,8 +736,7 @@ fun jwtDecoder(): JwtDecoder { + [[oauth2resourceserver-jwt-decoder-secret-key]] + === Trusting a Single Symmetric Key + +-Using a single symmetric key is also simple. +-You can simply load in your `SecretKey` and use the appropriate `NimbusJwtDecoder` builder, like so: ++To use a single symmetric key, you can load in your `SecretKey` and use the appropriate `NimbusJwtDecoder` builder: + + ==== + .Java +@@ -758,13 +761,13 @@ fun jwtDecoder(): JwtDecoder { + [[oauth2resourceserver-jwt-authorization]] + === Configuring Authorization + +-A JWT that is issued from an OAuth 2.0 Authorization Server will typically either have a `scope` or `scp` attribute, indicating the scopes (or authorities) it's been granted, for example: ++A JWT that is issued from an OAuth 2.0 Authorization Server typically have either a `scope` or an `scp` attribute, indicating the scopes (or authorities) it has been granted -- for example: + + `{ ..., "scope" : "messages contacts"}` + +-When this is the case, Resource Server will attempt to coerce these scopes into a list of granted authorities, prefixing each scope with the string "SCOPE_". ++When this is the case, Resource Server tries to coerce these scopes into a list of granted authorities, prefixing each scope with the string, `SCOPE_`. + +-This means that to protect an endpoint or method with a scope derived from a JWT, the corresponding expressions should include this prefix: ++This means that, to protect an endpoint or method with a scope derived from a JWT, the corresponding expressions should include this prefix: + + .Authorization Configuration + ==== +@@ -818,28 +821,30 @@ class DirectlyConfiguredJwkSetUri : WebSecurityConfigurerAdapter() { + ---- + ==== + +-Or similarly with method security: ++A similar arrangement applies to method security: + ++==== + [source,java] + ---- + @PreAuthorize("hasAuthority('SCOPE_messages')") + public List getMessages(...) {} + ---- ++==== + + [[oauth2resourceserver-jwt-authorization-extraction]] + ==== Extracting Authorities Manually + + However, there are a number of circumstances where this default is insufficient. +-For example, some authorization servers don't use the `scope` attribute, but instead have their own custom attribute. +-Or, at other times, the resource server may need to adapt the attribute or a composition of attributes into internalized authorities. ++For example, some authorization servers do not use the `scope` attribute but, instead, have their own custom attribute. ++At other times, the resource server may need to adapt the attribute or a composition of attributes into internalized authorities. + + To this end, Spring Security ships with `JwtAuthenticationConverter`, which is responsible for <>. +-By default, Spring Security will wire the `JwtAuthenticationProvider` with a default instance of `JwtAuthenticationConverter`. ++By default, Spring Security wires the `JwtAuthenticationProvider` with a default instance of `JwtAuthenticationConverter`. + + As part of configuring a `JwtAuthenticationConverter`, you can supply a subsidiary converter to go from `Jwt` to a `Collection` of granted authorities. + +-Let's say that that your authorization server communicates authorities in a custom claim called `authorities`. +-In that case, you can configure the claim that <> should inspect, like so: ++Suppose your authorization server communicates authorities in a custom claim called `authorities`. ++In that case, you can configure the claim that <> should inspect: + + .Authorities Claim Configuration + ==== +@@ -896,7 +901,7 @@ fun jwtAuthenticationConverter(): JwtAuthenticationConverter { + ==== + + You can also configure the authority prefix to be different as well. +-Instead of prefixing each authority with `SCOPE_`, you can change it to `ROLE_` like so: ++Instead of prefixing each authority with `SCOPE_`, you can change it to `ROLE_`: + + .Authorities Prefix Configuration + ==== +@@ -952,7 +957,7 @@ fun jwtAuthenticationConverter(): JwtAuthenticationConverter { + ---- + ==== + +-Or, you can remove the prefix altogether by calling `JwtGrantedAuthoritiesConverter#setAuthorityPrefix("")`. ++Alternatively, you can remove the prefix altogether by calling `JwtGrantedAuthoritiesConverter#setAuthorityPrefix("")`. + + For more flexibility, the DSL supports entirely replacing the converter with any class that implements `Converter`: + +@@ -1016,7 +1021,7 @@ class CustomAuthenticationConverterConfig : WebSecurityConfigurerAdapter() { + [[oauth2resourceserver-jwt-validation]] + === Configuring Validation + +-Using <>, indicating the authorization server's issuer uri, Resource Server will default to verifying the `iss` claim as well as the `exp` and `nbf` timestamp claims. ++Using <> and indicating the authorization server's issuer URI, Resource Server defaults to verifying the `iss` claim as well as the `exp` and `nbf` timestamp claims. + + In circumstances where validation needs to be customized, Resource Server ships with two standard validators and also accepts custom `OAuth2TokenValidator` instances. + +@@ -1025,10 +1030,10 @@ In circumstances where validation needs to be customized, Resource Server ships + + JWT's typically have a window of validity, with the start of the window indicated in the `nbf` claim and the end indicated in the `exp` claim. + +-However, every server can experience clock drift, which can cause tokens to appear expired to one server, but not to another. ++However, every server can experience clock drift, which can cause tokens to appear to be expired to one server but not to another. + This can cause some implementation heartburn as the number of collaborating servers increases in a distributed system. + +-Resource Server uses `JwtTimestampValidator` to verify a token's validity window, and it can be configured with a `clockSkew` to alleviate the above problem: ++Resource Server uses `JwtTimestampValidator` to verify a token's validity window, and you can configure it with a `clockSkew` to alleviate the problem of clock drift: + + ==== + .Java +@@ -1067,13 +1072,12 @@ fun jwtDecoder(): JwtDecoder { + ---- + ==== + +-[NOTE] +-By default, Resource Server configures a clock skew of 30 seconds. ++NOTE: By default, Resource Server configures a clock skew of 30 seconds. + + [[oauth2resourceserver-jwt-validation-custom]] + ==== Configuring a Custom Validator + +-Adding a check for the `aud` claim is simple with the `OAuth2TokenValidator` API: ++You can use the `OAuth2TokenValidator` API to add a check for the `aud` claim: + + ==== + .Java +@@ -1093,7 +1097,7 @@ fun audienceValidator(): OAuth2TokenValidator { + ---- + ==== + +-Or, for more control you can implement your own `OAuth2TokenValidator`: ++Alternatively, for more control, you can implement your own `OAuth2TokenValidator`: + + ==== + .Java +@@ -1142,7 +1146,7 @@ fun audienceValidator(): OAuth2TokenValidator { + ---- + ==== + +-Then, to add into a resource server, it's a matter of specifying the <> instance: ++Then, to add into a resource server, you can specify the <> instance: + + ==== + .Java +@@ -1184,21 +1188,21 @@ fun jwtDecoder(): JwtDecoder { + [[oauth2resourceserver-jwt-claimsetmapping]] + === Configuring Claim Set Mapping + +-Spring Security uses the https://bitbucket.org/connect2id/nimbus-jose-jwt/wiki/Home[Nimbus] library for parsing JWTs and validating their signatures. ++Spring Security uses the https://bitbucket.org/connect2id/nimbus-jose-jwt/wiki/Home[Nimbus] library to parse JWTs and validate their signatures. + Consequently, Spring Security is subject to Nimbus's interpretation of each field value and how to coerce each into a Java type. + +-For example, because Nimbus remains Java 7 compatible, it doesn't use `Instant` to represent timestamp fields. ++For example, because Nimbus remains Java 7 compatible, it does not use `Instant` to represent timestamp fields. + +-And it's entirely possible to use a different library or for JWT processing, which may make its own coercion decisions that need adjustment. ++Also, it is entirely possible to use a different library or for JWT processing, which may make its own coercion decisions that need adjustment. + +-Or, quite simply, a resource server may want to add or remove claims from a JWT for domain-specific reasons. ++Put differently, a resource server may want to add or remove claims from a JWT for domain-specific reasons. + + For these purposes, Resource Server supports mapping the JWT claim set with `MappedJwtClaimSetConverter`. + + [[oauth2resourceserver-jwt-claimsetmapping-singleclaim]] + ==== Customizing the Conversion of a Single Claim + +-By default, `MappedJwtClaimSetConverter` will attempt to coerce claims into the following types: ++By default, `MappedJwtClaimSetConverter` tries to coerce claims into the following types: + + |============ + | Claim | Java Type +@@ -1211,7 +1215,7 @@ By default, `MappedJwtClaimSetConverter` will attempt to coerce claims into the + | `sub` | `String` + |============ + +-An individual claim's conversion strategy can be configured using `MappedJwtClaimSetConverter.withDefaults`: ++You can configure an individual claim's conversion strategy by using `MappedJwtClaimSetConverter.withDefaults`: + + ==== + .Java +@@ -1244,12 +1248,13 @@ fun jwtDecoder(): JwtDecoder { + } + ---- + ==== +-This will keep all the defaults, except it will override the default claim converter for `sub`. ++ ++This approach keeps all the defaults, except that it overrides the default claim converter for `sub`. + + [[oauth2resourceserver-jwt-claimsetmapping-add]] + ==== Adding a Claim + +-`MappedJwtClaimSetConverter` can also be used to add a custom claim, for example, to adapt to an existing system: ++`MappedJwtClaimSetConverter` can also be used to add a custom claim -- for example, to adapt to an existing system: + + ==== + .Java +@@ -1268,7 +1273,7 @@ MappedJwtClaimSetConverter.withDefaults(mapOf("custom" to Converter + [[oauth2resourceserver-jwt-claimsetmapping-remove]] + ==== Removing a Claim + +-And removing a claim is also simple, using the same API: ++And removing a claim is also simple, by using the same API: + + ==== + .Java +@@ -1323,7 +1328,7 @@ class UsernameSubClaimAdapter : Converter, Map> + ---- + ==== + +-And then, the instance can be supplied like normal: ++Then you can supply the instance in the normal way: + + ==== + .Java +@@ -1355,7 +1360,7 @@ fun jwtDecoder(): JwtDecoder { + By default, Resource Server uses connection and socket timeouts of 30 seconds each for coordinating with the authorization server. + + This may be too short in some scenarios. +-Further, it doesn't take into account more sophisticated patterns like back-off and discovery. ++Further, it does not take into account more sophisticated patterns like back-off and discovery. + + To adjust the way in which Resource Server connects to the authorization server, `NimbusJwtDecoder` accepts an instance of `RestOperations`: + +@@ -1389,8 +1394,8 @@ fun jwtDecoder(builder: RestTemplateBuilder): JwtDecoder { + ---- + ==== + +-Also by default, Resource Server caches in-memory the authorization server's JWK set for 5 minutes, which you may want to adjust. +-Further, it doesn't take into account more sophisticated caching patterns like eviction or using a shared cache. ++Also, by default, Resource Server caches (in memory) the authorization server's JWK set for 5 minutes, which you may want to adjust. ++Further, it does not take into account more sophisticated caching patterns, such as eviction or using a shared cache. + + To adjust the way in which Resource Server caches the JWK set, `NimbusJwtDecoder` accepts an instance of `Cache`: + +@@ -1418,34 +1423,37 @@ fun jwtDecoder(cacheManager: CacheManager): JwtDecoder { + ---- + ==== + +-When given a `Cache`, Resource Server will use the JWK Set Uri as the key and the JWK Set JSON as the value. ++When given a `Cache`, Resource Server uses the JWK Set URI as the key and the JWK Set JSON as the value. + +-NOTE: Spring isn't a cache provider, so you'll need to make sure to include the appropriate dependencies, like `spring-boot-starter-cache` and your favorite caching provider. ++NOTE: Spring is not a cache provider, so you need to make sure to include the appropriate dependencies, such as `spring-boot-starter-cache` and your favorite caching provider. + +-NOTE: Whether it's socket or cache timeouts, you may instead want to work with Nimbus directly. ++NOTE: Whether it is socket or cache timeouts, you may instead want to work with Nimbus directly. + To do so, remember that `NimbusJwtDecoder` ships with a constructor that takes Nimbus's `JWTProcessor`. + + [[oauth2resourceserver-opaque-minimaldependencies]] + === Minimal Dependencies for Introspection + As described in <> most of Resource Server support is collected in `spring-security-oauth2-resource-server`. +-However unless a custom <> is provided, the Resource Server will fallback to NimbusOpaqueTokenIntrospector. +-Meaning that both `spring-security-oauth2-resource-server` and `oauth2-oidc-sdk` are necessary in order to have a working minimal Resource Server that supports opaque Bearer Tokens. +-Please refer to `spring-security-oauth2-resource-server` in order to determin the correct version for `oauth2-oidc-sdk`. ++However, unless a custom <> is provided, Resource Server falls back to NimbusOpaqueTokenIntrospector. ++This means that both `spring-security-oauth2-resource-server` and `oauth2-oidc-sdk` are necessary to have a working minimal Resource Server that supports opaque Bearer Tokens. ++See `spring-security-oauth2-resource-server` to determine the correct version for `oauth2-oidc-sdk`. + + [[oauth2resourceserver-opaque-minimalconfiguration]] + === Minimal Configuration for Introspection + +-Typically, an opaque token can be verified via an https://tools.ietf.org/html/rfc7662[OAuth 2.0 Introspection Endpoint], hosted by the authorization server. ++Typically, you can verify an opaque token through an https://tools.ietf.org/html/rfc7662[OAuth 2.0 Introspection Endpoint], hosted by the authorization server. + This can be handy when revocation is a requirement. + +-When using https://spring.io/projects/spring-boot[Spring Boot], configuring an application as a resource server that uses introspection consists of two basic steps. +-First, include the needed dependencies and second, indicate the introspection endpoint details. ++When you use https://spring.io/projects/spring-boot[Spring Boot], configuring an application as a resource server that uses introspection consists of two basic steps: ++ ++. Include the needed dependencies. ++. Indicate the introspection endpoint details. + + [[oauth2resourceserver-opaque-introspectionuri]] + ==== Specifying the Authorization Server + +-To specify where the introspection endpoint is, simply do: ++The following exmaple specifies where the introspection endpoint is: + ++==== + [source,yaml] + ---- + security: +@@ -1456,39 +1464,40 @@ security: + client-id: client + client-secret: secret + ---- ++==== + + Where `https://idp.example.com/introspect` is the introspection endpoint hosted by your authorization server and `client-id` and `client-secret` are the credentials needed to hit that endpoint. + +-Resource Server will use these properties to further self-configure and subsequently validate incoming JWTs. +- +-[NOTE] +-When using introspection, the authorization server's word is the law. +-If the authorization server responses that the token is valid, then it is. ++Resource Server uses these properties to further self-configure and subsequently validate incoming JWTs. + +-And that's it! ++NOTE: When using introspection, the authorization server's word is law. ++If the authorization server responsed that the token is valid, it is. + + ==== Startup Expectations + +-When this property and these dependencies are used, Resource Server will automatically configure itself to validate Opaque Bearer Tokens. ++When this property and these dependencies are used, Resource Server automatically configures itself to validate Opaque Bearer Tokens. + +-This startup process is quite a bit simpler than for JWTs since no endpoints need to be discovered and no additional validation rules get added. ++This startup process is quite a bit simpler than for JWTs, since no endpoints need to be discovered and no additional validation rules get added. + + ==== Runtime Expectations + +-Once the application is started up, Resource Server will attempt to process any request containing an `Authorization: Bearer` header: ++Once the application has started, Resource Server tries to process any request containing an `Authorization: Bearer` header: + +-```http ++==== ++[source,text] ++---- + GET / HTTP/1.1 + Authorization: Bearer some-token-value # Resource Server will process this +-``` ++---- ++==== + +-So long as this scheme is indicated, Resource Server will attempt to process the request according to the Bearer Token specification. ++So long as this scheme is indicated, Resource Server tries to process the request according to the Bearer Token specification. + +-Given an Opaque Token, Resource Server will ++Given an Opaque Token, Resource Server: + +-1. Query the provided introspection endpoint using the provided credentials and the token +-2. Inspect the response for an `{ 'active' : true }` attribute +-3. Map each scope to an authority with the prefix `SCOPE_` ++1. Queries the provided introspection endpoint by using the provided credentials and the token. ++2. Inspects the response for an `{ 'active' : true }` attribute. ++3. Maps each scope to an authority with a prefix of `SCOPE_`. + + The resulting `Authentication#getPrincipal`, by default, is a Spring Security `{security-api-url}org/springframework/security/oauth2/core/OAuth2AuthenticatedPrincipal.html[OAuth2AuthenticatedPrincipal]` object, and `Authentication#getName` maps to the token's `sub` property, if one is present. + +@@ -1502,12 +1511,12 @@ From here, you may want to jump to: + [[oauth2resourceserver-opaque-architecture]] + === How Opaque Token Authentication Works + +-Next, let's see the architectural components that Spring Security uses to support https://tools.ietf.org/html/rfc7662[opaque token] Authentication in servlet-based applications, like the one we just saw. ++Next, let's see the architectural components that Spring Security uses to support https://tools.ietf.org/html/rfc7662[opaque token] authentication in servlet-based applications, such as the one we examined earlier in this chapter. + + {security-api-url}org/springframework/security/oauth2/server/resource/authentication/OpaqueTokenAuthenticationProvider.html[`OpaqueTokenAuthenticationProvider`] is an <> implementation that leverages a <> to authenticate an opaque token. + +-Let's take a look at how `OpaqueTokenAuthenticationProvider` works within Spring Security. +-The figure explains details of how the <> in figures from <> works. ++Now we examine how `OpaqueTokenAuthenticationProvider` works within Spring Security. ++The figure details how the <> in figures from <> works. + + .`OpaqueTokenAuthenticationProvider` Usage + image::{figures}/opaquetokenauthenticationprovider.png[] +@@ -1517,16 +1526,16 @@ image:{icondir}/number_1.png[] The authentication `Filter` from <> of type `OpaqueTokenAuthenticationProvider`. + + [[oauth2resourceserver-opaque-architecture-introspector]] +-image:{icondir}/number_3.png[] `OpaqueTokenAuthenticationProvider` introspects the opaque token and adds granted authorities using an <>. ++image:{icondir}/number_3.png[] `OpaqueTokenAuthenticationProvider` introspects the opaque token and adds granted authorities by using an <>. + When authentication is successful, the <> that is returned is of type `BearerTokenAuthentication` and has a principal that is the `OAuth2AuthenticatedPrincipal` returned by the configured <>. +-Ultimately, the returned `BearerTokenAuthentication` will be set on the <> by the authentication `Filter`. ++Ultimately, the returned `BearerTokenAuthentication` is set on the <> by the authentication `Filter`. + + [[oauth2resourceserver-opaque-attributes]] + === Looking Up Attributes Post-Authentication + + Once a token is authenticated, an instance of `BearerTokenAuthentication` is set in the `SecurityContext`. + +-This means that it's available in `@Controller` methods when using `@EnableWebMvc` in your configuration: ++This means that it is available in `@Controller` methods when you use `@EnableWebMvc` in your configuration: + + ==== + .Java +@@ -1548,7 +1557,7 @@ fun foo(authentication: BearerTokenAuthentication): String { + ---- + ==== + +-Since `BearerTokenAuthentication` holds an `OAuth2AuthenticatedPrincipal`, that also means that it's available to controller methods, too: ++Since `BearerTokenAuthentication` holds an `OAuth2AuthenticatedPrincipal`, that also means that it is available to controller methods, too: + + ==== + .Java +@@ -1570,11 +1579,11 @@ fun foo(@AuthenticationPrincipal principal: OAuth2AuthenticatedPrincipal): Strin + ---- + ==== + +-==== Looking Up Attributes Via SpEL ++==== Looking Up Attributes with SpEL + +-Of course, this also means that attributes can be accessed via SpEL. ++Of course, this also means that attributes can be accessed with SpEL (Spring Expression Language). + +-For example, if using `@EnableGlobalMethodSecurity` so that you can use `@PreAuthorize` annotations, you can do: ++For example, if you use `@EnableGlobalMethodSecurity` so that you can use `@PreAuthorize` annotations, you can use: + + ==== + .Java +@@ -1599,10 +1608,10 @@ fun forFoosEyesOnly(): String { + [[oauth2resourceserver-opaque-sansboot]] + === Overriding or Replacing Boot Auto Configuration + +-There are two `@Bean` s that Spring Boot generates on Resource Server's behalf. ++There are two `@Bean` instances that Spring Boot generates on Resource Server's behalf. + +-The first is a `WebSecurityConfigurerAdapter` that configures the app as a resource server. +-When use Opaque Token, this `WebSecurityConfigurerAdapter` looks like: ++The first is a `WebSecurityConfigurerAdapter` that configures the application as a resource server. ++When you use Opaque Token, this `WebSecurityConfigurerAdapter` looks like: + + .Default Opaque Token Configuration + ==== +@@ -1634,9 +1643,9 @@ override fun configure(http: HttpSecurity) { + ---- + ==== + +-If the application doesn't expose a `WebSecurityConfigurerAdapter` bean, then Spring Boot will expose the above default one. ++If the application does not expose a `WebSecurityConfigurerAdapter` bean, Spring Boot exposes the preceding default one. + +-Replacing this is as simple as exposing the bean within the application: ++Replacing this involves exposing the bean within the application: + + .Custom Opaque Token Configuration + ==== +@@ -1682,12 +1691,12 @@ class MyCustomSecurityConfiguration : WebSecurityConfigurerAdapter() { + ---- + ==== + +-The above requires the scope of `message:read` for any URL that starts with `/messages/`. ++The preceding example requires the scope of `message:read` for any URL that starts with `/messages/`. + +-Methods on the `oauth2ResourceServer` DSL will also override or replace auto configuration. ++Methods on the `oauth2ResourceServer` DSL also override or replace auto configuration. + + [[oauth2resourceserver-opaque-introspector]] +-For example, the second `@Bean` Spring Boot creates is an `OpaqueTokenIntrospector`, <>: ++For example, the second `@Bean` that Spring Boot creates is an `OpaqueTokenIntrospector`, <>: + + ==== + .Java +@@ -1709,11 +1718,11 @@ fun introspector(): OpaqueTokenIntrospector { + ---- + ==== + +-If the application doesn't expose a <> bean, then Spring Boot will expose the above default one. ++If the application does not expose a <> bean, Spring Boot exposes the preceding default one. + +-And its configuration can be overridden using `introspectionUri()` and `introspectionClientCredentials()` or replaced using `introspector()`. ++You can override its configuration by using `introspectionUri()` and `introspectionClientCredentials()` or replace it by using `introspector()`. + +-Or, if you're not using Spring Boot at all, then both of these components - the filter chain and a <> can be specified in XML. ++Alternatively, if you do not use Spring Boot at all, you can specify both of these components (the filter chain and a <>) in XML. + + The filter chain is specified like so: + +@@ -1750,7 +1759,7 @@ And the <> or it can be supplied in the DSL: ++You can configure an authorization server's introspection URI <> or supply it in the DSL: + + .Introspection URI Configuration + ==== +@@ -1812,7 +1821,7 @@ Using `introspectionUri()` takes precedence over any configuration property. + [[oauth2resourceserver-opaque-introspector-dsl]] + ==== Using `introspector()` + +-More powerful than `introspectionUri()` is `introspector()`, which will completely replace any Boot auto configuration of <>: ++More powerful than `introspectionUri()` is `introspector()`, which completely replaces any Boot auto-configuration of <>: + + .Introspector Configuration + ==== +@@ -1867,13 +1876,14 @@ class DirectlyConfiguredIntrospector : WebSecurityConfigurerAdapter() { + ---- + ==== + +-This is handy when deeper configuration, like <>, <>, or <>, is necessary. ++This is handy when deeper configuration (such as <>, <>, or <>) is necessary. + + [[oauth2resourceserver-opaque-introspector-bean]] + ==== Exposing a `OpaqueTokenIntrospector` `@Bean` + +-Or, exposing a <> `@Bean` has the same effect as `introspector()`: ++Alternatively, exposing an <> `@Bean` has the same effect as `introspector()`: + ++==== + [source,java] + ---- + @Bean +@@ -1881,17 +1891,18 @@ public OpaqueTokenIntrospector introspector() { + return new NimbusOpaqueTokenIntrospector(introspectionUri, clientId, clientSecret); + } + ---- ++==== + + [[oauth2resourceserver-opaque-authorization]] + === Configuring Authorization + +-An OAuth 2.0 Introspection endpoint will typically return a `scope` attribute, indicating the scopes (or authorities) it's been granted, for example: ++An OAuth 2.0 Introspection endpoint typically returns a `scope` attribute, indicating the scopes (or authorities) it has been granted -- for example: + + `{ ..., "scope" : "messages contacts"}` + +-When this is the case, Resource Server will attempt to coerce these scopes into a list of granted authorities, prefixing each scope with the string "SCOPE_". ++When this is the case, Resource Server tries to coerce these scopes into a list of granted authorities, prefixing each scope with the string "SCOPE_". + +-This means that to protect an endpoint or method with a scope derived from an Opaque Token, the corresponding expressions should include this prefix: ++This means that, to protect an endpoint or method with a scope derived from an Opaque Token, the corresponding expressions should include this prefix: + + .Authorization Opaque Token Configuration + ==== +@@ -1945,7 +1956,7 @@ class MappedAuthorities : WebSecurityConfigurerAdapter() { + ---- + ==== + +-Or similarly with method security: ++Method security requires a similar approach: + + ==== + .Java +@@ -1966,10 +1977,11 @@ fun getMessages(): List {} + [[oauth2resourceserver-opaque-authorization-extraction]] + ==== Extracting Authorities Manually + +-By default, Opaque Token support will extract the scope claim from an introspection response and parse it into individual `GrantedAuthority` instances. ++By default, Opaque Token support extracts the scope claim from an introspection response and parse it into individual `GrantedAuthority` instances. + +-For example, if the introspection response were: ++For example, consider the following introspection response: + ++==== + [source,json] + ---- + { +@@ -1977,10 +1989,11 @@ For example, if the introspection response were: + "scope" : "message:read message:write" + } + ---- ++==== + +-Then Resource Server would generate an `Authentication` with two authorities, one for `message:read` and the other for `message:write`. ++Given that response, Resource Server would generate an `Authentication` with two authorities, one for `message:read` and the other for `message:write`. + +-This can, of course, be customized using a custom <> that takes a look at the attribute set and converts in its own way: ++You can customize this can be customized by using a custom <> that examines the attribute set and converts in its own way: + + ==== + .Java +@@ -2025,7 +2038,7 @@ class CustomAuthoritiesOpaqueTokenIntrospector : OpaqueTokenIntrospector { + ---- + ==== + +-Thereafter, this custom introspector can be configured simply by exposing it as a `@Bean`: ++Thereafter, you can configure this custom introspector by exposing it as a `@Bean`: + + ==== + .Java +@@ -2050,10 +2063,10 @@ fun introspector(): OpaqueTokenIntrospector { + [[oauth2resourceserver-opaque-timeouts]] + === Configuring Timeouts + +-By default, Resource Server uses connection and socket timeouts of 30 seconds each for coordinating with the authorization server. ++By default, Resource Server uses connection and socket timeouts of 30 seconds each to coordinate with the authorization server. + +-This may be too short in some scenarios. +-Further, it doesn't take into account more sophisticated patterns like back-off and discovery. ++In some scenarios this value may be too short. ++Further, it does not take into account more sophisticated patterns, such as backing off and discovery. + + To adjust the way in which Resource Server connects to the authorization server, `NimbusOpaqueTokenIntrospector` accepts an instance of `RestOperations`: + +@@ -2092,12 +2105,13 @@ fun introspector(builder: RestTemplateBuilder, properties: OAuth2ResourceServerP + === Using Introspection with JWTs + + A common question is whether or not introspection is compatible with JWTs. +-Spring Security's Opaque Token support has been designed to not care about the format of the token -- it will gladly pass any token to the introspection endpoint provided. ++Spring Security's Opaque Token support has been designed to not care about the format of the token -- it gladly passes any token to the provided introspection endpoint. + +-So, let's say that you've got a requirement that requires you to check with the authorization server on each request, in case the JWT has been revoked. ++So, suppose you have a requirement to check with the authorization server on each request, in case the JWT has been revoked. + +-Even though you are using the JWT format for the token, your validation method is introspection, meaning you'd want to do: ++Even though you use the JWT format for the token, your validation method is introspection, meaning that you want to do: + ++==== + [source,yaml] + ---- + spring: +@@ -2109,14 +2123,15 @@ spring: + client-id: client + client-secret: secret + ---- ++==== + +-In this case, the resulting `Authentication` would be `BearerTokenAuthentication`. ++In this case, the resulting `Authentication` is `BearerTokenAuthentication`. + Any attributes in the corresponding `OAuth2AuthenticatedPrincipal` would be whatever was returned by the introspection endpoint. + +-But, let's say that, oddly enough, the introspection endpoint only returns whether or not the token is active. ++However, suppose that, oddly enough, the introspection endpoint returns only whether or not the token is active. + Now what? + +-In this case, you can create a custom <> that still hits the endpoint, but then updates the returned principal to have the JWTs claims as the attributes: ++In that case, you can create a custom <> that still hits the endpoint but then updates the returned principal to have the JWTs claims as the attributes: + + ==== + .Java +@@ -2171,7 +2186,7 @@ class JwtOpaqueTokenIntrospector : OpaqueTokenIntrospector { + ---- + ==== + +-Thereafter, this custom introspector can be configured simply by exposing it as a `@Bean`: ++Thereafter, you can configure this custom introspector by exposing it as a `@Bean`: + + ==== + .Java +@@ -2196,12 +2211,12 @@ fun introspector(): OpaqueTokenIntrospector { + [[oauth2resourceserver-opaque-userinfo]] + === Calling a `/userinfo` Endpoint + +-Generally speaking, a Resource Server doesn't care about the underlying user, but instead about the authorities that have been granted. ++Generally speaking, a Resource Server does not care about the underlying user but, instead, cares about the authorities that have been granted. + +-That said, at times it can be valuable to tie the authorization statement back to a user. ++That said, at times, it can be valuable to tie the authorization statement back to a user. + +-If an application is also using `spring-security-oauth2-client`, having set up the appropriate `ClientRegistrationRepository`, then this is quite simple with a custom <>. +-This implementation below does three things: ++If an application also uses `spring-security-oauth2-client`, having set up the appropriate `ClientRegistrationRepository`, then this is possible with a custom <>. ++The implementation shown in the next listing does three things: + + * Delegates to the introspection endpoint, to affirm the token's validity + * Looks up the appropriate client registration associated with the `/userinfo` endpoint +@@ -2256,8 +2271,8 @@ class UserInfoOpaqueTokenIntrospector : OpaqueTokenIntrospector { + ---- + ==== + +-If you aren't using `spring-security-oauth2-client`, it's still quite simple. +-You will simply need to invoke the `/userinfo` with your own instance of `WebClient`: ++If you do not use `spring-security-oauth2-client`, it is still possible. ++You need to invoke the `/userinfo` with your own instance of `WebClient`: + + ==== + .Java +@@ -2316,10 +2331,10 @@ fun introspector(): OpaqueTokenIntrospector { + [[oauth2reourceserver-opaqueandjwt]] + === Supporting both JWT and Opaque Token + +-In some cases, you may have a need to access both kinds of tokens. +-For example, you may support more than one tenant where one tenant issues JWTs and the other issues opaque tokens. ++In some cases, you may need to access both kinds of tokens. ++For example, you may support more than one tenant, where one tenant issues JWTs and the other issues opaque tokens. + +-If this decision must be made at request-time, then you can use an `AuthenticationManagerResolver` to achieve it, like so: ++If this decision must be made at request-time, you can use an `AuthenticationManagerResolver` to achieve it: + + ==== + .Java +@@ -2361,9 +2376,9 @@ fun tokenAuthenticationManagerResolver(): AuthenticationManagerResolver A hypothetical source for tenant information. ++<2> A cache for `JWKKeySelector`s, keyed by tenant identifier. ++<3> Looking up the tenant is more secure than calculating the JWK Set endpoint on the fly -- the lookup acts as a list of allowed tenants. ++<4> Create a `JWSKeySelector` through the types of keys that come back from the JWK Set endpoint -- the lazy lookup here means that you need not configure all tenants at startup. + ==== +-<1> A hypothetical source for tenant information +-<2> A cache for `JWKKeySelector`s, keyed by tenant identifier +-<3> Looking up the tenant is more secure than simply calculating the JWK Set endpoint on the fly - the lookup acts as a list of allowed tenants +-<4> Create a `JWSKeySelector` via the types of keys that come back from the JWK Set endpoint - the lazy lookup here means that you don't need to configure all tenants at startup + +-The above key selector is a composition of many key selectors. ++The preceding key selector is a composition of many key selectors. + It chooses which key selector to use based on the `iss` claim in the JWT. + + NOTE: To use this approach, make sure that the authorization server is configured to include the claim set as part of the token's signature. +-Without this, you have no guarantee that the issuer hasn't been altered by a bad actor. ++Without this, you have no guarantee that the issuer has not been altered by a bad actor. + + Next, we can construct a `JWTProcessor`: + +@@ -2661,8 +2676,8 @@ fun jwtProcessor(keySelector: JWTClaimsSetAwareJWSKeySelector): + As you are already seeing, the trade-off for moving tenant-awareness down to this level is more configuration. + We have just a bit more. + +-Next, we still want to make sure you are validating the issuer. +-But, since the issuer may be different per JWT, then you'll need a tenant-aware validator, too: ++Next, we still want to make sure you validate the issuer. ++However, since the issuer may differ per JWT, you need a tenant-aware validator, too: + + ==== + .Java +@@ -2755,10 +2770,10 @@ fun jwtDecoder(jwtProcessor: JWTProcessor?, jwtValidator: OAuth + ---- + ==== + +-We've finished talking about resolving the tenant. ++We have finished talking about resolving the tenant. + +-If you've chosen to resolve the tenant by something other than a JWT claim, then you'll need to make sure you address your downstream resource servers in the same way. +-For example, if you are resolving it by subdomain, you may need to address the downstream resource server using the same subdomain. ++If you chose to resolve the tenant by something other than a JWT claim, you need to make sure you address your downstream resource servers in the same way. ++For example, if you resolve it by subdomain, you may need to address the downstream resource server by using the same subdomain. + + However, if you resolve it by a claim in the bearer token, read on to learn about <>. + +@@ -2766,12 +2781,12 @@ However, if you resolve it by a claim in the bearer token, read on to learn abou + === Bearer Token Resolution + + By default, Resource Server looks for a bearer token in the `Authorization` header. +-This, however, can be customized in a handful of ways. ++However, you can customize this in a handful of ways. + + ==== Reading the Bearer Token from a Custom Header + +-For example, you may have a need to read the bearer token from a custom header. +-To achieve this, you can expose a `DefaultBearerTokenResolver` as a bean, or wire an instance into the DSL, as you can see in the following example: ++For example, you may need to read the bearer token from a custom header. ++To do so, you can expose a `DefaultBearerTokenResolver` as a bean or wire an instance into the DSL, as follows: + + .Custom Bearer Token Header + ==== +@@ -2811,11 +2826,11 @@ fun bearerTokenResolver(): BearerTokenResolver { + ---- + ==== + +-Or, in circumstances where a provider is using both a custom header and value, you can use `HeaderBearerTokenResolver` instead. ++Alternatively, in circumstances where a provider uses both a custom header and value, you can use `HeaderBearerTokenResolver` instead. + + ==== Reading the Bearer Token from a Form Parameter + +-Or, you may wish to read the token from a form parameter, which you can do by configuring the `DefaultBearerTokenResolver`, as you can see below: ++Alternatively, you may wish to read the token from a form parameter, which you can do by configuring the `DefaultBearerTokenResolver`: + + .Form Parameter Bearer Token + ==== +@@ -2858,8 +2873,8 @@ http { + + === Bearer Token Propagation + +-Now that you're resource server has validated the token, it might be handy to pass it to downstream services. +-This is quite simple with `{security-api-url}org/springframework/security/oauth2/server/resource/web/reactive/function/client/ServletBearerExchangeFilterFunction.html[ServletBearerExchangeFilterFunction]`, which you can see in the following example: ++Now that your resource server has validated the token, it might be handy to pass it to downstream services. ++This is possible with {security-api-url}org/springframework/security/oauth2/server/resource/web/reactive/function/client/ServletBearerExchangeFilterFunction.html[`ServletBearerExchangeFilterFunction`]: + + ==== + .Java +@@ -2885,10 +2900,8 @@ fun rest(): WebClient { + ---- + ==== + +-When the above `WebClient` is used to perform requests, Spring Security will look up the current `Authentication` and extract any `{security-api-url}org/springframework/security/oauth2/core/AbstractOAuth2Token.html[AbstractOAuth2Token]` credential. +-Then, it will propagate that token in the `Authorization` header. +- +-For example: ++When the `WebClient` performs requests, Spring Security looks up the current `Authentication` and extracts any `{security-api-url}org/springframework/security/oauth2/core/AbstractOAuth2Token.html[`AbstractOAuth2Token`]` credential. ++Then it propagates that token in the `Authorization` header: + + ==== + .Java +@@ -2912,9 +2925,9 @@ this.rest.get() + ---- + ==== + +-Will invoke the `https://other-service.example.com/endpoint`, adding the bearer token `Authorization` header for you. ++The preceding code invokes the `https://other-service.example.com/endpoint`, adding the bearer token `Authorization` header for you. + +-In places where you need to override this behavior, it's a simple matter of supplying the header yourself, like so: ++In places where you need to override this behavior, you can supply the header yourself: + + ==== + .Java +@@ -2940,15 +2953,14 @@ this.rest.get() + ---- + ==== + +-In this case, the filter will fall back and simply forward the request onto the rest of the web filter chain. ++In this case, the filter falls back and forwards the request onto the rest of the web filter chain. + +-[NOTE] +-Unlike the {security-api-url}org/springframework/security/oauth2/client/web/reactive/function/client/ServletOAuth2AuthorizedClientExchangeFilterFunction.html[OAuth 2.0 Client filter function], this filter function makes no attempt to renew the token, should it be expired. +-To obtain this level of support, please use the OAuth 2.0 Client filter. ++NOTE: Unlike the {security-api-url}org/springframework/security/oauth2/client/web/reactive/function/client/ServletOAuth2AuthorizedClientExchangeFilterFunction.html[OAuth 2.0 Client filter function], this filter function makes no attempt to renew the token, should it be expired. ++To obtain this level of support, use the OAuth 2.0 Client filter. + + ==== `RestTemplate` support + +-There is no `RestTemplate` equivalent for `ServletBearerExchangeFilterFunction` at the moment, but you can propagate the request's bearer token quite simply with your own interceptor: ++There is no `RestTemplate` equivalent for `ServletBearerExchangeFilterFunction` at the moment, but you can propagate the request's bearer token with your own interceptor: + + ==== + .Java +@@ -3001,25 +3013,26 @@ fun rest(): RestTemplate { + ==== + + +-[NOTE] +-Unlike the {security-api-url}org/springframework/security/oauth2/client/OAuth2AuthorizedClientManager.html[OAuth 2.0 Authorized Client Manager], this filter interceptor makes no attempt to renew the token, should it be expired. +-To obtain this level of support, please create an interceptor using the <>. ++NOTE: Unlike the {security-api-url}org/springframework/security/oauth2/client/OAuth2AuthorizedClientManager.html[OAuth 2.0 Authorized Client Manager], this filter interceptor makes no attempt to renew the token, should it be expired. ++To obtain this level of support, create an interceptor by using the <>. + + [[oauth2resourceserver-bearertoken-failure]] + === Bearer Token Failure + +-A bearer token may be invalid for a number of reasons. For example, the token may no longer be active. ++A bearer token can be invalid for a number of reasons. For example, the token may no longer be active. + + In these circumstances, Resource Server throws an `InvalidBearerTokenException`. + Like other exceptions, this results in an OAuth 2.0 Bearer Token error response: + +-[source,http request] ++==== ++[source,text] + ---- + HTTP/1.1 401 Unauthorized + WWW-Authenticate: Bearer error_code="invalid_token", error_description="Unsupported algorithm of none", error_uri="https://tools.ietf.org/html/rfc6750#section-3.1" + ---- ++==== + +-Additionally, it is published as an `AuthenticationFailureBadCredentialsEvent`, which you can <> like so: ++Additionally, it is published as an `AuthenticationFailureBadCredentialsEvent`, for which you can <>: + + ==== + .Java +diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/saml2/index.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/saml2/index.adoc +index e872f5d9d8..b1eccd4112 100644 +--- a/docs/manual/src/docs/asciidoc/_includes/servlet/saml2/index.adoc ++++ b/docs/manual/src/docs/asciidoc/_includes/servlet/saml2/index.adoc +@@ -1,4 +1,7 @@ + [[servlet-saml2]] +-= SAML2 ++= SAML 2.0 ++ ++This section discusses how Spring Security works with Security Assertion Markup Language 2.0. ++The https://en.wikipedia.org/wiki/SAML_2.0[Wikipedia article about SAML 2.0] provides some general background + + include::saml2-login.adoc[] +diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/saml2/saml2-login.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/saml2/saml2-login.adoc +index a0431de31e..cba42cb8c0 100644 +--- a/docs/manual/src/docs/asciidoc/_includes/servlet/saml2/saml2-login.adoc ++++ b/docs/manual/src/docs/asciidoc/_includes/servlet/saml2/saml2-login.adoc +@@ -1,10 +1,9 @@ +- + [[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). ++The SAML 2.0 Login feature provides an application with the ability 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, and others). + + 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]. +@@ -14,55 +13,54 @@ Since 2009, support for relying parties has existed as an https://github.com/spr + 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 <>. + +-[NOTE] +-==== +-A working sample for {gh-samples-url}/boot/saml2login[SAML 2.0 Login] is available in the {gh-samples-url}[Spring Security repository]. +-==== ++NOTE: A working sample for {gh-samples-url}/boot/saml2login[SAML 2.0 Login] is available in the {gh-samples-url}[Spring Security repository]. + +-Let's take a look at how SAML 2.0 Relying Party Authentication works within Spring Security. +-First, we see that, like <>, Spring Security takes the user to a third-party for performing authentication. +-It does this through a series of redirects. ++We start by examining how SAML 2.0 Relying Party Authentication works within Spring Security. ++First, we see that, like <>, 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 <> and <> diagrams: ++NOTE: The preceding figure above builds off our <> and <> 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_1.png[] First, a user makes an unauthenticated request to the `/private` resource, for which it is not authorized. + +-image:{icondir}/number_2.png[] Spring Security's <> indicates that the unauthenticated request is __Denied__ by throwing an `AccessDeniedException`. ++image:{icondir}/number_2.png[] Spring Security's <> indicates that the unauthenticated request is _Denied_ by throwing an `AccessDeniedException`. + +-image:{icondir}/number_3.png[] Since the user lacks authorization, the <> initiates __Start Authentication__. +-The configured <> is an instance of {security-api-url}org/springframework/security/web/authentication/LoginUrlAuthenticationEntryPoint.html[`LoginUrlAuthenticationEntryPoint`] which redirects to <` generating endpoint>>, `Saml2WebSsoAuthenticationRequestFilter`. +-Or, if you've <>, it will first redirect to a picker page. ++image:{icondir}/number_3.png[] Since the user lacks authorization, the <> initiates _Start Authentication_. ++The configured <> is an instance of {security-api-url}org/springframework/security/web/authentication/LoginUrlAuthenticationEntryPoint.html[`LoginUrlAuthenticationEntryPoint`], which redirects to <` generating endpoint>>, `Saml2WebSsoAuthenticationRequestFilter`. ++Alternatively, if you have <>, it first redirects to a picker page. + +-image:{icondir}/number_4.png[] Next, the `Saml2WebSsoAuthenticationRequestFilter` creates, signs, serializes, and encodes a `` using its configured <>. ++image:{icondir}/number_4.png[] Next, the `Saml2WebSsoAuthenticationRequestFilter` creates, signs, serializes, and encodes a `` by using its configured <>. + +-image:{icondir}/number_5.png[] Then, the browser takes this `` and presents it to the asserting party. +-The asserting party attempts to authentication the user. +-If successful, it will return a `` back to the browser. ++image:{icondir}/number_5.png[] Then the browser takes this `` and presents it to the asserting party. ++The asserting party tries to authentication the user. ++If successful, it returns a `` back to the browser. + + image:{icondir}/number_6.png[] The browser then POSTs the `` to the assertion consumer service endpoint. + ++The following image shows how Spring Security authenticates a ``. ++ + [[servlet-saml2login-authentication-saml2webssoauthenticationfilter]] + .Authenticating a `` + image::{figures}/saml2webssoauthenticationfilter.png[] + +-The figure builds off our <> diagram. ++NOTE: The figure builds off our <> diagram. + + image:{icondir}/number_1.png[] When the browser submits a `` to the application, it <>. + This filter calls its configured `AuthenticationConverter` to create a `Saml2AuthenticationToken` by extracting the response from the `HttpServletRequest`. + This converter additionally resolves the <> and supplies it to `Saml2AuthenticationToken`. + + image:{icondir}/number_2.png[] Next, the filter passes the token to its configured <>. +-By default, it will use the <>. ++By default, it uses the <>. + +-image:{icondir}/number_3.png[] If authentication fails, then __Failure__ ++image:{icondir}/number_3.png[] If authentication fails, then _Failure_. + + * The <> is cleared out. + * The <> is invoked to restart the authentication process. + +-image:{icondir}/number_4.png[] If authentication is successful, then __Success__. ++image:{icondir}/number_4.png[] If authentication is successful, then _Success_. + + * The <> is set on the <>. + * The `Saml2WebSsoAuthenticationFilter` invokes `FilterChain#doFilter(request,response)` to continue with the rest of the application logic. +@@ -76,16 +74,19 @@ 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. ++When using https://spring.io/projects/spring-boot[Spring Boot], configuring an application as a service provider consists of two basic steps: ++. Include the needed dependencies. ++. Indicate the necessary asserting party metadata. + + [NOTE] +-Also, this presupposes that you've already <>. ++Also, this configuration presupposes that you have already <>. + ++[[saml2-specifying-identity-provider-metadata]] + ==== Specifying Identity Provider Metadata + +-In a Spring Boot application, to specify an identity provider's metadata, simply do: ++In a Spring Boot application, to specify an identity provider's metadata, create configuration similar to the following: + ++==== + [source,yml] + ---- + spring: +@@ -101,63 +102,63 @@ spring: + 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. ++where: + +-And that's it! ++* `https://idp.example.com/issuer` is the value contained in the `Issuer` attribute of the SAML responses that the identity provider issues. ++* `classpath:idp.crt` is the location on the classpath for the identity provider's certificate for verifying SAML responses. ++* `https://idp.example.com/issuer/sso` is the endpoint where the identity provider is expecting `AuthnRequest` instances. + +-[NOTE] +-Identity Provider and Asserting Party are synonymous, as are Service Provider and Relying Party. ++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: ++As configured <>, the application processes any `+POST /login/saml2/sso/{registrationId}+` request containing a `SAMLResponse` parameter: + +-[source,html] ++==== ++[source,text] + ---- + POST /login/saml2/sso/adfs HTTP/1.1 + + SAMLResponse=PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZ... + ---- ++==== + +-There are two ways to see induce your asserting party to generate a `SAMLResponse`: ++There are two ways to induce your asserting party to generate a `SAMLResponse`: + +-* First, you can navigate to your asserting party. ++* 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`. ++* You can navigate to a protected page in your application -- for example, `http://localhost:8080`. ++Your application 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 + + 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. ++* 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. ++* Ensure that 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. ++This makes it possible for you to switch out OpenSAML for some other library or 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 `OpenSamlAuthenticationRequestFactory` and `OpenSamlAuthenticationProvider` expose `Converter` s that customize various steps in the authentication process. ++As a natural outcome of these two goals, Spring Security's SAML API is quite small relative to other modules. ++Instead, such classes as `OpenSamlAuthenticationRequestFactory` and `OpenSamlAuthenticationProvider` expose `Converter` implementationss 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 `OpenSamlAuthenticationProvider`. ++For example, once your application receives a `SAMLResponse` and delegates to `Saml2WebSsoAuthenticationFilter`, the filter delegates to `OpenSamlAuthenticationProvider`: + + .Authenticating an OpenSAML `Response` + image:{figures}/opensamlauthenticationprovider.png[] + +-This figure builds off of the <>. ++NOTE: This figure builds off of the <>. + + image:{icondir}/number_1.png[] The `Saml2WebSsoAuthenticationFilter` formulates the `Saml2AuthenticationToken` and invokes the <>. + +@@ -166,18 +167,18 @@ image:{icondir}/number_2.png[] The <>. ++image:{icondir}/number_4.png[] Then the provider <>. + 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. ++If they do not 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 <>. ++image:{icondir}/number_7.png[] Then the provider <>. + If any decryptions fail, authentication fails. + + image:{icondir}/number_8.png[] Next, the provider validates each assertion's `ExpiresAt` and `NotBefore` timestamps, the `` and any `` conditions. +@@ -186,29 +187,31 @@ 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>`. + 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`. ++image:{icondir}/number_10.png[] 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: ++Any class that uses both Spring Security and OpenSAML should statically initialize `OpenSamlInitializationService` at the beginning of the class: + ++==== + [source,java] + ---- + static { + 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, in the event that you always want to always force the asserting party to reauthenticate the user, you can register your own `AuthnRequestMarshaller`, like so: ++For example, if you always want to always force the asserting party to reauthenticate the user, you can register your own `AuthnRequestMarshaller`: + + [source,java] + ---- +@@ -230,20 +233,20 @@ static { + authnRequest.setForceAuthN(true); + } + } +- ++ + factory.getMarshallerFactory().registerMarshaller(AuthnRequest.DEFAULT_ELEMENT_NAME, marshaller); + }); + } + ---- + +-The `requireInitialize` method may only be called once per application instance. ++The `requireInitialize` method may be called only 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. ++Spring Boot generates two `@Bean` objects for a relying party. + +-The first is a `WebSecurityConfigurerAdapter` that configures the app as a relying party. ++The first is a `WebSecurityConfigurerAdapter` that configures the application as a relying party. + When including `spring-security-saml2-service-provider`, the `WebSecurityConfigurerAdapter` looks like: + + .Default JWT Configuration +@@ -274,7 +277,7 @@ fun configure(http: HttpSecurity) { + ---- + ==== + +-If the application doesn't expose a `WebSecurityConfigurerAdapter` bean, then Spring Boot will expose the above default one. ++If the application does not expose a `WebSecurityConfigurerAdapter` bean, Spring Boot exposes the preceding default one. + + You can replace this by exposing the bean within the application: + +@@ -315,14 +318,14 @@ class MyCustomSecurityConfiguration : WebSecurityConfigurerAdapter() { + ---- + ==== + +-The above requires the role of `USER` for any URL that starts with `/messages/`. ++The preceding example 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. ++This includes such things as 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: ++For example, you can look up the asserting party's configuration by hitting its metadata endpoint: + + .Relying Party Registration Repository + ==== +@@ -342,7 +345,7 @@ public RelyingPartyRegistrationRepository relyingPartyRegistrations() { + ---- + ==== + +-Or you can provide each detail manually, as you can see below: ++Alternatively, you can provide each detail manually: + + .Relying Party Registration Repository Manual Configuration + ==== +@@ -369,12 +372,10 @@ public RelyingPartyRegistrationRepository relyingPartyRegistrations() throws Exc + ---- + ==== + +-[NOTE] +-Note that `X509Support` is an OpenSAML class, used here in the snippet for brevity ++NOTE: `X509Support` is an OpenSAML class, used in the preceding 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`: ++Alternatively, you can directly wire up the repository by using the DSL, which also overrides the auto-configured `WebSecurityConfigurerAdapter`: + + .Custom Relying Party Registration DSL + ==== +@@ -416,20 +417,20 @@ class MyCustomSecurityConfiguration : WebSecurityConfigurerAdapter() { + ---- + ==== + +-[NOTE] +-A relying party can be multi-tenant by registering more than one relying party in the `RelyingPartyRegistrationRepository`. ++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. ++instance represents a link between an relying party and an asserting 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. ++In a `RelyingPartyRegistration`, you can provide relying party metadata, such as its `Issuer` value, where it expects SAML Responses to be sent, 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. ++Also, you can provide asserting party metadata such as its `Issuer` value, where it expects AuthnRequests to be sent, 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: + ++==== + [source,java] + ---- + RelyingPartyRegistration relyingPartyRegistration = RelyingPartyRegistrations +@@ -437,9 +438,11 @@ RelyingPartyRegistration relyingPartyRegistration = RelyingPartyRegistrations + .registrationId("my-id") + .build(); + ---- ++==== + +-Though a more sophisticated setup is also possible, like so: ++A more sophisticated setup is also possible: + ++==== + [source,java] + ---- + RelyingPartyRegistration relyingPartyRegistration = RelyingPartyRegistration.withRegistrationId("my-id") +@@ -452,26 +455,25 @@ RelyingPartyRegistration relyingPartyRegistration = RelyingPartyRegistration.wit + .singleSignOnServiceLocation("https://ap.example.org/SSO.saml2") + ); + ---- ++==== + +-[TIP] +-The top-level metadata methods are details about the relying party. ++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. ++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. ++You need this value when you configure 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 <> in the filter chain. ++By default, it is mapped to <> in the filter chain. + + [[servlet-saml2login-rpr-uripatterns]] + ==== URI Patterns + +-You probably noticed in the above examples the `+{baseUrl}+` and `+{registrationId}+` placeholders. ++You probably noticed the `+{baseUrl}+` and `+{registrationId}+` placeholders in the preceding examples. + +-These are useful for generating URIs. As such, the relying party's `entityId` and `assertionConsumerServiceLocation` support the following placeholders: ++These are useful for generating URIs. As a result, 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 +@@ -479,37 +481,38 @@ These are useful for generating URIs. As such, the relying party's `entityId` an + * `baseHost` - the host of a deployed application + * `basePort` - the port of a deployed application + +-For example, the `assertionConsumerServiceLocation` defined above was: ++For example, the `assertionConsumerServiceLocation` defined earlier was: + + `+/my-login-endpoint/{registrationId}+` + +-which in a deployed application would translate to ++In a deployed application, it translates to: + + `+/my-login-endpoint/adfs+` + +-The `entityId` above was defined as: ++The `entityId` shown earlier was defined as: + + `+{baseUrl}/{registrationId}+` + +-which in a deployed application would translate to ++In a deployed application, that translates to: + + `+https://rp.example.com/adfs+` + + [[servlet-saml2login-rpr-credentials]] + ==== Credentials + +-You also likely noticed the credential that was used. ++In the example shown <>, 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. ++Oftentimes, a relying party uses the same key to sign payloads as well as decrypt them. ++Alternatively, it can 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. ++At a minimum, you need 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: ++To construct a `Saml2X509Credential` that you can use to verify assertions from the asserting party, you can load the file and use ++the `CertificateFactory`: + ++==== + [source,java] + ---- + Resource resource = new ClassPathResource("ap.crt"); +@@ -519,13 +522,15 @@ try (InputStream is = resource.getInputStream()) { + return Saml2X509Credential.verification(certificate); + } + ---- ++==== + +-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. ++Suppose that the asserting party is going to also encrypt the assertion. ++In that case, the relying party needs a private key 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: ++In that case, you need an `RSAPrivateKey` as well as its corresponding `X509Certificate`. ++You can load the first by using Spring Security's `RsaKeyConverters` utility class and the second as you did before: + ++==== + [source,java] + ---- + X509Certificate certificate = relyingPartyDecryptionCertificate(); +@@ -535,25 +540,26 @@ try (InputStream is = resource.getInputStream()) { + 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. ++TIP: When you specify the locations of these files as the appropriate Spring Boot properties, Spring Boot performs 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. ++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 want to customize for a number of reasons, including: + +-* 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 ++* You may know that your application is never going to be a multi-tenant application and, as a result, want 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`. +-The default looks up the registration id from the URI's last path element and looks it up in your `RelyingPartyRegistrationRepository`. ++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: + ++==== + [source,java] + ---- + public class SingleRelyingPartyRegistrationResolver +@@ -565,11 +571,11 @@ public class SingleRelyingPartyRegistrationResolver + } + } + ---- ++==== + +-Then, you can provide this resolver to the appropriate filters that <` s>>, <` s>>, and <` metadata>>. ++Then you can provide this resolver to the appropriate filters that <` instances>>, <` instances>>, and <` metadata>>. + +-[NOTE] +-Remember that if you have any placeholders in your `RelyingPartyRegistration`, your resolver implementation should resolve them. ++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 +@@ -577,15 +583,16 @@ Remember that if you have any placeholders in your `RelyingPartyRegistration`, y + 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 ++* Its `assertionConsumerServiceLocation` ++* 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. ++This setup may let credentials be more easily rotated for some identity providers versus others. + + The duplication can be alleviated in a few different ways. + +-First, in YAML this can be alleviated with references, like so: ++First, in YAML this can be alleviated with references: + ++==== + [source,yaml] + ---- + spring: +@@ -603,11 +610,13 @@ spring: + identityprovider: + entity-id: ... + ---- ++==== + +-Second, in a database, it's not necessary to replicate `RelyingPartyRegistration` 's model. ++Second, in a database, you need not replicate the model of `RelyingPartyRegistration`. + +-Third, in Java, you can create a custom configuration method, like so: ++Third, in Java, you can create a custom configuration method: + ++==== + [source,java] + ---- + private RelyingPartyRegistration.Builder +@@ -633,29 +642,29 @@ public RelyingPartyRegistrationRepository relyingPartyRegistrations() { + return new InMemoryRelyingPartyRegistrationRepository(okta, azure); + } + ---- ++==== + + [[servlet-saml2login-sp-initiated-factory]] +-=== Producing `` s ++=== Producing `` Instances + +-As stated earlier, Spring Security's SAML 2.0 support produces a `` to commence authentication with the asserting party. ++As stated earlier, Spring Security's SAML 2.0 support produces a `` to start 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}+`. ++Spring Security achieves this, in part, by registering the `Saml2WebSsoAuthenticationRequestFilter` in the filter chain. ++By default, this filter responds to the `+/saml2/authenticate/{registrationId}+` endpoint. + +-For example, if you were deployed to `https://rp.example.com` and you gave your registration an ID of `okta`, you could navigate to: ++For example, if you were deployed to `https://rp.example.com` and 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 ``. ++The result should be a redirect that includes a `SAMLRequest` parameter containing the signed, deflated, and encoded ``. + + [[servlet-saml2login-sp-initiated-factory-signing]] + ==== Changing How the `` Gets Sent + +-By default, Spring Security signs each `` and send it as a GET to the asserting party. +- +-Many asserting parties don't require a signed ``. +-This can be configured automatically via `RelyingPartyRegistrations`, or you can supply it manually, like so: ++By default, Spring Security signs each `` and sends it as a `GET` to the asserting party. + ++Many asserting parties do not require a signed ``. ++This can be configured automatically by `RelyingPartyRegistrations`, or you can supply it manually: + + .Not Requiring Signed AuthnRequests + ==== +@@ -684,15 +693,16 @@ RelyingPartyRegistration relyingPartyRegistration = RelyingPartyRegistration.wit + ---- + ==== + +-Otherwise, you will need to specify a private key to `RelyingPartyRegistration#signingX509Credentials` so that Spring Security can sign the `` before sending. ++Otherwise, you need to specify a private key to `RelyingPartyRegistration#signingX509Credentials` so that Spring Security can sign the `` before sending. + + [[servlet-saml2login-sp-initiated-factory-algorithm]] +-By default, Spring Security will sign the `` using `rsa-sha256`, though some asserting parties will require a different algorithm, as indicated in their metadata. ++By default, Spring Security signs the `` by using `rsa-sha256`, though some asserting parties require a different algorithm, as indicated in their metadata. + +-You can configure the algorithm based on the asserting party's <>. ++You can configure the algorithm based on the asserting party's <>. + +-Or, you can provide it manually: ++Alternatively, you can provide it manually: + ++==== + [source,java] + ---- + String metadataLocation = "classpath:asserting-party-metadata.xml"; +@@ -703,15 +713,17 @@ RelyingPartyRegistration relyingPartyRegistration = RelyingPartyRegistrations.fr + .signingAlgorithms((sign) -> sign.add(SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA512)) + ); + ---- ++==== + +-NOTE: The snippet above uses the OpenSAML `SignatureConstants` class to supply the algorithm name. +-But, that's just for convenience. ++NOTE: The preceding snippet uses the OpenSAML `SignatureConstants` class to supply the algorithm name. ++However, that is only 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 `` be POSTed. +-This can be configured automatically via `RelyingPartyRegistrations`, or you can supply it manually, like so: ++This can be configured automatically through `RelyingPartyRegistrations`, or you can supply it manually: + ++==== + [source,java] + ---- + RelyingPartyRegistration relyingPartyRegistration = RelyingPartyRegistration.withRegistrationId("okta") +@@ -721,19 +733,20 @@ RelyingPartyRegistration relyingPartyRegistration = RelyingPartyRegistration.wit + .singleSignOnServiceBinding(Saml2MessageType.POST) + ); + ---- +- ++==== + + [[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. ++You may want to adjust an `AuthnRequest` for a number of reasons. ++For example, you may want `ForceAuthN` to be set to `true`. By default, Spring Security sets it to `false`. + +-If you don't need information from the `HttpServletRequest` to make your decision, then the easiest way is to <>. +-This will give you access to post-process the `AuthnRequest` instance before it's serialized. ++If you do not need information from the `HttpServletRequest` to make your decision, the easiest way is to <>. ++This gives you access to post-process the `AuthnRequest` instance before it is serialized. + +-But, if you do need something from the request, then you can use create a custom `Saml2AuthenticationRequestContext` implementation and then a `Converter` to build an `AuthnRequest` yourself, like so: ++However, if you do need something from the request, you can use create a custom `Saml2AuthenticationRequestContext` implementation and then a `Converter` to build an `AuthnRequest` yourself: + ++==== + [source,java] + ---- + @Component +@@ -762,9 +775,11 @@ public class AuthnRequestConverter implements + } + } + ---- ++==== + +-Then, you can construct your own `Saml2AuthenticationRequestContextResolver` and `Saml2AuthenticationRequestFactory` and publish them as `@Bean` s: ++Then you can construct your own `Saml2AuthenticationRequestContextResolver` and `Saml2AuthenticationRequestFactory` and publish them as `@Bean` objects: + ++==== + [source,java] + ---- + @Bean +@@ -787,27 +802,29 @@ Saml2AuthenticationRequestFactory authenticationRequestFactory( + return authenticationRequestFactory; + } + ---- ++==== + + [[servlet-saml2login-authenticate-responses]] +-=== Authenticating `` s ++=== Authenticating `` Instances + + To verify SAML 2.0 Responses, Spring Security uses <> by default. + +-You can configure this in a number of ways including: ++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 ++* Setting a clock skew to timestamp validation ++* Mapping the response to a list of `GrantedAuthority` instances ++* Customizing the strategy for validating assertions ++* Customizing the strategy for decrypting response and assertion elements + +-To configure these, you'll use the `saml2Login#authenticationManager` method in the DSL. ++To configure these, you can 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 `OpenSamlAuthenticationProvider` 's default assertion validator with some tolerance: ++Often, the asserting and relying parties have system clocks that are not perfectly synchronized. ++For that reason, you can configure the default assertion validator of `OpenSamlAuthenticationProvider` with some tolerance: + ++==== + [source,java] + ---- + @EnableWebSecurity +@@ -835,13 +852,15 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter { + } + } + ---- ++==== + + [[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: ++Alternatively, you might like to include user details from a legacy `UserDetailsService`. ++In that case, the response authentication converter can come in handy: + ++==== + [source,java] + ---- + @EnableWebSecurity +@@ -872,28 +891,29 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter { + } + } + ---- +-<1> First, call the default converter, which extracts attributes and authorities from the response +-<2> Second, call the <> using the relevant information +-<3> Third, return a custom authentication that includes the user details ++<1> Call the default converter, which extracts attributes and authorities from the response ++<2> Call the <> by using the relevant information ++<3> Return a custom authentication that includes the user details ++==== + +-[NOTE] +-It's not required to call `OpenSamlAuthenticationProvider` 's default authentication converter. +-It returns a `Saml2AuthenticatedPrincipal` containing the attributes it extracted from `AttributeStatement` s as well as the single `ROLE_USER` authority. ++NOTE: You need not call the default authentication converter of `OpenSamlAuthenticationProvider`. ++It returns a `Saml2AuthenticatedPrincipal` that contains the attributes it extracted from `AttributeStatement` instances as well as the single `ROLE_USER` authority. + + [[servlet-saml2login-opensamlauthenticationprovider-additionalvalidation]] + ==== Performing Additional Validation + + `OpenSamlAuthenticationProvider` performs minimal validation on SAML 2.0 Assertions. +-After verifying the signature, it will: ++After verifying the signature, it: + +-1. Validate `` and `` conditions +-2. Validate `` s, expect for any IP address information ++. Validates `` and `` conditions ++. Validates `` instances, expect for any IP address information + +-To perform additional validation, you can configure your own assertion validator that delegates to `OpenSamlAuthenticationProvider` 's default and then performs its own. ++To perform additional validation, you can configure your own assertion validator that delegates to the default of `OpenSamlAuthenticationProvider` and then performs its own validation. + + [[servlet-saml2login-opensamlauthenticationprovider-onetimeuse]] +-For example, you can use OpenSAML's `OneTimeUseConditionValidator` to also validate a `` condition, like so: ++For example, you can use OpenSAML's `OneTimeUseConditionValidator` to also validate a `` condition: + ++==== + [source,java] + ---- + OpenSamlAuthenticationProvider provider = new OpenSamlAuthenticationProvider(); +@@ -915,10 +935,10 @@ provider.setAssertionValidator(assertionToken -> { + return result.contact(new Saml2Error(INVALID_ASSERTION, context.getValidationFailureMessage())); + }); + ---- ++==== + +-[NOTE] +-While recommended, it's not necessary to call `OpenSamlAuthenticationProvider` 's default assertion validator. +-A circumstance where you would skip it would be if you don't need it to check the `` or the `` since you are doing those yourself. ++NOTE: While recommended, you need not call the default assertion validator of `OpenSamlAuthenticationProvider`. ++For example, you could skip it if you do not need to check the `` or the `` because you are doing those yourself. + + [[servlet-saml2login-opensamlauthenticationprovider-decryption]] + ==== Customizing Decryption +@@ -926,37 +946,42 @@ A circumstance where you would skip it would be if you don't need it to check th + Spring Security decrypts ``, ``, and `` elements automatically by using the decryption <> registered in the <>. + + `OpenSamlAuthenticationProvider` exposes <>. +-The response decrypter is for decrypting encrypted elements of the ``, like ``. +-The assertion decrypter is for decrypting encrypted elements of the ``, like `` and ``. ++The response decrypter decrypts encrypted elements of the ``, such as ``. ++The assertion decrypter decrypts encrypted elements of the ``, such as `` and ``. + +-You can replace `OpenSamlAuthenticationProvider`'s default decryption strategy with your own. +-For example, if you have a separate service that decrypts the assertions in a ``, you can use it instead like so: ++You can replace the default decryption strategy of `OpenSamlAuthenticationProvider` with your own strategy. ++For example, if you have a separate service that decrypts the assertions in a ``, you can use it instead: + ++==== + [source,java] + ---- + MyDecryptionService decryptionService = ...; + OpenSamlAuthenticationProvider provider = new OpenSamlAuthenticationProvider(); + provider.setResponseElementsDecrypter((responseToken) -> decryptionService.decrypt(responseToken.getResponse())); + ---- ++==== + +-If you are also decrypting individual elements in a ``, you can customize the assertion decrypter, too: ++If you also decrypt individual elements in a ``, you can customize the assertion decrypter, too: + ++==== + [source,java] + ---- + provider.setAssertionElementsDecrypter((assertionToken) -> decryptionService.decrypt(assertionToken.getAssertion())); + ---- ++==== + +-NOTE: There are two separate decrypters since assertions can be signed separately from responses. ++NOTE: We have two separate decrypters, because 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. ++If your asserting party signs only the response, it is safe to decrypt all elements by 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. ++You can also use the `authenticationManager` DSL method to perform a completely custom SAML 2.0 authentication. ++This authentication manager should expect a `Saml2AuthenticationToken` object that contains the SAML 2.0 Response XML data. + ++==== + [source,java] + ---- + @EnableWebSecurity +@@ -976,15 +1001,17 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter { + } + } + ---- ++==== + + [[servlet-saml2login-authenticatedprincipal]] +-=== Using `Saml2AuthenticatedPrincipal` ++=== Using the `Saml2AuthenticatedPrincipal` + +-With the relying party correctly configured for a given asserting party, it's ready to accept assertions. ++With the relying party correctly configured for a given asserting party, it is 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: ++This means that you can access the principal in your controller: + ++==== + [source,java] + ---- + @Controller +@@ -997,16 +1024,17 @@ public class MainController { + } + } + ---- ++==== + +-[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. ++TIP: Because the SAML 2.0 specification lets each attribute 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 handy when you know that there is only one value. + + [[servlet-saml2login-metadata]] + === Producing `` Metadata + +-You can publish a metadata endpoint by adding the `Saml2MetadataFilter` to the filter chain, as you'll see below: ++You can publish a metadata endpoint by adding the `Saml2MetadataFilter` to the filter chain: + ++==== + [source,java] + ---- + Converter relyingPartyRegistrationResolver = +@@ -1020,26 +1048,31 @@ http + .saml2Login(withDefaults()) + .addFilterBefore(new Saml2MetadataFilter(r), Saml2WebSsoAuthenticationFilter.class); + ---- ++==== + + 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. ++This is often as simple as finding the correct form field to supply to 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: + ++==== + [source,java] + ---- + filter.setRequestMatcher(new AntPathRequestMatcher("/saml2/metadata/{registrationId}", "GET")); + ---- ++==== + +-ensuring that the `registrationId` hint is at the end of the path. ++Doing so ensures 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: ++Alternatively, if you have registered a custom relying party registration resolver in the constructor, you can specify a path without a `registrationId` hint: + ++==== + [source,java] + ---- + filter.setRequestMatcher(new AntPathRequestMatcher("/saml2/metadata", "GET")); + ---- ++==== + + [[servlet-saml2login-logout]] + === Performing Single Logout +@@ -1048,6 +1081,7 @@ Spring Security does not yet support single logout. + + Generally speaking, though, you can achieve this by creating and registering a custom `LogoutSuccessHandler` and `RequestMatcher`: + ++==== + [source,java] + ---- + http +@@ -1057,7 +1091,8 @@ http + .logoutRequestMatcher(myRequestMatcher()) + ) + ---- ++==== + +-The success handler will send logout requests to the asserting party. ++The success handler sends logout requests to the asserting party. + +-The request matcher will detect logout requests from the asserting party. ++The request matcher detects logout requests from the asserting party. +diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/test/index.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/test/index.adoc +index da7d74db4a..ae8ef2de74 100644 +--- a/docs/manual/src/docs/asciidoc/_includes/servlet/test/index.adoc ++++ b/docs/manual/src/docs/asciidoc/_includes/servlet/test/index.adoc +@@ -3,10 +3,7 @@ + + This section describes the testing support provided by Spring Security. + +-[TIP] +-==== +-To use the Spring Security test support, you must include `spring-security-test-{spring-security-version}.jar` as a dependency of your project. +-==== ++NOTE: To use the Spring Security test support, you must include `spring-security-test-{spring-security-version}.jar` as a dependency of your project. + + include::method.adoc[] + +diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/test/method.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/test/method.adoc +index 6bc7272347..316cf6c4d0 100644 +--- a/docs/manual/src/docs/asciidoc/_includes/servlet/test/method.adoc ++++ b/docs/manual/src/docs/asciidoc/_includes/servlet/test/method.adoc +@@ -1,9 +1,10 @@ + [[test-method]] + == 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. ++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 to be able to access it: + ++==== + [source,java] + ---- + public class HelloMessageService implements MessageService { +@@ -16,41 +17,46 @@ public class HelloMessageService implements MessageService { + } + } + ---- ++==== + +-The result of `getMessage` is a String saying "Hello" to the current Spring Security `Authentication`. +-An example of the output is displayed below. ++The result of `getMessage` is a `String` that says "`Hello`" to the current Spring Security `Authentication`. ++The follwoing listing shows example output: + ++==== + [source,text] + ---- + Hello org.springframework.security.authentication.UsernamePasswordAuthenticationToken@ca25360: Principal: org.springframework.security.core.userdetails.User@36ebcb: Username: user; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: ROLE_USER; Credentials: [PROTECTED]; Authenticated: true; Details: null; Granted Authorities: ROLE_USER + ---- ++==== + + [[test-method-setup]] + === Security Test Setup + +-Before we can use Spring Security Test support, we must perform some setup. An example can be seen below: ++Before we can use the Spring Security test support, we must perform some setup: + ++==== + [source,java] + ---- + @RunWith(SpringJUnit4ClassRunner.class) // <1> + @ContextConfiguration // <2> + public class WithMockUserTests { ++ ... ++} + ---- ++<1> `@RunWith` instructs the spring-test module that it should create an `ApplicationContext`. This is no different than using the existing Spring Test support. For additional information, see the https://docs.spring.io/spring-framework/docs/4.0.x/spring-framework-reference/htmlsingle/#integration-testing-annotations-standard[Spring Reference]. ++<2> `@ContextConfiguration` instructs the Spring test configuration to use to create the `ApplicationContext`. Since no configuration is specified, the default configuration locations are tried. This is no different than using the existing Spring test support. For additional information, see the https://docs.spring.io/spring-framework/docs/4.0.x/spring-framework-reference/htmlsingle/#testcontext-ctx-management[Spring Reference]. ++==== + +-This is a basic example of how to setup Spring Security Test. The highlights are: +- +-<1> `@RunWith` instructs the spring-test module that it should create an `ApplicationContext`. This is no different than using the existing Spring Test support. For additional information, refer to the https://docs.spring.io/spring-framework/docs/4.0.x/spring-framework-reference/htmlsingle/#integration-testing-annotations-standard[Spring Reference] +-<2> `@ContextConfiguration` instructs the spring-test the configuration to use to create the `ApplicationContext`. Since no configuration is specified, the default configuration locations will be tried. This is no different than using the existing Spring Test support. For additional information, refer to the https://docs.spring.io/spring-framework/docs/4.0.x/spring-framework-reference/htmlsingle/#testcontext-ctx-management[Spring Reference] +- +-NOTE: Spring Security hooks into Spring Test support using the `WithSecurityContextTestExecutionListener` which will ensure our tests are ran with the correct user. ++NOTE: Spring Security hooks into Spring Test support through the `WithSecurityContextTestExecutionListener`, which ensures that our tests are run with the correct user. + It does this by populating the `SecurityContextHolder` prior to running our tests. +-If you are using reactive method security, you will also need `ReactorContextTestExecutionListener` which populates `ReactiveSecurityContextHolder`. +-After the test is done, it will clear out the `SecurityContextHolder`. +-If you only need Spring Security related support, you can replace `@ContextConfiguration` with `@SecurityTestExecutionListeners`. ++If you use reactive method security, you also need `ReactorContextTestExecutionListener`, which populates `ReactiveSecurityContextHolder`. ++After the test is done, it clears out the `SecurityContextHolder`. ++If you need only Spring Security related support, you can replace `@ContextConfiguration` with `@SecurityTestExecutionListeners`. + +-Remember we added the `@PreAuthorize` annotation to our `HelloMessageService` and so it requires an authenticated user to invoke it. +-If we ran the following test, we would expect the following test will pass: ++Remember, we added the `@PreAuthorize` annotation to our `HelloMessageService`, so it requires an authenticated user to invoke it. ++If we run the tests, we expect the following test will pass: + ++==== + [source,java] + ---- + @Test(expected = AuthenticationCredentialsNotFoundException.class) +@@ -58,14 +64,16 @@ public void getMessageUnauthenticated() { + messageService.getMessage(); + } + ---- ++==== + + [[test-method-withmockuser]] + === @WithMockUser + +-The question is "How could we most easily run the test as a specific user?" ++The question is "`How could we most easily run the test as a specific user?`" + The answer is to use `@WithMockUser`. +-The following test will be run as a user with the username "user", the password "password", and the roles "ROLE_USER". ++The following test runs as a user with a username of `user`, a password of `password`, and the role of `ROLE_USER`. + ++==== + [source,java] + ---- + @Test +@@ -75,18 +83,22 @@ String message = messageService.getMessage(); + ... + } + ---- ++==== + + Specifically the following is true: + +-* The user with the username "user" does not have to exist since we are mocking the user +-* The `Authentication` that is populated in the `SecurityContext` is of type `UsernamePasswordAuthenticationToken` +-* The principal on the `Authentication` is Spring Security's `User` object +-* The `User` will have the username of "user", the password "password", and a single `GrantedAuthority` named "ROLE_USER" is used. ++* The user with a username of `user` does not have to exist, since we mock the user object. ++* The `Authentication` that is populated in the `SecurityContext` is of type `UsernamePasswordAuthenticationToken`. ++* The principal on the `Authentication` is Spring Security's `User` object. ++* The `User` has a username of `user`. ++* The `User` has a password of `password`. ++* A single `GrantedAuthority` named `ROLE_USER` is used. + +-Our example is nice because we are able to leverage a lot of defaults. ++The preceding example is handy, because it lets us use a lot of defaults. + What if we wanted to run the test with a different username? +-The following test would run with the username "customUser". Again, the user does not need to actually exist. ++The following test would run with a username of `customUser` (again, the user does not need to actually exist): + ++==== + [source,java] + ---- + @Test +@@ -96,10 +108,12 @@ public void getMessageWithMockUserCustomUsername() { + ... + } + ---- ++==== + + We can also easily customize the roles. +-For example, this test will be invoked with the username "admin" and the roles "ROLE_USER" and "ROLE_ADMIN". ++For example, the following test is invoked with a username of `admin` and roles of `ROLE_USER` and `ROLE_ADMIN`. + ++==== + [source,java] + ---- + @Test +@@ -109,10 +123,12 @@ public void getMessageWithMockUserCustomUser() { + ... + } + ---- ++==== + +-If we do not want the value to automatically be prefixed with ROLE_ we can leverage the authorities attribute. +-For example, this test will be invoked with the username "admin" and the authorities "USER" and "ADMIN". ++If we do not want the value to automatically be prefixed with `ROLE_` we can use the `authorities` attribute. ++For example, the following test is invoked with a username of `admin` and the `USER` and `ADMIN` authorities. + ++==== + [source,java] + ---- + @Test +@@ -122,22 +138,28 @@ public void getMessageWithMockUserCustomAuthorities() { + ... + } + ---- ++==== + +-Of course it can be a bit tedious placing the annotation on every test method. +-Instead, we can place the annotation at the class level and every test will use the specified user. +-For example, the following would run every test with a user with the username "admin", the password "password", and the roles "ROLE_USER" and "ROLE_ADMIN". ++It can be a bit tedious to place the annotation on every test method. ++Instead, we can place the annotation at the class level. Then every test uses the specified user. ++The following example runs every test with a user whose username is `admin`, whose password is `password`, and who has the `ROLE_USER` and `ROLE_ADMIN` roles: + ++==== + [source,java] + ---- + @RunWith(SpringJUnit4ClassRunner.class) + @ContextConfiguration + @WithMockUser(username="admin",roles={"USER","ADMIN"}) + public class WithMockUserTests { ++ ... ++} + ---- ++==== + +-If you are using JUnit 5's `@Nested` test support, you can also place the annotation on the enclosing class to apply to all nested classes. +-For example, the following would run every test with a user with the username "admin", the password "password", and the roles "ROLE_USER" and "ROLE_ADMIN" for both test methods. ++If you use JUnit 5's `@Nested` test support, you can also place the annotation on the enclosing class to apply to all nested classes. ++The following example runs every test with a user whose username is `admin`, whose password is `password`, and who has the `ROLE_USER` and `ROLE_ADMIN` roles for both test methods. + ++==== + [source,java] + ---- + @ExtendWith(SpringExtension.class) +@@ -156,24 +178,27 @@ public class WithMockUserTests { + } + } + ---- ++==== + +-By default the `SecurityContext` is set during the `TestExecutionListener.beforeTestMethod` event. ++By default, the `SecurityContext` is set during the `TestExecutionListener.beforeTestMethod` event. + This is the equivalent of happening before JUnit's `@Before`. +-You can change this to happen during the `TestExecutionListener.beforeTestExecution` event which is after JUnit's `@Before` but before the test method is invoked. ++You can change this to happen during the `TestExecutionListener.beforeTestExecution` event, which is after JUnit's `@Before` but before the test method is invoked: + ++==== + [source,java] + ---- + @WithMockUser(setupBefore = TestExecutionEvent.TEST_EXECUTION) + ---- +- ++==== + + [[test-method-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. +-For example, the following will run withMockUser1 and withMockUser2 using <> and anonymous 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. ++The following example runs `withMockUser1` and `withMockUser2` by using <> and `anonymous` as an anonymous user: + ++==== + [source,java] + ---- + @RunWith(SpringJUnit4ClassRunner.class) +@@ -195,30 +220,33 @@ public class WithUserClassLevelAuthenticationTests { + } + } + ---- ++==== + +-By default the `SecurityContext` is set during the `TestExecutionListener.beforeTestMethod` event. ++By default, the `SecurityContext` is set during the `TestExecutionListener.beforeTestMethod` event. + This is the equivalent of happening before JUnit's `@Before`. +-You can change this to happen during the `TestExecutionListener.beforeTestExecution` event which is after JUnit's `@Before` but before the test method is invoked. ++You can change this to happen during the `TestExecutionListener.beforeTestExecution` event, which is after JUnit's `@Before` but before the test method is invoked: + ++==== + [source,java] + ---- + @WithAnonymousUser(setupBefore = TestExecutionEvent.TEST_EXECUTION) + ---- +- ++==== + + [[test-method-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. ++While `@WithMockUser` is a convenient way to get started, it may not work in all instances. ++For example, some applications expect the `Authentication` principal to be of a specific type. + This is done so that the application can refer to the principal as the custom type and reduce coupling on Spring Security. + +-The custom principal is often times returned by a custom `UserDetailsService` that returns an object that implements both `UserDetails` and the custom type. +-For situations like this, it is useful to create the test user using the custom `UserDetailsService`. ++The custom principal is often returned by a custom `UserDetailsService` that returns an object that implements both `UserDetails` and the custom type. ++For situations like this, it is useful to create the test user by using a custom `UserDetailsService`. + That is exactly what `@WithUserDetails` does. + +-Assuming we have a `UserDetailsService` exposed as a bean, the following test will be invoked with an `Authentication` of type `UsernamePasswordAuthenticationToken` and a principal that is returned from the `UserDetailsService` with the username of "user". ++Assuming we have a `UserDetailsService` exposed as a bean, the following test is invoked with an `Authentication` of type `UsernamePasswordAuthenticationToken` and a principal that is returned from the `UserDetailsService` with the username of `user`: + ++==== + [source,java] + ---- + @Test +@@ -228,10 +256,12 @@ public void getMessageWithUserDetails() { + ... + } + ---- ++==== + + We can also customize the username used to lookup the user from our `UserDetailsService`. +-For example, this test would be run with a principal that is returned from the `UserDetailsService` with the username of "customUsername". ++For example, this test can be run with a principal that is returned from the `UserDetailsService` with the username of `customUsername`: + ++==== + [source,java] + ---- + @Test +@@ -241,10 +271,12 @@ public void getMessageWithUserDetailsCustomUsername() { + ... + } + ---- ++==== + + We can also provide an explicit bean name to look up the `UserDetailsService`. +-For example, this test would look up the username of "customUsername" using the `UserDetailsService` with the bean name "myUserDetailsService". ++The following test looks up the username of `customUsername` by using the `UserDetailsService` with a bean name of `myUserDetailsService`: + ++==== + [source,java] + ---- + @Test +@@ -254,30 +286,33 @@ public void getMessageWithUserDetailsServiceBeanName() { + ... + } + ---- ++==== + +-Like `@WithMockUser` we can also place our annotation at the class level so that every test uses the same user. +-However unlike `@WithMockUser`, `@WithUserDetails` requires the user to exist. ++As we did with `@WithMockUser`, we can also place our annotation at the class level so that every test uses the same user. ++However, unlike `@WithMockUser`, `@WithUserDetails` requires the user to exist. + +-By default the `SecurityContext` is set during the `TestExecutionListener.beforeTestMethod` event. ++By default, the `SecurityContext` is set during the `TestExecutionListener.beforeTestMethod` event. + This is the equivalent of happening before JUnit's `@Before`. +-You can change this to happen during the `TestExecutionListener.beforeTestExecution` event which is after JUnit's `@Before` but before the test method is invoked. ++You can change this to happen during the `TestExecutionListener.beforeTestExecution` event, which is after JUnit's `@Before` but before the test method is invoked: + ++==== + [source,java] + ---- + @WithUserDetails(setupBefore = TestExecutionEvent.TEST_EXECUTION) + ---- +- ++==== + + [[test-method-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. +-We will now see an option that allows the most flexibility. ++We have seen that `@WithMockUser` is an excellent choice if we do not use a custom `Authentication` principal. ++Next, we discovered that `@WithUserDetails` lets us use a custom `UserDetailsService` to create our `Authentication` principal but requires the user to exist. ++We now see an option that allows the most flexibility. + + We can create our own annotation that uses the `@WithSecurityContext` to create any `SecurityContext` we want. +-For example, we might create an annotation named `@WithMockCustomUser` as shown below: ++For example, we might create an annotation named `@WithMockCustomUser`: + ++==== + [source,java] + ---- + @Retention(RetentionPolicy.RUNTIME) +@@ -289,12 +324,14 @@ public @interface WithMockCustomUser { + String name() default "Rob Winch"; + } + ---- ++==== + + You can see that `@WithMockCustomUser` is annotated with the `@WithSecurityContext` annotation. +-This is what signals to Spring Security Test support that we intend to create a `SecurityContext` for the test. +-The `@WithSecurityContext` annotation requires we specify a `SecurityContextFactory` that will create a new `SecurityContext` given our `@WithMockCustomUser` annotation. +-You can find our `WithMockCustomUserSecurityContextFactory` implementation below: ++This is what signals to Spring Security test support that we intend to create a `SecurityContext` for the test. ++The `@WithSecurityContext` annotation requires that we specify a `SecurityContextFactory` to create a new `SecurityContext`, given our `@WithMockCustomUser` annotation. ++The following listing shows our `WithMockCustomUserSecurityContextFactory` implementation: + ++==== + [source,java] + ---- + public class WithMockCustomUserSecurityContextFactory +@@ -312,12 +349,14 @@ public class WithMockCustomUserSecurityContextFactory + } + } + ---- ++==== + +-We can now annotate a test class or a test method with our new annotation and Spring Security's `WithSecurityContextTestExecutionListener` will ensure that our `SecurityContext` is populated appropriately. ++We can now annotate a test class or a test method with our new annotation and Spring Security's `WithSecurityContextTestExecutionListener` to ensure that our `SecurityContext` is populated appropriately. + + When creating your own `WithSecurityContextFactory` implementations, it is nice to know that they can be annotated with standard Spring annotations. + For example, the `WithUserDetailsSecurityContextFactory` uses the `@Autowired` annotation to acquire the `UserDetailsService`: + ++==== + [source,java] + ---- + final class WithUserDetailsSecurityContextFactory +@@ -341,39 +380,45 @@ final class WithUserDetailsSecurityContextFactory + } + } + ---- ++==== + +-By default the `SecurityContext` is set during the `TestExecutionListener.beforeTestMethod` event. ++By default, the `SecurityContext` is set during the `TestExecutionListener.beforeTestMethod` event. + This is the equivalent of happening before JUnit's `@Before`. +-You can change this to happen during the `TestExecutionListener.beforeTestExecution` event which is after JUnit's `@Before` but before the test method is invoked. ++You can change this to happen during the `TestExecutionListener.beforeTestExecution` event, which is after JUnit's `@Before` but before the test method is invoked: + ++==== + [source,java] + ---- + @WithSecurityContext(setupBefore = TestExecutionEvent.TEST_EXECUTION) + ---- +- ++==== + + [[test-method-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: ++For example, if you have many tests related to an administrative user with a username of `admin` and roles of `ROLE_USER` and `ROLE_ADMIN`, you have to write: + ++==== + [source,java] + ---- + @WithMockUser(username="admin",roles={"USER","ADMIN"}) + ---- ++==== + + Rather than repeating this everywhere, we can use a meta annotation. + For example, we could create a meta annotation named `WithMockAdmin`: + ++==== + [source,java] + ---- + @Retention(RetentionPolicy.RUNTIME) + @WithMockUser(value="rob",roles="ADMIN") + public @interface WithMockAdmin { } + ---- ++==== + + Now we can use `@WithMockAdmin` in the same way as the more verbose `@WithMockUser`. + +-Meta annotations work with any of the testing annotations described above. +-For example, this means we could create a meta annotation for `@WithUserDetails("admin")` as well. ++Meta annotations work with any of the testing annotations described in this section. ++For example, this means that we could create a meta annotation for `@WithUserDetails("admin")` as well. +diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/test/mockmvc.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/test/mockmvc.adoc +index 5fe1fbd94d..6a8e3712b1 100644 +--- a/docs/manual/src/docs/asciidoc/_includes/servlet/test/mockmvc.adoc ++++ b/docs/manual/src/docs/asciidoc/_includes/servlet/test/mockmvc.adoc +@@ -6,16 +6,15 @@ Spring Security provides comprehensive integration with https://docs.spring.io/s + [[test-mockmvc-setup]] + === 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 <>. +-This can be done using Spring Security's `SecurityMockMvcConfigurers.springSecurity()`. +-For example: +- + NOTE: Spring Security's testing support requires spring-test-4.1.3.RELEASE or greater. + ++To use Spring Security with Spring MVC Test, add the Spring Security `FilterChainProxy` as a `Filter`. ++You also need to add Spring Security's `TestSecurityContextHolderPostProcessor` to support <>. ++To do so, use Spring Security's `SecurityMockMvcConfigurers.springSecurity()`: ++ ++==== + [source,java] + ---- +- + import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.*; + + @RunWith(SpringJUnit4ClassRunner.class) +@@ -37,129 +36,151 @@ public 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 + +-Spring MVC Test provides a convenient interface called a `RequestPostProcessor` that can be used to modify a request. ++Spring MVC Test provides a convenient interface (`RequestPostProcessor`) that you can use to modify a request. + Spring Security provides a number of `RequestPostProcessor` implementations that make testing easier. +-In order to use Spring Security's `RequestPostProcessor` implementations ensure the following static import is used: ++To use Spring Security's `RequestPostProcessor` implementations, use the following static import: + ++==== + [source,java] + ---- + import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.*; + ---- ++==== + + [[test-mockmvc-csrf]] + ==== 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: ++When testing any non-safe HTTP methods and using Spring Security's CSRF protection, you must include a valid CSRF Token in the request. ++To specify a valid CSRF token as a request parameter, use the following: + ++==== + [source,java] + ---- + mvc + .perform(post("/").with(csrf())) + ---- ++==== + +-If you like you can include CSRF token in the header instead: ++If you like, you can include CSRF token in the header instead: + ++==== + [source,java] + ---- + mvc + .perform(post("/").with(csrf().asHeader())) + ---- ++==== + +-You can also test providing an invalid CSRF token using the following: ++You can also test providing an invalid CSRF token by using the following: + ++==== + [source,java] + ---- + mvc + .perform(post("/").with(csrf().useInvalidToken())) + ---- ++==== + + [[test-mockmvc-securitycontextholder]] + ==== 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: ++There are two simple ways to populate the user: + +-* <> +-* <> ++* <> ++* <> + + [[test-mockmvc-securitycontextholder-rpp]] + ==== 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": ++You have a number of options to associate a user to the current `HttpServletRequest`. ++The following example runs as a user (which does not need to exist) whose username is `user`, whose password is `password`, and whose role is `ROLE_USER`: ++ ++==== ++[source,java] ++---- ++mvc ++ .perform(get("/").with(user("user"))) ++---- ++==== + + [NOTE] + ==== + The support works by associating the user to the `HttpServletRequest`. +-To associate the request to the `SecurityContextHolder` you need to ensure that the `SecurityContextPersistenceFilter` is associated with the `MockMvc` instance. +-A few ways to do this are: ++To associate the request to the `SecurityContextHolder`, you need to ensure that the `SecurityContextPersistenceFilter` is associated with the `MockMvc` instance. ++You can do so in a number of ways: + + * Invoking <> + * Adding Spring Security's `FilterChainProxy` to `MockMvc` + * Manually adding `SecurityContextPersistenceFilter` to the `MockMvc` instance may make sense when using `MockMvcBuilders.standaloneSetup` + ==== + +-[source,java] +----- +-mvc +- .perform(get("/").with(user("user"))) +----- +- +-You can easily make customizations. +-For example, the following will run as a user (which does not need to exist) with the username "admin", the password "pass", and the roles "ROLE_USER" and "ROLE_ADMIN". ++You can make customizations. ++The following example runs as a user (which does not need to exist) whose username is `admin`, whose password is `pass`, and whose roles are `ROLE_USER` and `ROLE_ADMIN`. + ++==== + [source,java] + ---- + mvc + .perform(get("/admin").with(user("admin").password("pass").roles("USER","ADMIN"))) + ---- ++==== + +-If you have a custom `UserDetails` that you would like to use, you can easily specify that as well. +-For example, the following will use the specified `UserDetails` (which does not need to exist) to run with a `UsernamePasswordAuthenticationToken` that has a principal of the specified `UserDetails`: ++If you have a custom `UserDetails` object that you would like to use, you can specify that as well. ++The following example uses the specified `UserDetails` (which does not need to exist) to run with a `UsernamePasswordAuthenticationToken` that has a principal of the specified `UserDetails`: + ++==== + [source,java] + ---- + mvc + .perform(get("/").with(user(userDetails))) + ---- ++==== + +-You can run as anonymous user using the following: ++You can run as anonymous user by using the following: + ++==== + [source,java] + ---- + mvc + .perform(get("/").with(anonymous())) + ---- ++==== + +-This is especially useful if you are running with a default user and wish to process a few requests as an anonymous user. ++This is especially useful when you run with a default user and wish to process a few requests as an anonymous user. + +-If you want a custom `Authentication` (which does not need to exist) you can do so using the following: ++If you want a custom `Authentication` (which does not need to exist), you can do so by using the following: + ++==== + [source,java] + ---- + mvc + .perform(get("/").with(authentication(authentication))) + ---- ++==== + +-You can even customize the `SecurityContext` using the following: ++You can even customize the `SecurityContext`, by using the following: + ++==== + [source,java] + ---- + mvc + .perform(get("/").with(securityContext(securityContext))) + ---- ++==== + +-We can also ensure to run as a specific user for every request by using ``MockMvcBuilders``'s default request. +-For example, the following will run as a user (which does not need to exist) with the username "admin", the password "password", and the role "ROLE_ADMIN": ++We can also ensure running as a specific user for every request by using the default request of `MockMvcBuilders`. ++The following exampe runs as a user (which does not need to exist) whose username is `admin`, whose password is `password`, and whose role is `ROLE_ADMIN`: + ++==== + [source,java] + ---- + mvc = MockMvcBuilders +@@ -168,19 +189,23 @@ mvc = MockMvcBuilders + .apply(springSecurity()) + .build(); + ---- ++==== + +-If you find you are using the same user in many of your tests, it is recommended to move the user to a method. +-For example, you can specify the following in your own class named `CustomSecurityMockMvcRequestPostProcessors`: ++If you find yourself using the same user in many of your tests, we recommended moving the user to a method. ++For example, you can specify the following in your own `CustomSecurityMockMvcRequestPostProcessors` class: + ++==== + [source,java] + ---- + public static RequestPostProcessor rob() { + return user("rob").roles("ADMIN"); + } + ---- ++==== + + Now you can perform a static import on `SecurityMockMvcRequestPostProcessors` and use that within your tests: + ++==== + [source,java] + ---- + import static sample.CustomSecurityMockMvcRequestPostProcessors.*; +@@ -190,12 +215,14 @@ import static sample.CustomSecurityMockMvcRequestPostProcessors.*; + mvc + .perform(get("/").with(rob())) + ---- +- ++==== ++[[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 <>. +-For example, the following will run the test with the user with username "user", password "password", and role "ROLE_USER": ++As an alternative to using a `RequestPostProcessor` to create your user, you can use the annotations described in <>. ++The following example runs the test with a user whose username is `user`, whose password is `password`, and whose role is `ROLE_USER`: + ++==== + [source,java] + ---- + @Test +@@ -206,9 +233,11 @@ mvc + ... + } + ---- ++==== + +-Alternatively, the following will run the test with the user with username "user", password "password", and role "ROLE_ADMIN": ++Alternatively, the following example runs the test with a user whose username is `user`, whose password is `password`, and whose role is `ROLE_ADMIN`: + ++==== + [source,java] + ---- + @Test +@@ -219,33 +248,39 @@ mvc + ... + } + ---- ++==== + + ==== 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`. +-For example, the snippet below: ++Now you can do so by using Spring Security's `httpBasic` `RequestPostProcessor`. ++Consider the following snippet: + ++==== + [source,java] + ---- + mvc + .perform(get("/").with(httpBasic("user","password"))) + ---- ++==== + +-will attempt to use HTTP Basic to authenticate a user with the username "user" and the password "password" by ensuring the following header is populated on the HTTP Request: ++The preceding line tries to use HTTP Basic to authenticate a user whose username is `user` and whose password is `password` by ensuring the following header is populated on the HTTP Request: + ++==== + [source,text] + ---- + Authorization: Basic dXNlcjpwYXNzd29yZA== + ---- ++==== + + [[testing-oauth2]] + ==== 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`. + +-For example, for a controller that looks like this: ++For example, consider the following controller: + ++==== + [source,java] + ---- + @GetMapping("/endpoint") +@@ -253,11 +288,13 @@ public String foo(Principal user) { + return user.getName(); + } + ---- ++==== + +-There's nothing OAuth2-specific about it, so you will likely be able to simply <> and be fine. ++There is nothing OAuth2-specific about it, so you can probably <> and be fine. + +-But, in cases where your controllers are bound to some aspect of Spring Security's OAuth 2.0 support, like the following: ++However, in cases where your controllers are bound to some aspect of Spring Security's OAuth 2.0 support, Spring Security's test support can come in handy: + ++==== + [source,java] + ---- + @GetMapping("/endpoint") +@@ -265,50 +302,57 @@ public String foo(@AuthenticationPrincipal OidcUser user) { + return user.getIdToken().getSubject(); + } + ---- +- +-then Spring Security's test support can come in handy. ++==== + + [[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. ++Testing the method above with Spring MVC Test requires simulating some kind of grant flow with an authorization server. ++This can be a daunting task, which is why Spring Security ships with support for removing this boilerplate. + +-For example, we can tell Spring Security to include a default `OidcUser` using the `SecurityMockMvcRequestPostProcessors#oidcLogin` method, like so: ++For example, we can tell Spring Security to include a default `OidcUser` by using the `SecurityMockMvcRequestPostProcessors#oidcLogin` method: + ++==== + [source,java] + ---- + mvc + .perform(get("/endpoint").with(oidcLogin())); + ---- ++==== + +-What this will do is configure the associated `MockHttpServletRequest` with an `OidcUser` that includes a simple `OidcIdToken`, `OidcUserInfo`, and `Collection` of granted authorities. ++The preceding line configures the associated `MockHttpServletRequest` with an `OidcUser` that includes a `OidcIdToken`, an `OidcUserInfo`, and a `Collection` of granted authorities. + +-Specifically, it will include an `OidcIdToken` with a `sub` claim set to `user`: ++Specifically, it includes an `OidcIdToken` with a `sub` claim set to `user`: + +-[source,json] ++==== ++[source,java] + ---- + assertThat(user.getIdToken().getClaim("sub")).isEqualTo("user"); + ---- ++==== + +-an `OidcUserInfo` with no claims set: ++It also includes an `OidcUserInfo` with no claims set: + +-[source,json] ++==== ++[source,java] + ---- + assertThat(user.getUserInfo().getClaims()).isEmpty(); + ---- ++==== + +-and a `Collection` of authorities with just one authority, `SCOPE_read`: ++Finally, it includes a `Collection` of authorities with only one authority, `SCOPE_read`: + +-[source,json] ++==== ++[source,java] + ---- + assertThat(user.getAuthorities()).hasSize(1); + assertThat(user.getAuthorities()).containsExactly(new SimpleGrantedAuthority("SCOPE_read")); + ---- ++==== + + Spring Security does the necessary work to make sure that the `OidcUser` instance is available for <>. + +-Further, it also links that `OidcUser` to a simple instance of `OAuth2AuthorizedClient` that it deposits into an mock `OAuth2AuthorizedClientRepository`. ++Further, it also links the `OidcUser` to an instance of `OAuth2AuthorizedClient` that it deposits into an mock `OAuth2AuthorizedClientRepository`. + This can be handy if your tests <>.. + + [[testing-oidc-login-authorities]] +@@ -316,8 +360,9 @@ This can be handy if your tests <>, 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. + +-Let's say that we've got a controller that gets the logged-in user as an `OAuth2User`: ++Suppose that you have a controller that gets the logged-in user as an `OAuth2User`: + ++==== + [source,java] + ---- + @GetMapping("/endpoint") +@@ -403,35 +456,42 @@ public String foo(@AuthenticationPrincipal OAuth2User oauth2User) { + return oauth2User.getAttribute("sub"); + } + ---- ++==== + +-In that case, we can tell Spring Security to include a default `OAuth2User` using the `SecurityMockMvcRequestPostProcessors#oauth2User` method, like so: ++In that case, you can tell Spring Security to include a default `OAuth2User` by using the `SecurityMockMvcRequestPostProcessors#oauth2User` method: + ++==== + [source,java] + ---- + mvc + .perform(get("/endpoint").with(oauth2Login())); + ---- ++==== + +-What this will do is configure the associated `MockHttpServletRequest` with an `OAuth2User` that includes a simple `Map` of attributes and `Collection` of granted authorities. ++This line configures the associated `MockHttpServletRequest` with an `OAuth2User` that includes a simple `Map` of attributes and a `Collection` of granted authorities. + +-Specifically, it will include a `Map` with a key/value pair of `sub`/`user`: ++Specifically, it includes a `Map` with a key/value pair of `sub`/`user`: + +-[source,json] ++==== ++[source,java] + ---- + assertThat((String) user.getAttribute("sub")).isEqualTo("user"); + ---- ++==== + +-and a `Collection` of authorities with just one authority, `SCOPE_read`: ++It also includes a `Collection` of authorities with only one authority, `SCOPE_read`: + +-[source,json] ++==== ++[source,java] + ---- + assertThat(user.getAuthorities()).hasSize(1); + assertThat(user.getAuthorities()).containsExactly(new SimpleGrantedAuthority("SCOPE_read")); + ---- ++==== + + Spring Security does the necessary work to make sure that the `OAuth2User` instance is available for <>. + +-Further, it also links that `OAuth2User` to a simple instance of `OAuth2AuthorizedClient` that it deposits in a mock `OAuth2AuthorizedClientRepository`. ++Further, it also links that `OAuth2User` to an instance of `OAuth2AuthorizedClient` that it deposits in a mock `OAuth2AuthorizedClientRepository`. + This can be handy if your tests <>. + + [[testing-oauth2-login-authorities]] +@@ -439,8 +499,9 @@ This can be handy if your tests <)` - For configuring the associated `ClientRegistration` +-* `clientRegistration(ClientRegistration)` - For configuring the complete `ClientRegistration` ++* `principalName(String)`: For configuring the resource owner name ++* `clientRegistration(Consumer)`: For configuring the associated `ClientRegistration` ++* `clientRegistration(ClientRegistration)`: For configuring the complete `ClientRegistration` + +-That last one is handy if you want to use a real `ClientRegistration` ++That last one is handy if you want to use a real `ClientRegistration` object. + +-For example, let's say that you are wanting to use one of your app's `ClientRegistration` definitions, as specified in your `application.yml`. ++For example, suppose that you want to use one of your application's `ClientRegistration` definitions, as specified in your `application.yml`. + + In that case, your test can autowire the `ClientRegistrationRepository` and look up the one your test needs: + ++==== + [source,java] + ---- + @Autowired +@@ -623,33 +706,37 @@ mvc + .with(oauth2Client() + .clientRegistration(this.clientRegistrationRepository.findByRegistrationId("facebook")))); + ---- ++==== + + [[testing-jwt]] + ==== Testing JWT Authentication + +-In order to make an authorized request on a resource server, you need a bearer token. ++To make an authorized request on a resource server, you need a bearer token. + +-If your resource server is configured for JWTs, then this would mean that the bearer token needs to be signed and then encoded according to the JWT specification. +-All of this can be quite daunting, especially when this isn't the focus of your test. ++If your resource server is configured for JWTs, the bearer token needs to be signed and then encoded according to the JWT specification. ++All of this can be quite daunting, especially when this is not the focus of your test. + +-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: ++Fortunately, there are a number of ways that you can overcome this difficulty and let your tests focus on authorization and not on representing bearer tokens. ++We look at two of them in the next two subsections. + + ===== `jwt() RequestPostProcessor` + +-The first way is via a `RequestPostProcessor`. +-The simplest of these would look something like this: ++The first way is with a `RequestPostProcessor`. ++The simplest of these looks something like this: + ++==== + [source,java] + ---- + mvc + .perform(get("/endpoint").with(jwt())); + ---- ++==== + +-What this will do is create a mock `Jwt`, passing it correctly through any authentication APIs so that it's available for your authorization mechanisms to verify. ++This line creates a mock `Jwt` and passes it correctly through any authentication APIs so that itis available for your authorization mechanisms to verify. + + By default, the `JWT` that it creates has the following characteristics: + ++==== + [source,json] + ---- + { +@@ -660,9 +747,11 @@ By default, the `JWT` that it creates has the following characteristics: + } + } + ---- ++==== + +-And the resulting `Jwt`, were it tested, would pass in the following way: ++The resulting `Jwt`, were it tested, would pass in the following way: + ++==== + [source,java] + ---- + assertThat(jwt.getTokenValue()).isEqualTo("token"); +@@ -671,11 +760,13 @@ assertThat(jwt.getSubject()).isEqualTo("sub"); + GrantedAuthority authority = jwt.getAuthorities().iterator().next(); + assertThat(authority.getAuthority()).isEqualTo("read"); + ---- ++==== + +-These values can, of course be configured. ++You can configure these values. + +-Any headers or claims can be configured with their corresponding methods: ++You can configure any headers or claims with their corresponding methods: + ++==== + [source,java] + ---- + mvc +@@ -689,28 +780,34 @@ mvc + .perform(get("/endpoint") + .with(jwt().jwt(jwt -> jwt.claims(claims -> claims.remove("scope"))))); + ---- ++==== + + The `scope` and `scp` claims are processed the same way here as they are in a normal bearer token request. +-However, this can be overridden simply by providing the list of `GrantedAuthority` instances that you need for your test: ++However, you can override this by providing the list of `GrantedAuthority` instances that you need for your test: + ++==== + [source,java] + ---- + mvc + .perform(get("/endpoint") + .with(jwt().authorities(new SimpleGrantedAuthority("SCOPE_messages")))); + ---- ++==== + +-Or, if you have a custom `Jwt` to `Collection` converter, you can also use that to derive the authorities: ++Alternatively, if you have a custom `Jwt` to `Collection` converter, you can also use that to derive the authorities: + ++==== + [source,java] + ---- + mvc + .perform(get("/endpoint") + .with(jwt().authorities(new MyConverter()))); + ---- ++==== + +-You can also specify a complete `Jwt`, for which `{security-api-url}org/springframework/security/oauth2/jwt/Jwt.Builder.html[Jwt.Builder]` comes quite handy: ++You can also specify a complete `Jwt`, which you can do with `{security-api-url}org/springframework/security/oauth2/jwt/Jwt.Builder.html[`Jwt.Builder`]`: + ++==== + [source,java] + ---- + Jwt jwt = Jwt.withTokenValue("token") +@@ -722,12 +819,14 @@ mvc + .perform(get("/endpoint") + .with(jwt().jwt(jwt))); + ---- ++==== + + ===== `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: ++Essentially, you can instantiate your own `JwtAuthenticationToken` and provide it in your test: + ++==== + [source,java] + ---- + Jwt jwt = Jwt.withTokenValue("token") +@@ -741,17 +840,19 @@ mvc + .perform(get("/endpoint") + .with(authentication(token))); + ---- ++==== + +-Note that as an alternative to these, you can also mock the `JwtDecoder` bean itself with a `@MockBean` annotation. ++Note that, as an alternative to these approaches, you can also mock the `JwtDecoder` bean itself with a `@MockBean` annotation. + + [[testing-opaque-token]] + ==== Testing Opaque Token Authentication + +-Similar to <>, opaque tokens require an authorization server in order to verify their validity, which can make testing more difficult. ++Similar to <>, opaque tokens require an authorization server to verify their validity, which can make testing more difficult. + To help with that, Spring Security has test support for opaque tokens. + +-Let's say that we've got a controller that retrieves the authentication as a `BearerTokenAuthentication`: ++Suppose that you have a controller that retrieves the authentication as a `BearerTokenAuthentication`: + ++==== + [source,java] + ---- + @GetMapping("/endpoint") +@@ -759,27 +860,32 @@ public String foo(BearerTokenAuthentication authentication) { + return (String) authentication.getTokenAttributes("sub"); + } + ---- ++==== + +-In that case, we can tell Spring Security to include a default `BearerTokenAuthentication` using the `SecurityMockMvcRequestPostProcessors#opaqueToken` method, like so: ++In that case, we can tell Spring Security to include a default `BearerTokenAuthentication` by using the `SecurityMockMvcRequestPostProcessors#opaqueToken` method: + ++==== + [source,java] + ---- + mvc + .perform(get("/endpoint").with(opaqueToken())); + ---- ++==== + +-What this will do is configure the associated `MockHttpServletRequest` with a `BearerTokenAuthentication` that includes a simple `OAuth2AuthenticatedPrincipal`, `Map` of attributes, and `Collection` of granted authorities. ++This line configures the associated `MockHttpServletRequest` with a `BearerTokenAuthentication` that includes a simple `OAuth2AuthenticatedPrincipal`, a `Map` of attributes, and a `Collection` of granted authorities. + +-Specifically, it will include a `Map` with a key/value pair of `sub`/`user`: ++Specifically, it includes a `Map` with a key/value pair of `sub`/`user`: + +-[source,json] ++==== ++[source,java] + ---- + assertThat((String) token.getTokenAttributes().get("sub")).isEqualTo("user"); + ---- ++==== + +-and a `Collection` of authorities with just one authority, `SCOPE_read`: ++It also includes a `Collection` of authorities with only one authority, `SCOPE_read`: + +-[source,json] ++[source,java] + ---- + assertThat(token.getAuthorities()).hasSize(1); + assertThat(token.getAuthorities()).containsExactly(new SimpleGrantedAuthority("SCOPE_read")); +@@ -792,8 +898,9 @@ Spring Security does the necessary work to make sure that the `BearerTokenAuthen + + 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. + +-In this case, you can supply what granted authorities you need using the `authorities()` method: ++In this case, you can supply the granted authorities you need by using the `authorities()` method: + ++==== + [source,java] + ---- + mvc +@@ -803,15 +910,17 @@ mvc + ) + ); + ---- ++==== + + [[testing-opaque-token-attributes]] + ===== 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. ++While granted authorities are quite common across all of Spring Security, we also have attributes, in the case of OAuth 2.0. + +-Let's say, for example, that you've got a `user_id` attribute that indicates the user's id in your system. +-You might access it like so in a controller: ++Suppose, for example, that you have a `user_id` attribute that indicates the user's ID in your system. ++You can access it in a controller: + ++==== + [source,java] + ---- + @GetMapping("/endpoint") +@@ -820,9 +929,11 @@ public String foo(BearerTokenAuthentication authentication) { + // ... + } + ---- ++==== + +-In that case, you'd want to specify that attribute with the `attributes()` method: ++In that case, you want to specify that attribute with the `attributes()` method: + ++==== + [source,java] + ---- + mvc +@@ -832,21 +943,23 @@ mvc + ) + ); + ---- ++==== + + [[testing-opaque-token-principal]] + ===== Additional Configurations + +-There are additional methods, too, for further configuring the authentication; it simply depends on what data your controller expects. ++There are additional methods, too, for further configuring the authentication. It simply depends on what data your controller expects. + +-One such is `principal(OAuth2AuthenticatedPrincipal)`, which you can use to configure the complete `OAuth2AuthenticatedPrincipal` instance that underlies the `BearerTokenAuthentication` ++One such method is `principal(OAuth2AuthenticatedPrincipal)`, which you can use to configure the complete `OAuth2AuthenticatedPrincipal` instance that underlies the `BearerTokenAuthentication` + +-It's handy if you: +-1. Have your own implementation of `OAuth2AuthenticatedPrincipal`, or +-2. Want to specify a different principal name ++It is useful if you: ++* Have your own implementation of `OAuth2AuthenticatedPrincipal` ++* Want to specify a different principal name + +-For example, let's say that your authorization server sends the principal name in the `user_name` attribute instead of the `sub` attribute. ++For example, suppose that your authorization server sends the principal name in the `user_name` attribute instead of the `sub` attribute. + In that case, you can configure an `OAuth2AuthenticatedPrincipal` by hand: + ++==== + [source,java] + ---- + Map attributes = Collections.singletonMap("user_name", "foo_user"); +@@ -860,136 +973,162 @@ mvc + .with(opaqueToken().principal(principal)) + ); + ---- ++==== + +-Note that as an alternative to using `opaqueToken()` test support, you can also mock the `OpaqueTokenIntrospector` bean itself with a `@MockBean` annotation. ++Note that, as an alternative to using `opaqueToken()` test support, you can also mock the `OpaqueTokenIntrospector` bean itself with a `@MockBean` annotation. + + === 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. +-In order to use Spring Security's `RequestBuilder` implementations ensure the following static import is used: ++Spring MVC Test also provides a `RequestBuilder` interface that you can use to create the `MockHttpServletRequest` for your test. ++Spring Security provides a few `RequestBuilder` implementations that you can use to make testing easier. ++To use Spring Security's `RequestBuilder` implementations, use the following static import: + ++==== + [source,java] + ---- + import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestBuilders.*; + ---- ++==== + +-==== 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: ++You can create a request to test a form-based authentication using Spring Security's testing support. ++For example, the following line submits a POST to `/login` with a username of `user`, a password of `password`, and a valid CSRF token: + ++==== + [source,java] + ---- + mvc + .perform(formLogin()) + ---- ++==== + + It is easy to customize the request. +-For example, the following will submit a POST to "/auth" with the username "admin", the password "pass", and a valid CSRF token: ++For example, the following line submits a POST to `/auth` with a username of `admin`, a password of `pass`, and a valid CSRF token: + ++==== + [source,java] + ---- + mvc + .perform(formLogin("/auth").user("admin").password("pass")) + ---- ++==== + +-We can also customize the parameters names that the username and password are included on. +-For example, this is the above request modified to include the username on the HTTP parameter "u" and the password on the HTTP parameter "p". ++You can also customize the parameters names on which the username and password are included. ++For example, the following line modifies the preceding request to include the username on the HTTP parameter named `u` and the password on the HTTP parameter named `p`: + ++==== + [source,java] + ---- + mvc + .perform(formLogin("/auth").user("u","admin").password("p","pass")) + ---- ++==== + + [[test-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: ++A minor but still useful use case for Spring Security's testing support is to test logging out. ++The following example submits a POST to `/logout` with a valid CSRF token: + ++==== + [source,java] + ---- + mvc + .perform(logout()) + ---- ++==== + +-You can also customize the URL to post to. +-For example, the snippet below will submit a POST to "/signout" with a valid CSRF token: ++You can also customize the URL to which to post. ++The following example submits a POST to `/signout` with a valid CSRF token: + ++==== + [source,java] + ---- + mvc + .perform(logout("/signout")) + ---- ++==== + + === 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. +-In order to use Spring Security's `ResultMatcher` implementations ensure the following static import is used: ++At times, you may want to make various security-related assertions about a request. ++To accommodate this need, Spring Security's testing support implements Spring MVC Test's `ResultMatcher` interface. ++To use Spring Security's `ResultMatcher` implementations, use the following static import: + ++==== + [source,java] + ---- + import static org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.*; + ---- ++==== + + ==== Unauthenticated Assertion + +-At times it may be valuable to assert that there is no authenticated user associated with the result of a `MockMvc` invocation. ++At times, you may want 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. +-You can easily do this with Spring Security's testing support using something like the following: ++You can do so with Spring Security's testing support by using something like the following: + ++==== + [source,java] + ---- + mvc + .perform(formLogin().password("invalid")) + .andExpect(unauthenticated()); + ---- ++==== + + ==== 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. +-We could verify that a form based login was successful with the following snippet of code: ++Often, you must assert that an authenticated user exists. ++For example, you may want to verify that we authenticated successfully. ++You could verify that a form-based login was successful: + ++==== + [source,java] + ---- + mvc + .perform(formLogin()) + .andExpect(authenticated()); + ---- ++==== + +-If we wanted to assert the roles of the user, we could refine our previous code as shown below: ++To assert the roles of the user, you can refine our previous code as follows: + ++==== + [source,java] + ---- + mvc + .perform(formLogin().user("admin")) + .andExpect(authenticated().withRoles("USER","ADMIN")); + ---- ++==== + +-Alternatively, we could verify the username: ++Similarly, you can verify the username: + ++==== + [source,java] + ---- + mvc + .perform(formLogin().user("admin")) + .andExpect(authenticated().withUsername("admin")); + ---- ++==== + +-We can also combine the assertions: ++You can also combine the assertions: + ++==== + [source,java] + ---- + mvc + .perform(formLogin().user("admin").roles("USER","ADMIN")) + .andExpect(authenticated().withUsername("admin")); + ---- ++==== + +-We can also make arbitrary assertions on the authentication ++We can also make arbitrary assertions on the authentication: + ++==== + [source,java] + ---- + mvc +@@ -997,3 +1136,4 @@ mvc + .andExpect(authenticated().withAuthentication(auth -> + assertThat(auth).isInstanceOf(UsernamePasswordAuthenticationToken.class))); + ---- ++==== +diff --git a/docs/manual/src/docs/asciidoc/index.adoc b/docs/manual/src/docs/asciidoc/index.adoc +index 3be0158b67..c248a98304 100644 +--- a/docs/manual/src/docs/asciidoc/index.adoc ++++ b/docs/manual/src/docs/asciidoc/index.adoc +@@ -6,8 +6,9 @@ Ben Alex; Luke Taylor; Rob Winch; Gunnar Hillert; Joe Grandja; Jay Bryant; Eddú + :tabsize: 4 + :toc: left + +-// FIXME: Add links for authentication, authorization, common attacks +-Spring Security is a framework that provides authentication, authorization, and protection against common attacks. ++ ++// FIXME: The current authorization link is for the servlet architecture. We need a reactive link, too. (On a deeper level, we need an authorization topic that accounts for both paths.) ++Spring Security is a framework that provides <>, <>, and protection against <>. + // FIXME: Add links for imperative and reactive applications + With first class support for both imperative and reactive applications, it is the de-facto standard for securing Spring-based applications. + +@@ -16,5 +17,3 @@ include::{include-dir}/about/index.adoc[] + include::{include-dir}/servlet/index.adoc[] + + include::{include-dir}/reactive/index.adoc[] +- +- +-- +2.24.1 + diff --git a/docs/manual/src/docs/asciidoc/_includes/about/authentication/password-storage.adoc b/docs/manual/src/docs/asciidoc/_includes/about/authentication/password-storage.adoc index 7770eb6b5a1..a0cec811eda 100644 --- a/docs/manual/src/docs/asciidoc/_includes/about/authentication/password-storage.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/about/authentication/password-storage.adoc @@ -1,70 +1,69 @@ [[authentication-password-storage]] = Password Storage -Spring Security's `PasswordEncoder` interface is used to perform a one way transformation of a password to allow the password to be stored securely. -Given `PasswordEncoder` is a one way transformation, it is not intended when the password transformation needs to be two way (i.e. storing credentials used to authenticate to a database). -Typically `PasswordEncoder` is used for storing a password that needs to be compared to a user provided password at the time of authentication. +Spring Security's `PasswordEncoder` interface is used to perform a one-way transformation of a password to let the password be stored securely. +Given `PasswordEncoder` is a one-way transformation, it is not useful when the password transformation needs to be two-way (such as storing credentials used to authenticate to a database). +Typically, `PasswordEncoder` is used for storing a password that needs to be compared to a user-provided password at the time of authentication. [[authentication-password-storage-history]] == Password Storage History -Throughout the years the standard mechanism for storing passwords has evolved. -In the beginning passwords were stored in plain text. +Throughout the years, the standard mechanism for storing passwords has evolved. +In the beginning, passwords were stored in plain text. The passwords were assumed to be safe because the data store the passwords were saved in required credentials to access it. -However, malicious users were able to find ways to get large "data dumps" of usernames and passwords using attacks like SQL Injection. -As more and more user credentials became public security experts realized we needed to do more to protect users' passwords. +However, malicious users were able to find ways to get large "`data dumps`" of usernames and passwords by using attacks such as SQL Injection. +As more and more user credentials became public, security experts realized that we needed to do more to protect users' passwords. -Developers were then encouraged to store passwords after running them through a one way hash such as SHA-256. +Developers were then encouraged to store passwords after running them through a one way hash, such as SHA-256. When a user tried to authenticate, the hashed password would be compared to the hash of the password that they typed. -This meant that the system only needed to store the one way hash of the password. -If a breach occurred, then only the one way hashes of the passwords were exposed. -Since the hashes were one way and it was computationally difficult to guess the passwords given the hash, it would not be worth the effort to figure out each password in the system. -To defeat this new system malicious users decided to create lookup tables known as https://en.wikipedia.org/wiki/Rainbow_table[Rainbow Tables]. +This meant that the system only needed to store the one-way hash of the password. +If a breach occurred, only the one-way hashes of the passwords were exposed. +Since the hashes were one-way and it was computationally difficult to guess the passwords given the hash, it would not be worth the effort to figure out each password in the system. +To defeat this new system, malicious users decided to create lookup tables known as https://en.wikipedia.org/wiki/Rainbow_table[Rainbow Tables]. Rather than doing the work of guessing each password every time, they computed the password once and stored it in a lookup table. To mitigate the effectiveness of Rainbow Tables, developers were encouraged to use salted passwords. -Instead of using just the password as input to the hash function, random bytes (known as salt) would be generated for every users' password. -The salt and the user's password would be ran through the hash function which produced a unique hash. +Instead of using just the password as input to the hash function, random bytes (known as salt) would be generated for every user's password. +The salt and the user's password would be run through the hash function to produce a unique hash. The salt would be stored alongside the user's password in clear text. -Then when a user tried to authenticate, the hashed password would be compared to the hash of the stored salt and the password that they typed. -The unique salt meant that Rainbow Tables were no longer effective because the hash was different for every salt and password combination. +Then, when a user tried to authenticate, the hashed password would be compared to the hash of the stored salt and the password that they typed. +The unique salt meant that Rainbow Tables were no longer effective, because the hash was different for every salt and password combination. -In modern times we realize that cryptographic hashes (like SHA-256) are no longer secure. +In modern times, we realize that cryptographic hashes (like SHA-256) are no longer secure. The reason is that with modern hardware we can perform billions of hash calculations a second. This means that we can crack each password individually with ease. Developers are now encouraged to leverage adaptive one-way functions to store a password. -Validation of passwords with adaptive one-way functions are intentionally resource (i.e. CPU, memory, etc) intensive. -An adaptive one-way function allows configuring a "work factor" which can grow as hardware gets better. -It is recommended that the "work factor" be tuned to take about 1 second to verify a password on your system. -This trade off is to make it difficult for attackers to crack the password, but not so costly it puts excessive burden on your own system. -Spring Security has attempted to provide a good starting point for the "work factor", but users are encouraged to customize the "work factor" for their own system since the performance will vary drastically from system to system. +Validation of passwords with adaptive one-way functions are intentionally resource-intensive (they intentionally use a lot of CPU, memory, or other resources). +An adaptive one-way function allows configuring a "`work factor`" that can grow as hardware gets better. +We recommend that the "`work factor`" be tuned to take about one second to verify a password on your system. +This trade off is to make it difficult for attackers to crack the password, but not so costly that it puts excessive burden on your own system or irritates users. +Spring Security has attempted to provide a good starting point for the "`work factor`", but we encourage users to customize the "`work factor`" for their own system, since the performance varies drastically from system to system. Examples of adaptive one-way functions that should be used include <>, <>, <>, and <>. -Because adaptive one-way functions are intentionally resource intensive, validating a username and password for every request will degrade performance of an application significantly. -There is nothing Spring Security (or any other library) can do to speed up the validation of the password since security is gained by making the validation resource intensive. -Users are encouraged to exchange the long term credentials (i.e. username and password) for a short term credential (i.e. session, OAuth Token, etc). +Because adaptive one-way functions are intentionally resource intensive, validating a username and password for every request can significantly degrade the performance of an application. +There is nothing Spring Security (or any other library) can do to speed up the validation of the password, since security is gained by making the validation resource intensive. +Users are encouraged to exchange the long term credentials (that is, username and password) for a short term credential (such as a session, and OAuth Token, and so on). The short term credential can be validated quickly without any loss in security. - [[authentication-password-storage-dpe]] == DelegatingPasswordEncoder -Prior to Spring Security 5.0 the default `PasswordEncoder` was `NoOpPasswordEncoder` which required plain text passwords. -Based upon the <> section you might expect that the default `PasswordEncoder` is now something like `BCryptPasswordEncoder`. +Prior to Spring Security 5.0, the default `PasswordEncoder` was `NoOpPasswordEncoder`, which required plain-text passwords. +Based on the <> section, you might expect that the default `PasswordEncoder` would now be something like `BCryptPasswordEncoder`. However, this ignores three real world problems: -- There are many applications using old password encodings that cannot easily migrate +- Many applications use old password encodings that cannot easily migrate. - The best practice for password storage will change again. -- As a framework Spring Security cannot make breaking changes frequently +- As a framework, Spring Security cannot make breaking changes frequently. -Instead Spring Security introduces `DelegatingPasswordEncoder` which solves all of the problems by: +Instead Spring Security introduces `DelegatingPasswordEncoder`, which solves all of the problems by: -- Ensuring that passwords are encoded using the current password storage recommendations +- Ensuring that passwords are encoded by using the current password storage recommendations - Allowing for validating passwords in modern and legacy formats - Allowing for upgrading the encoding in the future -You can easily construct an instance of `DelegatingPasswordEncoder` using `PasswordEncoderFactories`. +You can easily construct an instance of `DelegatingPasswordEncoder` by using `PasswordEncoderFactories`: .Create Default DelegatingPasswordEncoder ==== @@ -82,7 +81,7 @@ val passwordEncoder: PasswordEncoder = PasswordEncoderFactories.createDelegating ---- ==== -Alternatively, you may create your own custom instance. For example: +Alternatively, you can create your own custom instance: .Create Custom DelegatingPasswordEncoder ==== @@ -129,11 +128,11 @@ The general format for a password is: ---- ==== -Such that `id` is an identifier used to look up which `PasswordEncoder` should be used and `encodedPassword` is the original encoded password for the selected `PasswordEncoder`. -The `id` must be at the beginning of the password, start with `{` and end with `}`. -If the `id` cannot be found, the `id` will be null. -For example, the following might be a list of passwords encoded using different `id`. -All of the original passwords are "password". +`id` is an identifier that is used to look up which `PasswordEncoder` should be used and `encodedPassword` is the original encoded password for the selected `PasswordEncoder`. +The `id` must be at the beginning of the password, start with `{`, and end with `}`. +If the `id` cannot be found, the `id` is set to null. +For example, the following might be a list of passwords encoded using different `id` values. +All of the original passwords are `password`. .DelegatingPasswordEncoder Encoded Passwords Example ==== @@ -147,16 +146,16 @@ All of the original passwords are "password". ---- ==== -<1> The first password would have a `PasswordEncoder` id of `bcrypt` and encodedPassword of `$2a$10$dXJ3SW6G7P50lGmMkkmwe.20cQQubK3.HZWzG3YB1tlRy.fqvM/BG`. -When matching it would delegate to `BCryptPasswordEncoder` -<2> The second password would have a `PasswordEncoder` id of `noop` and encodedPassword of `password`. -When matching it would delegate to `NoOpPasswordEncoder` -<3> The third password would have a `PasswordEncoder` id of `pbkdf2` and encodedPassword of `5d923b44a6d129f3ddf3e3c8d29412723dcbde72445e8ef6bf3b508fbf17fa4ed4d6b99ca763d8dc`. -When matching it would delegate to `Pbkdf2PasswordEncoder` -<4> The fourth password would have a `PasswordEncoder` id of `scrypt` and encodedPassword of `$e0801$8bWJaSu2IKSn9Z9kM+TPXfOc/9bdYSrN1oD9qfVThWEwdRTnO7re7Ei+fUZRJ68k9lTyuTeUp4of4g24hHnazw==$OAOec05+bXxvuu/1qZ6NUR+xQYvYv7BeL1QxwRpY5Pc=` -When matching it would delegate to `SCryptPasswordEncoder` -<5> The final password would have a `PasswordEncoder` id of `sha256` and encodedPassword of `97cde38028ad898ebc02e690819fa220e88c62e0699403e94fff291cfffaf8410849f27605abcbc0`. -When matching it would delegate to `StandardPasswordEncoder` +<1> The first password has a `PasswordEncoder` id of `bcrypt` and an encoded password value of `$2a$10$dXJ3SW6G7P50lGmMkkmwe.20cQQubK3.HZWzG3YB1tlRy.fqvM/BG`. +When matching, it would delegate to `BCryptPasswordEncoder` +<2> The second password has a `PasswordEncoder` id of `noop` and encoded password value of `password`. +When matching, it would delegate to `NoOpPasswordEncoder` +<3> The third password has a `PasswordEncoder` id of `pbkdf2` and encoded password value of `5d923b44a6d129f3ddf3e3c8d29412723dcbde72445e8ef6bf3b508fbf17fa4ed4d6b99ca763d8dc`. +When matching, it would delegate to `Pbkdf2PasswordEncoder` +<4> The fourth password has a `PasswordEncoder` id of `scrypt` and encoded password value of `$e0801$8bWJaSu2IKSn9Z9kM+TPXfOc/9bdYSrN1oD9qfVThWEwdRTnO7re7Ei+fUZRJ68k9lTyuTeUp4of4g24hHnazw==$OAOec05+bXxvuu/1qZ6NUR+xQYvYv7BeL1QxwRpY5Pc=` +When matching, it would delegate to `SCryptPasswordEncoder` +<5> The final password has a `PasswordEncoder` id of `sha256` and encoded password value of `97cde38028ad898ebc02e690819fa220e88c62e0699403e94fff291cfffaf8410849f27605abcbc0`. +When matching, it would delegate to `StandardPasswordEncoder` [NOTE] ==== @@ -169,9 +168,9 @@ For example, BCrypt passwords often start with `$2a$`. [[authentication-password-storage-dpe-encoding]] === Password Encoding -The `idForEncode` passed into the constructor determines which `PasswordEncoder` will be used for encoding passwords. -In the `DelegatingPasswordEncoder` we constructed above, that means that the result of encoding `password` would be delegated to `BCryptPasswordEncoder` and be prefixed with `+{bcrypt}+`. -The end result would look like: +The `idForEncode` passed into the constructor determines which `PasswordEncoder` is used for encoding passwords. +In the `DelegatingPasswordEncoder` we constructed earlier, that means that the result of encoding `password` is delegated to `BCryptPasswordEncoder` and be prefixed with `+{bcrypt}+`. +The end result looks like the following example: .DelegatingPasswordEncoder Encode Example ==== @@ -184,15 +183,15 @@ The end result would look like: [[authentication-password-storage-dpe-matching]] === Password Matching -Matching is done based upon the `+{id}+` and the mapping of the `id` to the `PasswordEncoder` provided in the constructor. +Matching is based upon the `+{id}+` and the mapping of the `id` to the `PasswordEncoder` provided in the constructor. Our example in <> provides a working example of how this is done. -By default, the result of invoking `matches(CharSequence, String)` with a password and an `id` that is not mapped (including a null id) will result in an `IllegalArgumentException`. -This behavior can be customized using `DelegatingPasswordEncoder.setDefaultPasswordEncoderForMatches(PasswordEncoder)`. +By default, the result of invoking `matches(CharSequence, String)` with a password and an `id` that is not mapped (including a null id) results in an `IllegalArgumentException`. +This behavior can be customized by using `DelegatingPasswordEncoder.setDefaultPasswordEncoderForMatches(PasswordEncoder)`. -By using the `id` we can match on any password encoding, but encode passwords using the most modern password encoding. -This is important, because unlike encryption, password hashes are designed so that there is no simple way to recover the plaintext. -Since there is no way to recover the plaintext, it makes it difficult to migrate the passwords. -While it is simple for users to migrate `NoOpPasswordEncoder`, we chose to include it by default to make it simple for the getting started experience. +By using the `id`, we can match on any password encoding but encode passwords by using the most modern password encoding. +This is important, because unlike encryption, password hashes are designed so that there is no simple way to recover the plain text. +Since there is no way to recover the plain text, it is difficult to migrate the passwords. +While it is simple for users to migrate `NoOpPasswordEncoder`, we chose to include it by default to make it simple for the getting-started experience. [[authentication-password-storage-dep-getting-started]] === Getting Started Experience @@ -227,7 +226,7 @@ println(user.password) ---- ==== -If you are creating multiple users, you can also reuse the builder. +If you are creating multiple users, you can also reuse the builder: .withDefaultPasswordEncoder Reusing the Builder ==== @@ -273,7 +272,7 @@ For production, you should <>: +For example, the following example encodes the password of `password` for use with <>: .Spring Boot CLI encodepassword Example ==== @@ -287,44 +286,48 @@ spring encodepassword password [[authentication-password-storage-dpe-troubleshoot]] === Troubleshooting -The following error occurs when one of the passwords that are stored has no id as described in <>. +The following error occurs when one of the passwords that are stored has no `id`, as described in <>. +==== ---- java.lang.IllegalArgumentException: There is no PasswordEncoder mapped for the id "null" at org.springframework.security.crypto.password.DelegatingPasswordEncoder$UnmappedIdPasswordEncoder.matches(DelegatingPasswordEncoder.java:233) at org.springframework.security.crypto.password.DelegatingPasswordEncoder.matches(DelegatingPasswordEncoder.java:196) ---- +==== -The easiest way to resolve the error is to switch to explicitly provide the `PasswordEncoder` that you passwords are encoded with. The easiest way to resolve it is to figure out how your passwords are currently being stored and explicitly provide the correct `PasswordEncoder`. -If you are migrating from Spring Security 4.2.x you can revert to the previous behavior by <>. +If you are migrating from Spring Security 4.2.x, you can revert to the previous behavior by <>. -Alternatively, you can prefix all of your passwords with the correct id and continue to use `DelegatingPasswordEncoder`. +Alternatively, you can prefix all of your passwords with the correct `id` and continue to use `DelegatingPasswordEncoder`. For example, if you are using BCrypt, you would migrate your password from something like: +==== ---- $2a$10$dXJ3SW6G7P50lGmMkkmwe.20cQQubK3.HZWzG3YB1tlRy.fqvM/BG ---- +==== to - +==== [source,attrs="-attributes"] ---- {bcrypt}$2a$10$dXJ3SW6G7P50lGmMkkmwe.20cQQubK3.HZWzG3YB1tlRy.fqvM/BG ---- +==== -For a complete listing of the mappings refer to the Javadoc on -https://docs.spring.io/spring-security/site/docs/5.0.x/api/org/springframework/security/crypto/factory/PasswordEncoderFactories.html[PasswordEncoderFactories]. +For a complete listing of the mappings, see the Javadoc for +https://docs.spring.io/spring-security/site/docs/5.0.x/api/org/springframework/security/crypto/factory/PasswordEncoderFactories.html[`PasswordEncoderFactories`]. [[authentication-password-storage-bcrypt]] == BCryptPasswordEncoder The `BCryptPasswordEncoder` implementation uses the widely supported https://en.wikipedia.org/wiki/Bcrypt[bcrypt] algorithm to hash the passwords. -In order to make it more resistent to password cracking, bcrypt is deliberately slow. +To make it more resistant to password cracking, bcrypt is deliberately slow. Like other adaptive one-way functions, it should be tuned to take about 1 second to verify a password on your system. -The default implementation of `BCryptPasswordEncoder` uses strength 10 as mentioned in the Javadoc of https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/crypto/bcrypt/BCryptPasswordEncoder.html[BCryptPasswordEncoder]. You are encouraged to +The default implementation of `BCryptPasswordEncoder` uses strength 10 as mentioned in the Javadoc of https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/crypto/bcrypt/BCryptPasswordEncoder.html[`BCryptPasswordEncoder`]. You are encouraged to tune and test the strength parameter on your own system so that it takes roughly 1 second to verify a password. .BCryptPasswordEncoder @@ -353,7 +356,7 @@ assertTrue(encoder.matches("myPassword", result)) The `Argon2PasswordEncoder` implementation uses the https://en.wikipedia.org/wiki/Argon2[Argon2] algorithm to hash the passwords. Argon2 is the winner of the https://en.wikipedia.org/wiki/Password_Hashing_Competition[Password Hashing Competition]. -In order to defeat password cracking on custom hardware, Argon2 is a deliberately slow algorithm that requires large amounts of memory. +To defeat password cracking on custom hardware, Argon2 is a deliberately slow algorithm that requires large amounts of memory. Like other adaptive one-way functions, it should be tuned to take about 1 second to verify a password on your system. The current implementation of the `Argon2PasswordEncoder` requires BouncyCastle. @@ -382,7 +385,7 @@ assertTrue(encoder.matches("myPassword", result)) == Pbkdf2PasswordEncoder The `Pbkdf2PasswordEncoder` implementation uses the https://en.wikipedia.org/wiki/PBKDF2[PBKDF2] algorithm to hash the passwords. -In order to defeat password cracking PBKDF2 is a deliberately slow algorithm. +To defeat password cracking, PBKDF2 is a deliberately slow algorithm. Like other adaptive one-way functions, it should be tuned to take about 1 second to verify a password on your system. This algorithm is a good choice when FIPS certification is required. @@ -410,8 +413,8 @@ assertTrue(encoder.matches("myPassword", result)) [[authentication-password-storage-scrypt]] == SCryptPasswordEncoder -The `SCryptPasswordEncoder` implementation uses https://en.wikipedia.org/wiki/Scrypt[scrypt] algorithm to hash the passwords. -In order to defeat password cracking on custom hardware scrypt is a deliberately slow algorithm that requires large amounts of memory. +The `SCryptPasswordEncoder` implementation uses the https://en.wikipedia.org/wiki/Scrypt[scrypt] algorithm to hash the passwords. +To defeat password cracking on custom hardware, scrypt is a deliberately slow algorithm that requires large amounts of memory. Like other adaptive one-way functions, it should be tuned to take about 1 second to verify a password on your system. .SCryptPasswordEncoder @@ -436,20 +439,19 @@ assertTrue(encoder.matches("myPassword", result)) ==== [[authentication-password-storage-other]] -== Other PasswordEncoders +== Other Password Encoders There are a significant number of other `PasswordEncoder` implementations that exist entirely for backward compatibility. They are all deprecated to indicate that they are no longer considered secure. -However, there are no plans to remove them since it is difficult to migrate existing legacy systems. +However, there are no plans to remove them, since it is difficult to migrate existing legacy systems. [[authentication-password-storage-configuration]] == Password Storage Configuration Spring Security uses <> by default. -However, this can be customized by exposing a `PasswordEncoder` as a Spring bean. - +However, you can customize this by exposing a `PasswordEncoder` as a Spring bean. -If you are migrating from Spring Security 4.2.x you can revert to the previous behavior by exposing a `NoOpPasswordEncoder` bean. +If you are migrating from Spring Security 4.2.x, you can revert to the previous behavior by exposing a `NoOpPasswordEncoder` bean. [WARNING] ==== @@ -485,7 +487,4 @@ fun passwordEncoder(): PasswordEncoder { ---- ==== -[NOTE] -==== -XML Configuration requires the `NoOpPasswordEncoder` bean name to be `passwordEncoder`. -==== +NOTE: XML Configuration requires the `NoOpPasswordEncoder` bean name to be `passwordEncoder`. diff --git a/docs/manual/src/docs/asciidoc/_includes/about/authentication/supported.adoc b/docs/manual/src/docs/asciidoc/_includes/about/authentication/supported.adoc index 85bd943456d..67c03c68fe1 100644 --- a/docs/manual/src/docs/asciidoc/_includes/about/authentication/supported.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/about/authentication/supported.adoc @@ -1,5 +1,5 @@ [[authentication-support]] = Authentication Support -Spring Security provides built in support for authenticating users. -Refer to the sections on authentication for <> and WebFlux for details on what is supported for each stack. +Spring Security provides built-in support for authenticating users. +See the sections on authentication for <> and <> for details on what is supported for each stack. diff --git a/docs/manual/src/docs/asciidoc/_includes/about/exploits/csrf.adoc b/docs/manual/src/docs/asciidoc/_includes/about/exploits/csrf.adoc index 0a7a98b5612..67728e135ba 100644 --- a/docs/manual/src/docs/asciidoc/_includes/about/exploits/csrf.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/about/exploits/csrf.adoc @@ -1,21 +1,15 @@ -// FIXME: Add links to Servlet and WebFlux support - [[csrf]] = Cross Site Request Forgery (CSRF) Spring provides comprehensive support for protecting against https://en.wikipedia.org/wiki/Cross-site_request_forgery[Cross Site Request Forgery (CSRF)] attacks. -In the following sections we will explore: +In the following sections, we explore: * <> * <> * <> -// FIXME: Add WebFlux csrf documentation (the link below is broken) -[NOTE] -==== -This portion of the documentation discusses the general topic of CSRF protection. -Refer to the relevant sections for specific information on CSRF protection for <> and <> based applications. -==== +NOTE: This portion of the documentation discusses the general topic of CSRF protection. +See the relevant sections for specific information on CSRF protection for <>- and <>-based applications. [[csrf-explained]] == What is a CSRF Attack? @@ -85,52 +79,49 @@ You like to win money, so you click on the submit button. In the process, you have unintentionally transferred $100 to a malicious user. This happens because, while the evil website cannot see your cookies, the cookies associated with your bank are still sent along with the request. -Worst yet, this whole process could have been automated using JavaScript. -This means you didn't even need to click on the button. +Worse yet, this whole process could have been automated by using JavaScript. +This means you did not even need to click on the button. Furthermore, it could just as easily happen when visiting an honest site that is a victim of a https://www.owasp.org/index.php/Cross-site_Scripting_(XSS)[XSS attack]. So how do we protect our users from such attacks? [[csrf-protection]] == Protecting Against CSRF Attacks The reason that a CSRF attack is possible is that the HTTP request from the victim's website and the request from the attacker's website are exactly the same. -This means there is no way to reject requests coming from the evil website and allow requests coming from the bank's website. -To protect against CSRF attacks we need to ensure there is something in the request that the evil site is unable to provide so we can differentiate the two requests. +This means there is no way to reject requests coming from the evil website and allow only requests coming from the bank's website. +To protect against CSRF attacks, we need to ensure there is something in the request that the evil site is unable to provide so we can differentiate the two requests. Spring provides two mechanisms to protect against CSRF attacks: * The <> * Specifying the <> on your session cookie -[NOTE] -==== -Both protections require that <> -==== +NOTE: Both protections require that <>. [[csrf-protection-idempotent]] === Safe Methods Must be Idempotent -In order for <> against CSRF to work, the application must ensure that https://tools.ietf.org/html/rfc7231#section-4.2.1["safe" HTTP methods are idempotent]. -This means that requests with the HTTP method `GET`, `HEAD`, `OPTIONS`, and `TRACE` should not change the state of the application. +For <> against CSRF to work, the application must ensure that https://tools.ietf.org/html/rfc7231#section-4.2.1["safe" HTTP methods are idempotent]. +This means that requests with the HTTP `GET`, `HEAD`, `OPTIONS`, and `TRACE` methods should not change the state of the application. [[csrf-protection-stp]] === Synchronizer Token Pattern The predominant and most comprehensive way to protect against CSRF attacks is to use the https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)_Prevention_Cheat_Sheet#General_Recommendation:_Synchronizer_Token_Pattern[Synchronizer Token Pattern]. -This solution is to ensure that each HTTP request requires, in addition to our session cookie, a secure random generated value called a CSRF token must be present in the HTTP request. +This solution is to ensure that each HTTP request requires, in addition to our session cookie, a secure random generated value called a CSRF token be present in the HTTP request. When an HTTP request is submitted, the server must look up the expected CSRF token and compare it against the actual CSRF token in the HTTP request. If the values do not match, the HTTP request should be rejected. The key to this working is that the actual CSRF token should be in a part of the HTTP request that is not automatically included by the browser. -For example, requiring the actual CSRF token in an HTTP parameter or an HTTP header will protect against CSRF attacks. +For example, requiring the actual CSRF token in an HTTP parameter or an HTTP header protects against CSRF attacks. Requiring the actual CSRF token in a cookie does not work because cookies are automatically included in the HTTP request by the browser. -We can relax the expectations to only require the actual CSRF token for each HTTP request that updates state of the application. +We can relax the expectations to require only the actual CSRF token for each HTTP request that updates the state of the application. For that to work, our application must ensure that <>. -This improves usability since we want to allow linking to our website using links from external sites. -Additionally, we do not want to include the random token in HTTP GET as this can cause the tokens to be leaked. +This improves usability, since we want to allow linking to our website from external sites. +Additionally, we do not want to include the random token in HTTP GET, as this can cause the tokens to be leaked. -Let's take a look at how <> would change when using the Synchronizer Token Pattern. -Assume the actual CSRF token is required to be in an HTTP parameter named `_csrf`. +Consider how <> would change when we use the Synchronizer Token Pattern. +Assume that the actual CSRF token is required to be in an HTTP parameter named `_csrf`. Our application's transfer form would look like: .Synchronizer Token Form @@ -173,22 +164,19 @@ amount=100.00&routingNumber=1234&account=9876&_csrf=4bfd1575-3ad1-4d21-96c7-4ef2 ==== -You will notice that the HTTP request now contains the `_csrf` parameter with a secure random value. -The evil website will not be able to provide the correct value for the `_csrf` parameter (which must be explicitly provided on the evil website) and the transfer will fail when the server compares the actual CSRF token to the expected CSRF token. +Notice that the HTTP request now contains the `_csrf` parameter with a secure random value. +The evil website cannot provide the correct value for the `_csrf` parameter (which must be explicitly provided on the evil website), and the transfer fails when the server compares the actual CSRF token to the expected CSRF token. [[csrf-protection-ssa]] === SameSite Attribute An emerging way to protect against <> is to specify the https://tools.ietf.org/html/draft-west-first-party-cookies[SameSite Attribute] on cookies. A server can specify the `SameSite` attribute when setting a cookie to indicate that the cookie should not be sent when coming from external sites. -[NOTE] -==== -Spring Security does not directly control the creation of the session cookie, so it does not provide support for the SameSite attribute. -https://spring.io/projects/spring-session[Spring Session] provides support for the `SameSite` attribute in servlet based applications. -Spring Framework's https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/server/session/CookieWebSessionIdResolver.html[CookieWebSessionIdResolver] provides out of the box support for the `SameSite` attribute in WebFlux based applications. -==== +NOTE: Spring Security does not directly control the creation of the session cookie, so it does not provide support for the SameSite attribute. +https://spring.io/projects/spring-session[Spring Session] provides support for the `SameSite` attribute in servlet-based applications. +Spring Framework's https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/server/session/CookieWebSessionIdResolver.html[`CookieWebSessionIdResolver`] provides support for the `SameSite` attribute in WebFlux-based applications. -An example, HTTP response header with the `SameSite` attribute might look like: +An example of an HTTP response header with the `SameSite` attribute might look like: .SameSite HTTP response ==== @@ -200,49 +188,45 @@ Set-Cookie: JSESSIONID=randomid; Domain=bank.example.com; Secure; HttpOnly; Same Valid values for the `SameSite` attribute are: -* `Strict` - when specified any request coming from the https://tools.ietf.org/html/draft-west-first-party-cookies-07#section-2.1[same-site] will include the cookie. -Otherwise, the cookie will not be included in the HTTP request. -* `Lax` - when specified cookies will be sent when coming from the https://tools.ietf.org/html/draft-west-first-party-cookies-07#section-2.1[same-site] or when the request comes from top-level navigations and the <>. -Otherwise, the cookie will not be included in the HTTP request. +* `Strict`: When specified, any request coming from the https://tools.ietf.org/html/draft-west-first-party-cookies-07#section-2.1[same-site] includes the cookie. +Otherwise, the cookie is not included in the HTTP request. +* `Lax`: When specified, cookies are sent when coming from the https://tools.ietf.org/html/draft-west-first-party-cookies-07#section-2.1[same-site] or when the request comes from top-level navigations and the <>. +Otherwise, the cookie is not included in the HTTP request. -Let's take a look at how <> could be protected using the `SameSite` attribute. +Consider how <> could be protected using the `SameSite` attribute. The bank application can protect against CSRF by specifying the `SameSite` attribute on the session cookie. -With the `SameSite` attribute set on our session cookie, the browser will continue to send the `JSESSIONID` cookie with requests coming from the banking website. -However, the browser will no longer send the `JSESSIONID` cookie with a transfer request coming from the evil website. +With the `SameSite` attribute set on our session cookie, the browser continues to send the `JSESSIONID` cookie with requests coming from the banking website. +However, the browser no longer sends the `JSESSIONID` cookie with a transfer request coming from the evil website. Since the session is no longer present in the transfer request coming from the evil website, the application is protected from the CSRF attack. -There are some important https://tools.ietf.org/html/draft-west-first-party-cookies-07#section-5[considerations] that one should be aware about when using `SameSite` attribute to protect against CSRF attacks. - +There are some important https://tools.ietf.org/html/draft-west-first-party-cookies-07#section-5[considerations] to be aware of when using `SameSite` attribute to protect against CSRF attacks. Setting the `SameSite` attribute to `Strict` provides a stronger defense but can confuse users. -Consider a user that stays logged into a social media site hosted at https://social.example.com. +Consider a user who stays logged into a social media site hosted at https://social.example.com. The user receives an email at https://email.example.org that includes a link to the social media site. If the user clicks on the link, they would rightfully expect to be authenticated to the social media site. -However, if the `SameSite` attribute is `Strict` the cookie would not be sent and so the user would not be authenticated. +However, if the `SameSite` attribute is `Strict`, the cookie would not be sent and the user would not be authenticated. -[NOTE] -==== -We could improve the protection and usability of `SameSite` protection against CSRF attacks by implementing https://github.com/spring-projects/spring-security/issues/7537[gh-7537]. -==== +NOTE: We could improve the protection and usability of `SameSite` protection against CSRF attacks by implementing https://github.com/spring-projects/spring-security/issues/7537[gh-7537]. -Another obvious consideration is that in order for the `SameSite` attribute to protect users, the browser must support the `SameSite` attribute. +Another obvious consideration is that, in order for the `SameSite` attribute to protect users, the browser must support the `SameSite` attribute. Most modern browsers do https://developer.mozilla.org/en-US/docs/Web/HTTP/headers/Set-Cookie#Browser_compatibility[support the SameSite attribute]. However, older browsers that are still in use may not. -For this reason, it is generally recommended to use the `SameSite` attribute as a defense in depth rather than the sole protection against CSRF attacks. +For this reason, we generally recommend using the `SameSite` attribute as a defense in depth rather than the sole protection against CSRF attacks. [[csrf-when]] == When to use CSRF protection When should you use CSRF protection? Our recommendation is to use CSRF protection for any request that could be processed by a browser by normal users. -If you are only creating a service that is used by non-browser clients, you will likely want to disable CSRF protection. +If you are creating a service that is used only by non-browser clients, you likely want to disable CSRF protection. [[csrf-when-json]] === CSRF protection and JSON -A common question is "do I need to protect JSON requests made by javascript?" -The short answer is, it depends. -However, you must be very careful as there are CSRF exploits that can impact JSON requests. -For example, a malicious user can create a http://blog.opensecurityresearch.com/2012/02/json-csrf-with-parameter-padding.html[CSRF with JSON using the following form]: +A common question is "`do I need to protect JSON requests made by JavaScript?`" +The short answer is: It depends. +However, you must be very careful, as there are CSRF exploits that can impact JSON requests. +For example, a malicious user can create a http://blog.opensecurityresearch.com/2012/02/json-csrf-with-parameter-padding.html[CSRF with JSON by using the following form]: .CSRF with JSON form ==== @@ -257,7 +241,7 @@ For example, a malicious user can create a http://blog.opensecurityresearch.com/ ==== -This will produce the following JSON structure +This produces the following JSON structure .CSRF with JSON request ==== @@ -271,8 +255,8 @@ This will produce the following JSON structure ---- ==== -If an application were not validating the Content-Type, then it would be exposed to this exploit. -Depending on the setup, a Spring MVC application that validates the Content-Type could still be exploited by updating the URL suffix to end with `.json` as shown below: +If an application were not validating the `Content-Type` header, it would be exposed to this exploit. +Depending on the setup, a Spring MVC application that validates the Content-Type could still be exploited by updating the URL suffix to end with `.json`, as follows: .CSRF with JSON Spring MVC form ==== @@ -289,15 +273,15 @@ Depending on the setup, a Spring MVC application that validates the Content-Type [[csrf-when-stateless]] === CSRF and Stateless Browser Applications What if my application is stateless? -That doesn't necessarily mean you are protected. +That does not necessarily mean you are protected. In fact, if a user does not need to perform any actions in the web browser for a given request, they are likely still vulnerable to CSRF attacks. -For example, consider an application that uses a custom cookie that contains all the state within it for authentication instead of the JSESSIONID. -When the CSRF attack is made the custom cookie will be sent with the request in the same manner that the JSESSIONID cookie was sent in our previous example. -This application will be vulnerable to CSRF attacks. +For example, consider an application that uses a custom cookie that contains all the state within it for authentication (instead of the JSESSIONID). +When the CSRF attack is made, the custom cookie is sent with the request in the same manner that the JSESSIONID cookie was sent in our previous example. +This application is vulnerable to CSRF attacks. Applications that use basic authentication are also vulnerable to CSRF attacks. -The application is vulnerable since the browser will automatically include the username and password in any requests in the same manner that the JSESSIONID cookie was sent in our previous example. +The application is vulnerable since the browser automatically includes the username and password in any requests in the same manner that the JSESSIONID cookie was sent in our previous example. [[csrf-considerations]] == CSRF Considerations @@ -308,89 +292,87 @@ There are a few special considerations to consider when implementing protection [[csrf-considerations-login]] === Logging In -In order to protect against https://en.wikipedia.org/wiki/Cross-site_request_forgery#Forging_login_requests[forging log in requests] the log in HTTP request should be protected against CSRF attacks. -Protecting against forging log in requests is necessary so that a malicious user cannot read a victim's sensitive information. +To protect against https://en.wikipedia.org/wiki/Cross-site_request_forgery#Forging_login_requests[forging login requests], the login HTTP request should be protected against CSRF attacks. +Protecting against forging login requests is necessary so that a malicious user cannot read a victim's sensitive information. The attack is performed as follows: -* A malicious user performs a CSRF log in using the malicious user's credentials. +. A malicious user performs a CSRF login with the malicious user's credentials. The victim is now authenticated as the malicious user. -* The malicious user then tricks the victim to visit the compromised website and enter sensitive information -* The information is associated to the malicious user's account so the malicious user can log in with their own credentials and view the vicitim's sensitive information +. The malicious user then tricks the victim into visiting the compromised website and entering sensitive information. +. The information is associated to the malicious user's account so the malicious user can log in with their own credentials and view the victim's sensitive information. -A possible complication to ensuring log in HTTP requests are protected against CSRF attacks is that the user might experience a session timeout that causes the request to be rejected. -A session timeout is surprising to users who do not expect to need to have a session in order to log in. +A possible complication to ensuring login HTTP requests are protected against CSRF attacks is that the user might experience a session timeout that causes the request to be rejected. +A session timeout is surprising to users who do not expect to need to have a session to log in. For more information refer to <>. [[csrf-considerations-logout]] === Logging Out -In order to protect against forging log out requests, the log out HTTP request should be protected against CSRF attacks. -Protecting against forging log out requests is necessary so a malicious user cannot read a victim's sensitive information. -For details on the attack refer to https://labs.detectify.com/2017/03/15/loginlogout-csrf-time-to-reconsider/[this blog post]. +To protect against forging logout requests, the logout HTTP request should be protected against CSRF attacks. +Protecting against forging logout requests is necessary so that a malicious user cannot read a victim's sensitive information. +For details on the attack, see https://labs.detectify.com/2017/03/15/loginlogout-csrf-time-to-reconsider/[this blog post]. -A possible complication to ensuring log out HTTP requests are protected against CSRF attacks is that the user might experience a session timeout that causes the request to be rejected. -A session timeout is surprising to users who do not expect to need to have a session in order to log out. -For more information refer to <>. +A possible complication to ensuring logout HTTP requests are protected against CSRF attacks is that the user might experience a session timeout that causes the request to be rejected. +A session timeout is surprising to users who do not expect to have a session to log out. +For more information, see <>. [[csrf-considerations-timeouts]] === CSRF and Session Timeouts More often than not, the expected CSRF token is stored in the session. -This means that as soon as the session expires the server will not find an expected CSRF token and reject the HTTP request. -There are a number of options to solve timeouts each of which come with trade offs. +This means that, as soon as the session expires, the server does not find an expected CSRF token and rejects the HTTP request. +There are a number of options (each of which come with trade offs) to solve timeouts: * The best way to mitigate the timeout is by using JavaScript to request a CSRF token on form submission. The form is then updated with the CSRF token and submitted. * Another option is to have some JavaScript that lets the user know their session is about to expire. The user can click a button to continue and refresh the session. * Finally, the expected CSRF token could be stored in a cookie. -This allows the expected CSRF token to outlive the session. +This lets the expected CSRF token outlive the session. + -One might ask why the expected CSRF token isn't stored in a cookie by default. +One might ask why the expected CSRF token is not stored in a cookie by default. This is because there are known exploits in which headers (for example, to specify the cookies) can be set by another domain. -This is the same reason Ruby on Rails https://weblog.rubyonrails.org/2011/2/8/csrf-protection-bypass-in-ruby-on-rails/[no longer skips CSRF checks when the header X-Requested-With is present]. +This is the same reason Ruby on Rails https://weblog.rubyonrails.org/2011/2/8/csrf-protection-bypass-in-ruby-on-rails/[no longer skips a CSRF checks when the header X-Requested-With is present]. See http://lists.webappsec.org/pipermail/websecurity_lists.webappsec.org/2011-February/007533.html[this webappsec.org thread] for details on how to perform the exploit. Another disadvantage is that by removing the state (that is, the timeout), you lose the ability to forcibly invalidate the token if it is compromised. -// FIXME: Document timeout with lengthy form expire. We do not want to automatically replay that request because it can lead to exploit +// FIXME: Document timeout with lengthy form expire. We do not want to automatically replay that request because it can lead to an exploit. [[csrf-considerations-multipart]] === Multipart (file upload) -Protecting multipart requests (file uploads) from CSRF attacks causes a https://en.wikipedia.org/wiki/Chicken_or_the_egg[chicken and the egg] problem. -In order to prevent a CSRF attack from occurring, the body of the HTTP request must be read to obtain actual CSRF token. -However, reading the body means that the file will be uploaded which means an external site can upload a file. +Protecting multipart requests (file uploads) from CSRF attacks causes a https://en.wikipedia.org/wiki/Chicken_or_the_egg[chicken or the egg] problem. +To prevent a CSRF attack from occurring, the body of the HTTP request must be read to obtain the actual CSRF token. +However, reading the body means that the file is uploaded, which means an external site can upload a file. -There are two options to using CSRF protection with multipart/form-data. -Each option has its trade-offs. +There are two options to using CSRF protection with multipart/form-data: * <> * <> -[NOTE] -==== -Before you integrate Spring Security's CSRF protection with multipart file upload, ensure that you can upload without the CSRF protection first. -More information about using multipart forms with Spring can be found within the https://docs.spring.io/spring/docs/5.2.x/spring-framework-reference/web.html#mvc-multipart[1.1.11. Multipart Resolver] section of the Spring reference and the https://docs.spring.io/spring/docs/5.2.x/javadoc-api/org/springframework/web/multipart/support/MultipartFilter.html[MultipartFilter javadoc]. -==== +Each option has its trade-offs. + +NOTE: Before you integrate Spring Security's CSRF protection with multipart file upload, you should first ensure that you can upload without the CSRF protection. +More information about using multipart forms with Spring, see the https://docs.spring.io/spring/docs/5.2.x/spring-framework-reference/web.html#mvc-multipart[1.1.11. Multipart Resolver] section of the Spring reference and the https://docs.spring.io/spring/docs/5.2.x/javadoc-api/org/springframework/web/multipart/support/MultipartFilter.html[`MultipartFilter` Javadoc]. [[csrf-considerations-multipart-body]] ==== Place CSRF Token in the Body The first option is to include the actual CSRF token in the body of the request. -By placing the CSRF token in the body, the body will be read before authorization is performed. +By placing the CSRF token in the body, the body is read before authorization is performed. This means that anyone can place temporary files on your server. -However, only authorized users will be able to submit a File that is processed by your application. -In general, this is the recommended approach because the temporary file upload should have a negligible impact on most servers. +However, only authorized users can submit a file that is processed by your application. +In general, this is the recommended approach, because the temporary file upload should have a negligible impact on most servers. [[csrf-considerations-multipart-url]] ==== Include CSRF Token in URL -If allowing unauthorized users to upload temporary files is not acceptable, an alternative is to include the expected CSRF token as a query parameter in the action attribute of the form. +If letting unauthorized users upload temporary files is not acceptable, an alternative is to include the expected CSRF token as a query parameter in the action attribute of the form. The disadvantage to this approach is that query parameters can be leaked. More generally, it is considered best practice to place sensitive data within the body or headers to ensure it is not leaked. -Additional information can be found in https://www.w3.org/Protocols/rfc2616/rfc2616-sec15.html#sec15.1.3[RFC 2616 Section 15.1.3 Encoding Sensitive Information in URI's]. +You can find additional information in https://www.w3.org/Protocols/rfc2616/rfc2616-sec15.html#sec15.1.3[RFC 2616 Section 15.1.3 Encoding Sensitive Information in URI's]. [[csrf-considerations-override-method]] ==== HiddenHttpMethodFilter -In some applications a form parameter can be used to override the HTTP method. -For example, the form below could be used to treat the HTTP method as a `delete` rather than a `post`. +Some applications can use a form parameter to override the HTTP method. +For example, the following form can treat the HTTP method as a `delete` rather than a `post`. .CSRF Hidden HTTP Method Form ==== @@ -409,5 +391,5 @@ For example, the form below could be used to treat the HTTP method as a `delete` Overriding the HTTP method occurs in a filter. That filter must be placed before Spring Security's support. -Note that overriding only happens on a `post`, so this is actually unlikely to cause any real problems. -However, it is still best practice to ensure it is placed before Spring Security's filters. +Note that overriding happens only on a `post`, so this is actually unlikely to cause any real problems. +However, it is still best practice to ensure that it is placed before Spring Security's filters. diff --git a/docs/manual/src/docs/asciidoc/_includes/about/exploits/headers.adoc b/docs/manual/src/docs/asciidoc/_includes/about/exploits/headers.adoc index ee3639d937e..babd63026f4 100644 --- a/docs/manual/src/docs/asciidoc/_includes/about/exploits/headers.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/about/exploits/headers.adoc @@ -1,23 +1,17 @@ [[headers]] = Security HTTP Response Headers -[NOTE] -==== -This portion of the documentation discusses the general topic of Security HTTP Response Headers. -Refer to the relevant sections for specific information on Security HTTP Response Headers <> and <> based applications. -==== +NOTE: This portion of the documentation discusses the general topic of Security HTTP Response Headers. +See the relevant sections for specific information on Security HTTP Response Headers in <>- and <>-based applications. -There are many https://www.owasp.org/index.php/OWASP_Secure_Headers_Project#tab=Headers[HTTP response headers] that can be used to increase the security of web applications. -This section is dedicated to the various HTTP response headers that Spring Security provides explicit support for. -If necessary, Spring Security can also be configured to provide <>. +You can use https://www.owasp.org/index.php/OWASP_Secure_Headers_Project#tab=Headers[HTTP response headers] in many ways to increase the security of web applications. +This section is dedicated to the various HTTP response headers for which Spring Security provides explicit support. +If necessary, you can also configure Spring Security to provide <>. [[headers-default]] == Default Security Headers -[NOTE] -==== -Refer to the relevant sections to see how to customize the defaults for both <> and <> based applications. -==== +NOTE: See the relevant sections for how to customize the defaults for both <>- and <>-based applications. Spring Security provides a default set of security related HTTP response headers to provide secure defaults. @@ -37,10 +31,10 @@ X-XSS-Protection: 1; mode=block ---- ==== -NOTE: Strict-Transport-Security is only added on HTTPS requests +NOTE: Strict-Transport-Security is added only on HTTPS requests If the defaults do not meet your needs, you can easily remove, modify, or add headers from these defaults. -For additional details on each of these headers, refer to the corresponding sections: +For additional details on each of these headers, see the corresponding sections: * <> * <> @@ -51,14 +45,11 @@ For additional details on each of these headers, refer to the corresponding sect [[headers-cache-control]] == Cache Control -[NOTE] -==== -Refer to the relevant sections to see how to customize the defaults for both <> and <> based applications. -==== +NOTE: See the relevant sections for how to customize the defaults for both <>- and <>-based applications. -Spring Security's default is to disable caching to protect user's content. +Spring Security's default is to disable caching to protect the user's content. -If a user authenticates to view sensitive information and then logs out, we don't want a malicious user to be able to click the back button to view the sensitive information. +If a user authenticates to view sensitive information and then logs out, we do not want a malicious user to be able to click the back button to view the sensitive information. The cache control headers that are sent by default are: .Default Cache Control HTTP Response Headers @@ -71,35 +62,29 @@ Expires: 0 ---- ==== -In order to be secure by default, Spring Security adds these headers by default. -However, if your application provides its own cache control headers Spring Security will back out of the way. -This allows for applications to ensure that static resources like CSS and JavaScript can be cached. +To be secure by default, Spring Security adds these headers by default. +However, if your application provides its own cache control headers, Spring Security backs out of the way. +This allows for applications to ensure that static resources (such as CSS and JavaScript) can be cached. [[headers-content-type-options]] == Content Type Options -[NOTE] -==== -Refer to the relevant sections to see how to customize the defaults for both <> and <> based applications. -==== +NOTE: See the relevant sections for how to customize the defaults for both <>- and <>-based applications. -Historically browsers, including Internet Explorer, would try to guess the content type of a request using https://en.wikipedia.org/wiki/Content_sniffing[content sniffing]. -This allowed browsers to improve the user experience by guessing the content type on resources that had not specified the content type. +Historically, browsers, including Internet Explorer, would try to guess the content type of a request by using https://en.wikipedia.org/wiki/Content_sniffing[content sniffing]. +This let browsers improve the user experience by guessing the content type on resources that had not specified the content type. For example, if a browser encountered a JavaScript file that did not have the content type specified, it would be able to guess the content type and then run it. -[NOTE] -==== -There are many additional things one should do (i.e. only display the document in a distinct domain, ensure Content-Type header is set, sanitize the document, etc) when allowing content to be uploaded. +NOTE: There are many additional things one should do (such as only display the document in a distinct domain, ensure Content-Type header is set, sanitize the document, and others) when allowing content to be uploaded. However, these measures are out of the scope of what Spring Security provides. -It is also important to point out when disabling content sniffing, you must specify the content type in order for things to work properly. -==== +It is also important to point out that, when disabling content sniffing, you must specify the content type in order for things to work properly. -The problem with content sniffing is that this allowed malicious users to use polyglots (i.e. a file that is valid as multiple content types) to perform XSS attacks. +The problem with content sniffing is that this allowed malicious users to use polyglots (that is, a file that is valid as multiple content types) to perform XSS attacks. For example, some sites may allow users to submit a valid postscript document to a website and view it. -A malicious user might create a http://webblaze.cs.berkeley.edu/papers/barth-caballero-song.pdf[postscript document that is also a valid JavaScript file] and perform a XSS attack with it. +A malicious user might create a http://webblaze.cs.berkeley.edu/papers/barth-caballero-song.pdf[postscript document that is also a valid JavaScript file] and perform an XSS attack with it. -Spring Security disables content sniffing by default by adding the following header to HTTP responses: +By default, Spring Security disables content sniffing by adding the following header to HTTP responses: .nosniff HTTP Response Header ==== @@ -112,28 +97,22 @@ X-Content-Type-Options: nosniff [[headers-hsts]] == HTTP Strict Transport Security (HSTS) -[NOTE] -==== -Refer to the relevant sections to see how to customize the defaults for both <> and <> based applications. -==== +NOTE: Refer to the relevant sections to see how to customize the defaults for both <> and <> based applications. -When you type in your bank's website, do you enter mybank.example.com or do you enter https://mybank.example.com[]? -If you omit the https protocol, you are potentially vulnerable to https://en.wikipedia.org/wiki/Man-in-the-middle_attack[Man in the Middle attacks]. -Even if the website performs a redirect to https://mybank.example.com a malicious user could intercept the initial HTTP request and manipulate the response (e.g. redirect to https://mibank.example.com and steal their credentials). +When you type in your bank's website, do you enter `mybank.example.com` or do you enter `https://mybank.example.com`? +If you omit the `https` protocol, you are potentially vulnerable to https://en.wikipedia.org/wiki/Man-in-the-middle_attack[Man-in-the-Middle attacks]. +Even if the website performs a redirect to https://mybank.example.com, a malicious user could intercept the initial HTTP request and manipulate the response (for example, redirect to https://mibank.example.com and steal their credentials). -Many users omit the https protocol and this is why https://tools.ietf.org/html/rfc6797[HTTP Strict Transport Security (HSTS)] was created. -Once mybank.example.com is added as a https://tools.ietf.org/html/rfc6797#section-5.1[HSTS host], a browser can know ahead of time that any request to mybank.example.com should be interpreted as https://mybank.example.com. -This greatly reduces the possibility of a Man in the Middle attack occurring. +Many users omit the `https` protocol, and this is why https://tools.ietf.org/html/rfc6797[HTTP Strict Transport Security (HSTS)] was created. +Once `mybank.example.com` is added as a https://tools.ietf.org/html/rfc6797#section-5.1[HSTS host], a browser can know ahead of time that any request to mybank.example.com should be interpreted as https://mybank.example.com. +This greatly reduces the possibility of a Man-in-the-Middle attack occurring. -[NOTE] -==== -In accordance with https://tools.ietf.org/html/rfc6797#section-7.2[RFC6797], the HSTS header is only injected into HTTPS responses. -In order for the browser to acknowledge the header, the browser must first trust the CA that signed the SSL certificate used to make the connection (not just the SSL certificate). -==== +NOTE: In accordance with https://tools.ietf.org/html/rfc6797#section-7.2[RFC6797], the HSTS header is injected only into HTTPS responses. +For the browser to acknowledge the header, the browser must first trust the CA that signed the SSL certificate used to make the connection (not just the SSL certificate). One way for a site to be marked as a HSTS host is to have the host preloaded into the browser. -Another is to add the `Strict-Transport-Security` header to the response. -For example, Spring Security's default behavior is to add the following header which instructs the browser to treat the domain as an HSTS host for a year (there are approximately 31536000 seconds in a year): +Another way is to add the `Strict-Transport-Security` header to the response. +For example, Spring Security's default behavior is to add the following header, which instructs the browser to treat the domain as an HSTS host for a year (there are 31536000 seconds in a non-leap year): .Strict Transport Security HTTP Response Header @@ -144,99 +123,83 @@ Strict-Transport-Security: max-age=31536000 ; includeSubDomains ; preload ---- ==== -The optional `includeSubDomains` directive instructs the browser that subdomains (e.g. secure.mybank.example.com) should also be treated as an HSTS domain. +The optional `includeSubDomains` directive instructs the browser that subdomains (such as `secure.mybank.example.com`) should also be treated as an HSTS domain. -The optional `preload` directive instructs the browser that domain should be preloaded in browser as HSTS domain. -For more details on HSTS preload please see https://hstspreload.org. +The optional `preload` directive instructs the browser that the domain should be preloaded in browser as an HSTS domain. +For more details on HSTS preload, see https://hstspreload.org. [[headers-hpkp]] == HTTP Public Key Pinning (HPKP) -[NOTE] -==== -In order to remain passive Spring Security still provides <>, but for the reasons listed above HPKP is no longer recommended by the security team. -==== +NOTE: To remain passive, Spring Security still provides <>. However, for the reasons listed earlier, HPKP is no longer recommended by the Spring Security team. -https://developer.mozilla.org/en-US/docs/Web/HTTP/Public_Key_Pinning[HTTP Public Key Pinning (HPKP)] specifies to a web client which public key to use with certain web server to prevent Man in the Middle (MITM) attacks with forged certificates. +https://developer.mozilla.org/en-US/docs/Web/HTTP/Public_Key_Pinning[HTTP Public Key Pinning (HPKP)] specifies to a web client which public key to use with a certain web server to prevent Man-in-the-Middle (MITM) attacks with forged certificates. When used correctly, HPKP could add additional layers of protection against compromised certificates. -However, due to the complexity of HPKP many experts no longer recommend using it and https://www.chromestatus.com/feature/5903385005916160[Chrome has even removed support] for it. +However, due to the complexity of HPKP, many experts no longer recommend using it and https://www.chromestatus.com/feature/5903385005916160[Chrome has even removed support] for it. [[headers-hpkp-deprecated]] -For additional details around why HPKP is no longer recommended read https://blog.qualys.com/ssllabs/2016/09/06/is-http-public-key-pinning-dead[ -Is HTTP Public Key Pinning Dead?] and https://scotthelme.co.uk/im-giving-up-on-hpkp/[I'm giving up on HPKP]. +For additional details around why HPKP is no longer recommended, read https://blog.qualys.com/ssllabs/2016/09/06/is-http-public-key-pinning-dead[Is HTTP Public Key Pinning Dead?] and https://scotthelme.co.uk/im-giving-up-on-hpkp/[I'm giving up on HPKP]. [[headers-frame-options]] == X-Frame-Options -[NOTE] -==== -Refer to the relevant sections to see how to customize the defaults for both <> and <> based applications. -==== +NOTE: See the relevant sections to see how to customize the defaults for both <> and <> based applications. -Allowing your website to be added to a frame can be a security issue. -For example, using clever CSS styling users could be tricked into clicking on something that they were not intending. +Letting your website be added to a frame can be a security issue. +For example, by using clever CSS styling, users could be tricked into clicking on something that they were not intending. For example, a user that is logged into their bank might click a button that grants access to other users. This sort of attack is known as https://en.wikipedia.org/wiki/Clickjacking[Clickjacking]. -[NOTE] -==== -Another modern approach to dealing with clickjacking is to use <>. -==== +NOTE: Another modern approach to dealing with clickjacking is to use <>. There are a number ways to mitigate clickjacking attacks. -For example, to protect legacy browsers from clickjacking attacks you can use https://www.owasp.org/index.php/Clickjacking_Defense_Cheat_Sheet#Best-for-now_Legacy_Browser_Frame_Breaking_Script[frame breaking code]. +For example, to protect legacy browsers from clickjacking attacks, you can use https://www.owasp.org/index.php/Clickjacking_Defense_Cheat_Sheet#Best-for-now_Legacy_Browser_Frame_Breaking_Script[frame breaking code]. While not perfect, the frame breaking code is the best you can do for the legacy browsers. A more modern approach to address clickjacking is to use https://developer.mozilla.org/en-US/docs/HTTP/X-Frame-Options[X-Frame-Options] header. -By default Spring Security disables rendering pages within an iframe using with the following header: +By default, Spring Security disables rendering pages within an iframe by using with the following header: +==== [source] ---- X-Frame-Options: DENY ---- +==== [[headers-xss-protection]] == X-XSS-Protection -[NOTE] -==== -Refer to the relevant sections to see how to customize the defaults for both <> and <> based applications. -==== +NOTE: See the relevant sections to see how to customize the defaults for both <>- and <>-based applications. -Some browsers have built in support for filtering out https://www.owasp.org/index.php/Testing_for_Reflected_Cross_site_scripting_(OWASP-DV-001)[reflected XSS attacks]. -This is by no means foolproof, but does assist in XSS protection. +Some browsers have built-in support for filtering out https://www.owasp.org/index.php/Testing_for_Reflected_Cross_site_scripting_(OWASP-DV-001)[reflected XSS attacks]. +This is by no means foolproof but does assist in XSS protection. The filtering is typically enabled by default, so adding the header typically just ensures it is enabled and instructs the browser what to do when a XSS attack is detected. For example, the filter might try to change the content in the least invasive way to still render everything. -At times, this type of replacement can become a https://hackademix.net/2009/11/21/ies-xss-filter-creates-xss-vulnerabilities/[XSS vulnerability in itself]. +At times, this type of replacement can become an https://hackademix.net/2009/11/21/ies-xss-filter-creates-xss-vulnerabilities/[XSS vulnerability in itself]. Instead, it is best to block the content rather than attempt to fix it. -By default Spring Security blocks the content using the following header: +By default, Spring Security blocks the content by using the following header: +==== [source] ---- X-XSS-Protection: 1; mode=block ---- - +==== [[headers-csp]] == Content Security Policy (CSP) -[NOTE] -==== -Refer to the relevant sections to see how to configure both <> and <> based applications. -==== +NOTE: See the relevant sections to see how to configure both <>- and <>-based applications. -https://www.w3.org/TR/CSP2/[Content Security Policy (CSP)] is a mechanism that web applications can leverage to mitigate content injection vulnerabilities, such as cross-site scripting (XSS). +https://www.w3.org/TR/CSP2/[Content Security Policy (CSP)] is a mechanism that web applications can use to mitigate content injection vulnerabilities, such as cross-site scripting (XSS). CSP is a declarative policy that provides a facility for web application authors to declare and ultimately inform the client (user-agent) about the sources from which the web application expects to load resources. -[NOTE] -==== -Content Security Policy is not intended to solve all content injection vulnerabilities. -Instead, CSP can be leveraged to help reduce the harm caused by content injection attacks. +NOTE: Content Security Policy is not intended to solve all content injection vulnerabilities. +Instead, you can use CSP to help reduce the harm caused by content injection attacks. As a first line of defense, web application authors should validate their input and encode their output. -==== -A web application may employ the use of CSP by including one of the following HTTP headers in the response: +A web application can use CSP by including one of the following HTTP headers in the response: * `Content-Security-Policy` * `Content-Security-Policy-Report-Only` @@ -244,7 +207,7 @@ A web application may employ the use of CSP by including one of the following HT Each of these headers are used as a mechanism to deliver a security policy to the client. A security policy contains a set of security policy directives, each responsible for declaring the restrictions for a particular resource representation. -For example, a web application can declare that it expects to load scripts from specific, trusted sources, by including the following header in the response: +For example, a web application can declare that it expects to load scripts from specific, trusted sources by including the following header in the response: .Content Security Policy Example ==== @@ -254,10 +217,10 @@ Content-Security-Policy: script-src https://trustedscripts.example.com ---- ==== -An attempt to load a script from another source other than what is declared in the `script-src` directive will be blocked by the user-agent. -Additionally, if the https://www.w3.org/TR/CSP2/#directive-report-uri[report-uri] directive is declared in the security policy, then the violation will be reported by the user-agent to the declared URL. +An attempt to load a script from another source other than what is declared in the `script-src` directive is blocked by the user-agent. +Additionally, if the https://www.w3.org/TR/CSP2/#directive-report-uri[report-uri] directive is declared in the security policy, the violation will be reported by the user-agent to the declared URL. -For example, if a web application violates the declared security policy, the following response header will instruct the user-agent to send violation reports to the URL specified in the policy's `report-uri` directive. +For example, if a web application violates the declared security policy, the following response header instructs the user-agent to send violation reports to the URL specified in the policy's `report-uri` directive. .Content Security Policy with report-uri ==== @@ -267,13 +230,13 @@ Content-Security-Policy: script-src https://trustedscripts.example.com; report-u ---- ==== -https://www.w3.org/TR/CSP2/#violation-reports[Violation reports] are standard JSON structures that can be captured either by the web application's own API or by a publicly hosted CSP violation reporting service, such as, https://report-uri.io/. +https://www.w3.org/TR/CSP2/#violation-reports[Violation reports] are standard JSON structures that can be captured either by the web application's own API or by a publicly hosted CSP violation reporting service, such as https://report-uri.io/. -The `Content-Security-Policy-Report-Only` header provides the capability for web application authors and administrators to monitor security policies, rather than enforce them. -This header is typically used when experimenting and/or developing security policies for a site. +The `Content-Security-Policy-Report-Only` header provides the capability for web application authors and administrators to monitor security policies rather than enforce them. +This header is typically used when experimenting or developing security policies for a site. When a policy is deemed effective, it can be enforced by using the `Content-Security-Policy` header field instead. -Given the following response header, the policy declares that scripts may be loaded from one of two possible sources. +Given the following response header, the policy declares that scripts can be loaded from one of two possible sources. .Content Security Policy Report Only ==== @@ -283,10 +246,10 @@ Content-Security-Policy-Report-Only: script-src 'self' https://trustedscripts.ex ---- ==== -If the site violates this policy, by attempting to load a script from _evil.com_, the user-agent will send a violation report to the declared URL specified by the _report-uri_ directive, but still allow the violating resource to load nevertheless. +If the site violates this policy, by attempting to load a script from evil.com, the user-agent sends a violation report to the declared URL specified by the `report-uri` directive but still lets the violating resource load. Applying Content Security Policy to a web application is often a non-trivial undertaking. -The following resources may provide further assistance in developing effective security policies for your site. +The following resources may provide further assistance in developing effective security policies for your site: https://www.html5rocks.com/en/tutorials/security/content-security-policy/[An Introduction to Content Security Policy] @@ -297,15 +260,12 @@ https://www.w3.org/TR/CSP2/[W3C Candidate Recommendation] [[headers-referrer]] == Referrer Policy -[NOTE] -==== -Refer to the relevant sections to see how to configure both <> and <> based applications. -==== +NOTE: See the relevant sections to see how to configure both <>- and <>-based applications. -https://www.w3.org/TR/referrer-policy[Referrer Policy] is a mechanism that web applications can leverage to manage the referrer field, which contains the last +https://www.w3.org/TR/referrer-policy[Referrer Policy] is a mechanism that web applications can use to manage the referrer field, which contains the last page the user was on. -Spring Security's approach is to use https://www.w3.org/TR/referrer-policy/[Referrer Policy] header, which provides different https://www.w3.org/TR/referrer-policy/#referrer-policies[policies]: +Spring Security's approach is to use the https://www.w3.org/TR/referrer-policy/[Referrer Policy] header, which provides different https://www.w3.org/TR/referrer-policy/#referrer-policies[policies]: .Referrer Policy Example ==== @@ -320,12 +280,9 @@ The Referrer-Policy response header instructs the browser to let the destination [[headers-feature]] == Feature Policy -[NOTE] -==== -Refer to the relevant sections to see how to configure both <> and <> based applications. -==== +NOTE: See the relevant sections to see how to configure both <>- and <>-based applications. -https://wicg.github.io/feature-policy/[Feature Policy] is a mechanism that allows web developers to selectively enable, disable, and modify the behavior of certain APIs and web features in the browser. +https://wicg.github.io/feature-policy/[Feature Policy] is a mechanism that lets web developers selectively enable, disable, and modify the behavior of certain APIs and web features in the browser. .Feature Policy Example ==== @@ -335,19 +292,16 @@ Feature-Policy: geolocation 'self' ---- ==== -With Feature Policy, developers can opt-in to a set of "policies" for the browser to enforce on specific features used throughout your site. +With Feature Policy, developers can opt-in to a set of "`policies`" for the browser to enforce on specific features used throughout your site. These policies restrict what APIs the site can access or modify the browser's default behavior for certain features. [[headers-permissions]] == Permissions Policy -[NOTE] -==== -Refer to the relevant sections to see how to configure both <> and <> based applications. -==== +NOTE: See the relevant sections to see how to configure both <>- and <>-based applications. -https://w3c.github.io/webappsec-permissions-policy/[Permissions Policy] is a mechanism that allows web developers to selectively enable, disable, and modify the behavior of certain APIs and web features in the browser. +https://w3c.github.io/webappsec-permissions-policy/[Permissions Policy] is a mechanism that lets web developers selectively enable, disable, and modify the behavior of certain APIs and web features in the browser. .Permissions Policy Example ==== @@ -357,24 +311,23 @@ Permissions-Policy: geolocation=(self) ---- ==== -With Permissions Policy, developers can opt-in to a set of "policies" for the browser to enforce on specific features used throughout your site. +With a Permissions Policy, developers can opt-in to a set of "`policies`" for the browser to enforce on specific features used throughout your site. These policies restrict what APIs the site can access or modify the browser's default behavior for certain features. [[headers-clear-site-data]] == Clear Site Data -[NOTE] -==== -Refer to the relevant sections to see how to configure both <> and <> based applications. -==== +NOTE: See the relevant sections to see how to configure both <> and <> based applications. -https://www.w3.org/TR/clear-site-data/[Clear Site Data] is a mechanism by which any browser-side data - cookies, local storage, and the like - can be removed when an HTTP response contains this header: +https://www.w3.org/TR/clear-site-data/[Clear Site Data] is a mechanism by which any browser-side data (cookies, local storage, and the like) can be removed when an HTTP response contains this header: +==== [source] ---- Clear-Site-Data: "cache", "cookies", "storage", "executionContexts" ---- +==== This is a nice clean-up action to perform on logout. @@ -382,10 +335,7 @@ This is a nice clean-up action to perform on logout. [[headers-custom]] == Custom Headers -[NOTE] -==== -Refer to the relevant sections to see how to configure both <> based applications. -==== +NOTE: See the relevant sections to see how to configure both <> based applications. Spring Security has mechanisms to make it convenient to add the more common security headers to your application. However, it also provides hooks to enable adding custom headers. diff --git a/docs/manual/src/docs/asciidoc/_includes/about/exploits/http.adoc b/docs/manual/src/docs/asciidoc/_includes/about/exploits/http.adoc index 5d0dfa6c329..68f6631e6f3 100644 --- a/docs/manual/src/docs/asciidoc/_includes/about/exploits/http.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/about/exploits/http.adoc @@ -1,7 +1,7 @@ [[http]] = HTTP -All HTTP based communication, including https://www.troyhunt.com/heres-why-your-static-website-needs-https/[static resources], should be protected https://cheatsheetseries.owasp.org/cheatsheets/Transport_Layer_Protection_Cheat_Sheet.html[using TLS]. +All HTTP-based communication, including https://www.troyhunt.com/heres-why-your-static-website-needs-https/[static resources], should be protected by https://cheatsheetseries.owasp.org/cheatsheets/Transport_Layer_Protection_Cheat_Sheet.html[using TLS]. As a framework, Spring Security does not handle HTTP connections and thus does not provide support for HTTPS directly. However, it does provide a number of features that help with HTTPS usage. @@ -9,7 +9,7 @@ However, it does provide a number of features that help with HTTPS usage. [[http-redirect]] == Redirect to HTTPS -When a client uses HTTP, Spring Security can be configured to redirect to HTTPS both <> and <> environments. +When a client uses HTTP, you can configure Spring Security to redirect to HTTPS in both <> and <> environments. [[http-hsts]] == Strict Transport Security @@ -19,14 +19,14 @@ Spring Security provides support for <> [[http-proxy-server]] == 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 -Without proper configuration, the application server will not know that the load balancer exists and treat the request as though https://192.168.1:8080 was requested by the client. +When using a proxy server, it is important to ensure that you have configured your application properly. +For example, many applications 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 +Without proper configuration, the application server can not know that the load balancer exists and treats the request as though https://192.168.1:8080 was requested by the client. -To fix this you can use https://tools.ietf.org/html/rfc7239[RFC 7239] to specify that a load balancer is being used. -To make the application aware of this, you need to either configure your application server aware of the X-Forwarded headers. -For example Tomcat uses the https://tomcat.apache.org/tomcat-8.0-doc/api/org/apache/catalina/valves/RemoteIpValve.html[RemoteIpValve] and Jetty uses https://download.eclipse.org/jetty/stable-9/apidocs/org/eclipse/jetty/server/ForwardedRequestCustomizer.html[ForwardedRequestCustomizer]. -Alternatively, Spring users can leverage https://github.com/spring-projects/spring-framework/blob/v4.3.3.RELEASE/spring-web/src/main/java/org/springframework/web/filter/ForwardedHeaderFilter.java[ForwardedHeaderFilter]. +To fix this, you can use https://tools.ietf.org/html/rfc7239[RFC 7239] to specify that a load balancer is being used. +To make the application aware of this, you need to configure your application server to be aware of the X-Forwarded headers. +For example, Tomcat uses https://tomcat.apache.org/tomcat-8.0-doc/api/org/apache/catalina/valves/RemoteIpValve.html[`RemoteIpValve`] and Jetty uses https://download.eclipse.org/jetty/stable-9/apidocs/org/eclipse/jetty/server/ForwardedRequestCustomizer.html[`ForwardedRequestCustomizer`]. +Alternatively, Spring users can use https://github.com/spring-projects/spring-framework/blob/v4.3.3.RELEASE/spring-web/src/main/java/org/springframework/web/filter/ForwardedHeaderFilter.java[`ForwardedHeaderFilter`]. -Spring Boot users may use the `server.use-forward-headers` property to configure the application. +Spring Boot users can use the `server.use-forward-headers` property to configure the application. See the https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#howto-use-tomcat-behind-a-proxy-server[Spring Boot documentation] for further details. diff --git a/docs/manual/src/docs/asciidoc/_includes/about/exploits/index.adoc b/docs/manual/src/docs/asciidoc/_includes/about/exploits/index.adoc index bb8abc73dc8..eb5ef9b637f 100644 --- a/docs/manual/src/docs/asciidoc/_includes/about/exploits/index.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/about/exploits/index.adoc @@ -3,7 +3,7 @@ Spring Security provides protection against common exploits. Whenever possible, the protection is enabled by default. -Below you will find high level description of the various exploits that Spring Security protects against. +This section describes the various exploits that Spring Security protects against. include::csrf.adoc[leveloffset=+1] diff --git a/docs/manual/src/docs/asciidoc/_includes/about/features.adoc b/docs/manual/src/docs/asciidoc/_includes/about/features.adoc index c08113ae5ea..9ce044b519c 100644 --- a/docs/manual/src/docs/asciidoc/_includes/about/features.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/about/features.adoc @@ -1,6 +1,7 @@ [[features]] = Features +// FIXME: Add a link for authorization Spring Security provides comprehensive support for <>, authorization, and protection against <>. It also provides integration with other libraries to simplify its usage. diff --git a/docs/manual/src/docs/asciidoc/_includes/about/getting-spring-security.adoc b/docs/manual/src/docs/asciidoc/_includes/about/getting-spring-security.adoc index c2b64f113ad..464ee567dc7 100644 --- a/docs/manual/src/docs/asciidoc/_includes/about/getting-spring-security.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/about/getting-spring-security.adoc @@ -1,7 +1,7 @@ [[getting]] = Getting Spring Security -This section discusses all you need to know about getting the Spring Security binaries. +This section describes how to get the Spring Security binaries. See <> for how to obtain the source code. == Release Numbering @@ -10,7 +10,7 @@ Spring Security versions are formatted as MAJOR.MINOR.PATCH such that: * MAJOR versions may contain breaking changes. Typically, these are done to provide improved security to match modern security practices. -* MINOR versions contain enhancements but are considered passive updates +* MINOR versions contain enhancements but are considered passive updates. * PATCH level should be perfectly compatible, forwards and backwards, with the possible exception of changes that fix bugs. @@ -18,13 +18,13 @@ Typically, these are done to provide improved security to match modern security == Usage with Maven As most open source projects, Spring Security deploys its dependencies as Maven artifacts. -The topics in this section provide detail on how to consume Spring Security when using Maven. +The topics in this section describe how to consume Spring Security when using Maven. [[getting-maven-boot]] === Spring Boot with Maven -Spring Boot provides a `spring-boot-starter-security` starter that aggregates Spring Security-related dependencies together. -The simplest and preferred way to use the starter is to use https://docs.spring.io/initializr/docs/current/reference/htmlsingle/[Spring Initializr] by using an IDE integration (https://joshlong.com/jl/blogPost/tech_tip_geting_started_with_spring_boot.html[Eclipse], https://www.jetbrains.com/help/idea/spring-boot.html#d1489567e2[IntelliJ], https://github.com/AlexFalappa/nb-springboot/wiki/Quick-Tour[NetBeans]) or through https://start.spring.io. +Spring Boot provides a `spring-boot-starter-security` starter that aggregates Spring Security-related dependencies. +The simplest and preferred way to use the starter is to use https://docs.spring.io/initializr/docs/current/reference/htmlsingle/[Spring Initializr] by using an IDE integration in (https://joshlong.com/jl/blogPost/tech_tip_geting_started_with_spring_boot.html[Eclipse] or https://www.jetbrains.com/help/idea/spring-boot.html#d1489567e2[IntelliJ], https://github.com/AlexFalappa/nb-springboot/wiki/Quick-Tour[NetBeans]) or through https://start.spring.io. Alternatively, you can manually add the starter, as the following example shows: @@ -44,7 +44,7 @@ Alternatively, you can manually add the starter, as the following example shows: ==== Since Spring Boot provides a Maven BOM to manage dependency versions, you do not need to specify a version. -If you wish to override the Spring Security version, you may do so by providing a Maven property, as the following example shows: +If you wish to override the Spring Security version, you can do so by providing a Maven property: .pom.xml ==== @@ -57,9 +57,9 @@ If you wish to override the Spring Security version, you may do so by providing ---- ==== -Since Spring Security makes breaking changes only in major releases, it is safe to use a newer version of Spring Security with Spring Boot. +Since Spring Security makes breaking changes only in major releases, you can safely use a newer version of Spring Security with Spring Boot. However, at times, you may need to update the version of Spring Framework as well. -You can do so by adding a Maven property, as the following example shows: +You can do so by adding a Maven property: .pom.xml ==== @@ -72,12 +72,12 @@ You can do so by adding a Maven property, as the following example shows: ---- ==== -If you use additional features (such as LDAP, OpenID, and others), you need to also include the appropriate <>. +If you use additional features (such as LDAP, OpenID, and others), you need to also include the appropriate <>. [[getting-maven-no-boot]] === Maven Without Spring Boot -When you use Spring Security without Spring Boot, the preferred way is to use Spring Security's BOM to ensure a consistent version of Spring Security is used throughout the entire project. The following example shows how to do so: +When you use Spring Security without Spring Boot, the preferred way is to use Spring Security's BOM to ensure that a consistent version of Spring Security is used throughout the entire project. The following example shows how to do so: .pom.xml ==== @@ -98,7 +98,7 @@ When you use Spring Security without Spring Boot, the preferred way is to use Sp ---- ==== -A minimal Spring Security Maven set of dependencies typically looks like the following: +A minimal Spring Security Maven set of dependencies typically looks like the following example: .pom.xml ==== @@ -118,11 +118,11 @@ A minimal Spring Security Maven set of dependencies typically looks like the fol ---- ==== -If you use additional features (such as LDAP, OpenID, and others), you need to also include the appropriate <>. +If you use additional features (such as LDAP, OpenID, and others), you need to also include the appropriate <>. Spring Security builds against Spring Framework {spring-core-version} but should generally work with any newer version of Spring Framework 5.x. Many users are likely to run afoul of the fact that Spring Security's transitive dependencies resolve Spring Framework {spring-core-version}, which can cause strange classpath problems. -The easiest way to resolve this is to use the `spring-framework-bom` within the `` section of your `pom.xml` as the following example shows: +The easiest way to resolve this is to use the `spring-framework-bom` within the `` section of your `pom.xml`: .pom.xml ==== @@ -150,9 +150,9 @@ For additional details about how dependencies are resolved, see https://maven.ap [[maven-repositories]] === Maven Repositories -All GA releases (that is, versions ending in .RELEASE) are deployed to Maven Central, so no additional Maven repositories need to be declared in your pom. +All GA releases (that is, versions ending in .RELEASE) are deployed to Maven Central, so you need not declare additional Maven repositories in your pom. -If you use a SNAPSHOT version, you need to ensure that you have the Spring Snapshot repository defined, as the following example shows: +If you use a SNAPSHOT version, you need to ensure that you have the Spring Snapshot repository defined: .pom.xml ==== @@ -190,15 +190,15 @@ If you use a milestone or release candidate version, you need to ensure that you == Gradle As most open source projects, Spring Security deploys its dependencies as Maven artifacts, which allows for first-class Gradle support. -The following topics provide detail on how to consume Spring Security when using Gradle. +The following topics describe how to consume Spring Security when using Gradle. [[getting-gradle-boot]] === Spring Boot with Gradle -Spring Boot provides a `spring-boot-starter-security` starter that aggregates Spring Security related dependencies together. -The simplest and preferred method to use the starter is to use https://docs.spring.io/initializr/docs/current/reference/htmlsingle/[Spring Initializr] by using an IDE integration (https://joshlong.com/jl/blogPost/tech_tip_geting_started_with_spring_boot.html[Eclipse], https://www.jetbrains.com/help/idea/spring-boot.html#d1489567e2[IntelliJ], https://github.com/AlexFalappa/nb-springboot/wiki/Quick-Tour[NetBeans]) or through https://start.spring.io. +Spring Boot provides a `spring-boot-starter-security` starter that aggregates Spring Security related dependencies. +The simplest and preferred method to use the starter is to use https://docs.spring.io/initializr/docs/current/reference/htmlsingle/[Spring Initializr] by using an IDE integration in (https://joshlong.com/jl/blogPost/tech_tip_geting_started_with_spring_boot.html[Eclipse] or https://www.jetbrains.com/help/idea/spring-boot.html#d1489567e2[IntelliJ], https://github.com/AlexFalappa/nb-springboot/wiki/Quick-Tour[NetBeans]) or through https://start.spring.io. -Alternatively, you can manually add the starter, as the following example shows: +Alternatively, you can manually add the starter: .build.gradle ==== @@ -212,7 +212,7 @@ dependencies { ==== Since Spring Boot provides a Maven BOM to manage dependency versions, you need not specify a version. -If you wish to override the Spring Security version, you may do so by providing a Gradle property, as the following example shows: +If you wish to override the Spring Security version, you can do so by providing a Gradle property: .build.gradle ==== @@ -223,9 +223,9 @@ ext['spring-security.version']='{spring-security-version}' ---- ==== -Since Spring Security makes breaking changes only in major releases, it is safe to use a newer version of Spring Security with Spring Boot. +Since Spring Security makes breaking changes only in major releases, you can safely use a newer version of Spring Security with Spring Boot. However, at times, you may need to update the version of Spring Framework as well. -You can do so by adding a Gradle property, as the following example shows: +You can do so by adding a Gradle property: .build.gradle ==== @@ -236,12 +236,12 @@ ext['spring.version']='{spring-core-version}' ---- ==== -If you use additional features (such as LDAP, OpenID, and others), you need to also include the appropriate <>. +If you use additional features (such as LDAP, OpenID, and others), you need to also include the appropriate <>. === Gradle Without Spring Boot When you use Spring Security without Spring Boot, the preferred way is to use Spring Security's BOM to ensure a consistent version of Spring Security is used throughout the entire project. -You can do so by using the https://github.com/spring-gradle-plugins/dependency-management-plugin[Dependency Management Plugin], as the following example shows: +You can do so by using the https://github.com/spring-gradle-plugins/dependency-management-plugin[Dependency Management Plugin]: .build.gradle ==== @@ -260,7 +260,7 @@ dependencyManagement { ---- ==== -A minimal Spring Security Maven set of dependencies typically looks like the following: +A minimal Spring Security Maven set of dependencies typically looks like the following example: .build.gradle ==== @@ -274,12 +274,12 @@ dependencies { ---- ==== -If you use additional features (such as LDAP, OpenID, and others), you need to also include the appropriate <>. +If you use additional features (such as LDAP, OpenID, and others), you need to also include the appropriate <>. Spring Security builds against Spring Framework {spring-core-version} but should generally work with any newer version of Spring Framework 5.x. Many users are likely to run afoul of the fact that Spring Security's transitive dependencies resolve Spring Framework {spring-core-version}, which can cause strange classpath problems. The easiest way to resolve this is to use the `spring-framework-bom` within your `` section of your `pom.xml`. -You can do so by using the https://github.com/spring-gradle-plugins/dependency-management-plugin[Dependency Management Plugin], as the following example shows: +You can do so by using the https://github.com/spring-gradle-plugins/dependency-management-plugin[Dependency Management Plugin]: .build.gradle ==== @@ -302,7 +302,7 @@ The preceding example ensures that all the transitive dependencies of Spring Sec [[gradle-repositories]] === Gradle Repositories -All GA releases (that is, versions ending in .RELEASE) are deployed to Maven Central, so using the mavenCentral() repository is sufficient for GA releases. The following example shows how to do so: +All GA releases (that is, versions ending in .RELEASE) are deployed to Maven Central, so using the `mavenCentral()` repository is sufficient for GA releases. The following example shows how to do so: .build.gradle ==== @@ -314,7 +314,7 @@ repositories { ---- ==== -If you use a SNAPSHOT version, you need to ensure you have the Spring Snapshot repository defined, as the following example shows: +If you use a SNAPSHOT version, you need to ensure that you have the Spring Snapshot repository defined: .build.gradle ==== @@ -326,7 +326,7 @@ repositories { ---- ==== -If you use a milestone or release candidate version, you need to ensure that you have the Spring Milestone repository defined, as the following example shows: +If you use a milestone or release candidate version, you need to ensure that you have the Spring Milestone repository defined: .build.gradle ==== diff --git a/docs/manual/src/docs/asciidoc/_includes/about/modules.adoc b/docs/manual/src/docs/asciidoc/_includes/about/modules.adoc index 3503fea601b..fd0c274581c 100644 --- a/docs/manual/src/docs/asciidoc/_includes/about/modules.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/about/modules.adoc @@ -8,13 +8,13 @@ Even if you do not use Maven, we recommend that you consult the `pom.xml` files Another good idea is to examine the libraries that are included in the sample applications. This section provides a reference of the modules in Spring Security and the additional dependencies that they require in order to function in a running application. -We don't include dependencies that are only used when building or testing Spring Security itself. -Nor do we include transitive dependencies which are required by external dependencies. +We do not include dependencies that are used only when building or testing Spring Security itself. +Nor do we include transitive dependencies that are required by external dependencies. -The version of Spring required is listed on the project website, so the specific versions are omitted for Spring dependencies below. -Note that some of the dependencies listed as "optional" below may still be required for other non-security functionality in a Spring application. -Also dependencies listed as "optional" may not actually be marked as such in the project's Maven POM files if they are used in most applications. -They are "optional" only in the sense that you don't need them unless you are using the specified functionality. +The version of Spring required is listed on the project website, so the specific versions are omitted for Spring dependencies in the examples. +Note that some of the dependencies listed as "`optional`" in the examples may still be required for other non-security functionality in a Spring application. +Also dependencies listed as "`optional`" may not actually be marked as such in the project's Maven POM files if they are used in most applications. +They are "`optional`" only in the sense that you do not need them unless you use the specified functionality. Where a module depends on another Spring Security module, the non-optional dependencies of the module it depends on are also assumed to be required and are not listed separately. @@ -85,7 +85,7 @@ The main package is `org.springframework.security.remoting`. | spring-web | -| Required for clients which use HTTP remoting support. +| Required for clients that use HTTP remoting support. |=== [[spring-security-web]] @@ -109,7 +109,7 @@ The main package is `org.springframework.security.web`. | spring-jdbc | -| Required for JDBC-based persistent remember-me token repository (optional). +| Required for a JDBC-based persistent remember-me token repository (optional). | spring-tx | @@ -170,10 +170,9 @@ The top-level package is `org.springframework.security.ldap`. | | Data exception classes are required. -| apache-ds footnote:[The modules `apacheds-core`, `apacheds-core-entry`, `apacheds-protocol-shared`, `apacheds-protocol-ldap` and `apacheds-server-jndi` are required. -] +| apache-ds | 1.5.5 -| Required if you are using an embedded LDAP server (optional). +| Required if you are using an embedded LDAP server (optional). If you use `apache-ds`, the `apacheds-core`, `apacheds-core-entry`, `apacheds-protocol-shared`, `apacheds-protocol-ldap` and `apacheds-server-jndi` modules are required. | shared-ldap | 0.9.15 @@ -188,7 +187,7 @@ Used for decoding LDAP password policy controls if you are using password-policy [[spring-security-oauth2-core]] == OAuth 2.0 Core -- `spring-security-oauth2-core.jar` `spring-security-oauth2-core.jar` contains core classes and interfaces that provide support for the OAuth 2.0 Authorization Framework and for OpenID Connect Core 1.0. -It is required by applications that use OAuth 2.0 or OpenID Connect Core 1.0, such as client, resource server, and authorization server. +It is required by applications that use OAuth 2.0 or OpenID Connect Core 1.0, such as the client, the resource server, and the authorization server. The top-level package is `org.springframework.security.oauth2.core`. @@ -218,7 +217,7 @@ It contains the following top-level packages: [[spring-security-oauth2-resource-server]] == OAuth 2.0 Resource Server -- `spring-security-oauth2-resource-server.jar` `spring-security-oauth2-resource-server.jar` contains Spring Security's support for OAuth 2.0 Resource Servers. -It is used to protect APIs via OAuth 2.0 Bearer Tokens. +It is used to protect APIs by using OAuth 2.0 Bearer Tokens. The top-level package is `org.springframework.security.oauth2.server.resource`. [[spring-security-acl]] @@ -237,7 +236,7 @@ The top-level package is `org.springframework.security.acls`. | ehcache | 1.6.2 -| Required if the Ehcache-based ACL cache implementation is used (optional if you are using your own implementation). +| Required if the Ehcache-based ACL cache implementation is used (optional if you use your own implementation). | spring-jdbc | @@ -278,8 +277,7 @@ This is the basis of the Spring Security integration. [[spring-security-openid]] == OpenID -- `spring-security-openid.jar` -[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. +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. This module contains OpenID web authentication support. It is used to authenticate users against an external OpenID server. diff --git a/docs/manual/src/docs/asciidoc/_includes/reactive/exploits/csrf.adoc b/docs/manual/src/docs/asciidoc/_includes/reactive/exploits/csrf.adoc index c3a92fea4f2..b0f80242204 100644 --- a/docs/manual/src/docs/asciidoc/_includes/reactive/exploits/csrf.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/reactive/exploits/csrf.adoc @@ -7,32 +7,32 @@ This section discusses Spring Security's <> -* <> -* <> +* <> +* <> +* <> [[webflux-csrf-idempotent]] -=== Use proper HTTP verbs +=== Use Proper HTTP Verbs The first step to protecting against CSRF attacks is to ensure your website uses proper HTTP verbs. This is covered in detail in <>. [[webflux-csrf-configure]] === Configure CSRF Protection The next step is to configure Spring Security's CSRF protection within your application. -Spring Security's CSRF protection is enabled by default, but you may need to customize the configuration. -Below are a few common customizations. +By default, Spring Security's CSRF protection is enabled, but you may need to customize the configuration. +The next few subsections cover a few common customizations. [[webflux-csrf-configure-custom-repository]] ==== Custom CsrfTokenRepository -By default Spring Security stores the expected CSRF token in the `WebSession` using `WebSessionServerCsrfTokenRepository`. -There can be cases where users will want to configure a custom `ServerCsrfTokenRepository`. -For example, it might be desirable to persist the `CsrfToken` in a cookie to <>. +By default, Spring Security stores the expected CSRF token in the `WebSession` by using `WebSessionServerCsrfTokenRepository`. +Sometimes, you may need to configure a custom `ServerCsrfTokenRepository`. +For example, you may want to persist the `CsrfToken` in a cookie to <>. -By default the `CookieServerCsrfTokenRepository` will write to a cookie named `XSRF-TOKEN` and read it from a header named `X-XSRF-TOKEN` or the HTTP parameter `_csrf`. +By default, the `CookieServerCsrfTokenRepository` writes to a cookie named `XSRF-TOKEN` and read its from a header named `X-XSRF-TOKEN` or the HTTP `_csrf` parameter. These defaults come from https://docs.angularjs.org/api/ng/service/$http#cross-site-request-forgery-xsrf-protection[AngularJS] -You can configure `CookieServerCsrfTokenRepository` in Java Configuration using: +You can configure `CookieServerCsrfTokenRepository` in Java Configuration: .Store CSRF Token in a Cookie ==== @@ -63,19 +63,16 @@ fun springSecurityFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain ----- ==== -[NOTE] -==== -The sample explicitly sets `cookieHttpOnly=false`. -This is necessary to allow JavaScript (i.e. AngularJS) to read it. -If you do not need the ability to read the cookie with JavaScript directly, it is recommended to omit `cookieHttpOnly=false` (by using `new CookieServerCsrfTokenRepository()` instead) to improve security. -==== +NOTE: The preceding sample explicitly sets `cookieHttpOnly=false`. +This is necessary to let JavaScript (in this case, AngularJS) to read it. +If you do not need the ability to read the cookie with JavaScript directly, we recommend to omitting `cookieHttpOnly=false` (by using `new CookieServerCsrfTokenRepository()` instead) to improve security. [[webflux-csrf-configure-disable]] ==== Disable CSRF Protection -CSRF protection is enabled by default. -However, it is simple to disable CSRF protection if it <>. +By default, CSRF protection is enabled. +However, you can disable CSRF protection if it <>. -The Java configuration below will disable CSRF protection. +The following Java configuration disables CSRF protection: .Disable CSRF Configuration ==== @@ -109,15 +106,15 @@ fun springSecurityFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain [[webflux-csrf-include]] === Include the CSRF Token -In order for the <> to protect against CSRF attacks, we must include the actual CSRF token in the HTTP request. -This must be included in a part of the request (i.e. form parameter, HTTP header, etc) that is not automatically included in the HTTP request by the browser. +For the <> to protect against CSRF attacks, we must include the actual CSRF token in the HTTP request. +It must be included in a part of the request (a form parameter, an HTTP header, or other option) that is not automatically included in the HTTP request by the browser. -Spring Security's https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/web/server/csrf/CsrfWebFilter.html[CsrfWebFilter] exposes a https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/web/csrf/CsrfToken.html[Mono] as a `ServerWebExchange` attribute named `org.springframework.security.web.server.csrf.CsrfToken`. -This means that any view technology can access the `Mono` to expose the expected token as either a <> or <>. +Spring Security's https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/web/server/csrf/CsrfWebFilter.html[`CsrfWebFilter`] exposes a https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/web/csrf/CsrfToken.html[`Mono`] as a `ServerWebExchange` attribute named `org.springframework.security.web.server.csrf.CsrfToken`. +This means that any view technology can access the `Mono` to expose the expected token as either a <> or a <>. [[webflux-csrf-include-subscribe]] If your view technology does not provide a simple way to subscribe to the `Mono`, a common pattern is to use Spring's `@ControllerAdvice` to expose the `CsrfToken` directly. -For example, the following code will place the `CsrfToken` on the default attribute name (`_csrf`) used by Spring Security's <> to automatically include the CSRF token as a hidden input. +The following example places the `CsrfToken` on the default attribute name (`_csrf`) used by Spring Security's <> to automatically include the CSRF token as a hidden input: .`CsrfToken` as `@ModelAttribute` ==== @@ -155,8 +152,8 @@ Fortunately, Thymeleaf provides <> t [[webflux-csrf-include-form]] ==== Form URL Encoded -In order to post an HTML form the CSRF token must be included in the form as a hidden input. -For example, the rendered HTML might look like: +To post an HTML form, the CSRF token must be included in the form as a hidden input. +The following example shows what the rendered HTML might look like: .CSRF Token HTML ==== @@ -168,22 +165,22 @@ For example, the rendered HTML might look like: ---- ==== -Next we will discuss various ways of including the CSRF token in a form as a hidden input. +Next, we discuss various ways of including the CSRF token in a form as a hidden input. [[webflux-csrf-include-form-auto]] ===== Automatic CSRF Token Inclusion -Spring Security's CSRF support provides integration with Spring's https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/reactive/result/view/RequestDataValueProcessor.html[RequestDataValueProcessor] via its https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/web/reactive/result/view/CsrfRequestDataValueProcessor.html[CsrfRequestDataValueProcessor]. -In order for `CsrfRequestDataValueProcessor` to work, the `Mono` must be subscribed to and the `CsrfToken` must be <> that matches https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/web/reactive/result/view/CsrfRequestDataValueProcessor.html#DEFAULT_CSRF_ATTR_NAME[DEFAULT_CSRF_ATTR_NAME]. +Spring Security's CSRF support provides integration with Spring's https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/reactive/result/view/RequestDataValueProcessor.html[`RequestDataValueProcessor`] through its https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/web/reactive/result/view/CsrfRequestDataValueProcessor.html[`CsrfRequestDataValueProcessor`]. +For `CsrfRequestDataValueProcessor` to work, the `Mono` must be subscribed to and the `CsrfToken` must be <> that matches https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/web/reactive/result/view/CsrfRequestDataValueProcessor.html#DEFAULT_CSRF_ATTR_NAME[`DEFAULT_CSRF_ATTR_NAME`]. -Fortunately, Thymeleaf https://www.thymeleaf.org/doc/tutorials/2.1/thymeleafspring.html#integration-with-requestdatavalueprocessor[provides support] to take care of all the boilerplate for you by integrating with `RequestDataValueProcessor` to ensure that forms that have an unsafe HTTP method (i.e. post) will automatically include the actual CSRF token. +Fortunately, Thymeleaf https://www.thymeleaf.org/doc/tutorials/2.1/thymeleafspring.html#integration-with-requestdatavalueprocessor[takes care of all the boilerplate] for you by integrating with `RequestDataValueProcessor` to ensure that forms that have an unsafe HTTP method (POST) automatically include the actual CSRF token. [[webflux-csrf-include-form-attr]] ===== CsrfToken Request Attribute If the <> for including the actual CSRF token in the request do not work, you can take advantage of the fact that the `Mono` <> as a `ServerWebExchange` attribute named `org.springframework.security.web.server.csrf.CsrfToken`. -The Thymeleaf sample below assumes that you <> the `CsrfToken` on an attribute named `_csrf`. +The following Thymeleaf sample assumes that you <> the `CsrfToken` on an attribute named `_csrf`: .CSRF Token in Form with Request Attribute ==== @@ -202,19 +199,19 @@ The Thymeleaf sample below assumes that you <> to store the expected CSRF token in a cookie. -By storing the expected CSRF in a cookie, JavaScript frameworks like https://docs.angularjs.org/api/ng/service/$http#cross-site-request-forgery-xsrf-protection[AngularJS] will automatically include the actual CSRF token in the HTTP request headers. +You can <> Spring Security to store the expected CSRF token in a cookie. +By storing the expected CSRF in a cookie, JavaScript frameworks, such as https://docs.angularjs.org/api/ng/service/$http#cross-site-request-forgery-xsrf-protection[AngularJS], automatically include the actual CSRF token in the HTTP request headers. [[webflux-csrf-include-ajax-meta]] -===== Meta tags +===== Meta Tags An alternative pattern to <> is to include the CSRF token within your `meta` tags. The HTML might look something like this: @@ -233,8 +230,8 @@ The HTML might look something like this: ---- ==== -Once the meta tags contained the CSRF token, the JavaScript code would read the meta tags and include the CSRF token as a header. -If you were using jQuery, this could be done with the following: +Once the meta tags contain the CSRF token, the JavaScript code can read the meta tags and include the CSRF token as a header. +If you use jQuery, you could read the meta tags with the following code: .AJAX send CSRF Token ==== @@ -250,8 +247,8 @@ $(function () { ---- ==== -The sample below assumes that you <> the `CsrfToken` on an attribute named `_csrf`. -An example of doing this with Thymeleaf is shown below: +The following sample assumes that you <> the `CsrfToken` on an attribute named `_csrf`. +The following example does this with Thymeleaf: .CSRF meta tag JSP ==== @@ -272,28 +269,28 @@ An example of doing this with Thymeleaf is shown below: == CSRF Considerations There are a few special considerations to consider when implementing protection against CSRF attacks. This section discusses those considerations as it pertains to WebFlux environments. -Refer to <> for a more general discussion. +See <> for a more general discussion. [[webflux-considerations-csrf-login]] === Logging In -It is important to <> requests to protect against forging log in attempts. -Spring Security's WebFlux support does this out of the box. +You should <> requests to protect against forged login attempts. +Spring Security's WebFlux support automatically does this. [[webflux-considerations-csrf-logout]] === Logging Out -It is important to <> requests to protect against forging log out attempts. -By default Spring Security's `LogoutWebFilter` only processes HTTP post requests. -This ensures that log out requires a CSRF token and that a malicious user cannot forcibly log out your users. +You should <> requests to protect against forging logout attempts. +By default, Spring Security's `LogoutWebFilter` processes only HTTP post requests. +This ensures that logout requires a CSRF token and that a malicious user cannot forcibly log out your users. The easiest approach is to use a form to log out. -If you really want a link, you can use JavaScript to have the link perform a POST (i.e. maybe on a hidden form). -For browsers with JavaScript that is disabled, you can optionally have the link take the user to a log out confirmation page that will perform the POST. +If you really want a link, you can use JavaScript to have the link perform a POST (maybe on a hidden form). +For browsers with JavaScript that is disabled, you can optionally have the link take the user to a logout confirmation page that performs the POST. -If you really want to use HTTP GET with logout you can do so, but remember this is generally not recommended. -For example, the following Java Configuration will perform logout with the URL `/logout` is requested with any HTTP method: +If you really want to use HTTP GET with logout, you can do so, but remember that doing so is generally not recommended. +For example, the following Java Configuration logs out when the `/logout` URL is requested with any HTTP method: // FIXME: This should be a link to log out documentation @@ -330,16 +327,16 @@ fun springSecurityFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain [[webflux-considerations-csrf-timeouts]] === CSRF and Session Timeouts -By default Spring Security stores the CSRF token in the `WebSession`. -This can lead to a situation where the session expires which means there is not an expected CSRF token to validate against. +By default, Spring Security stores the CSRF token in the `WebSession`. +This arrangement can lead to a situation where the session expires, which means that there is not an expected CSRF token to validate against. -We've already discussed <> to session timeouts. +We have already discussed <> to session timeouts. This section discusses the specifics of CSRF timeouts as it pertains to the WebFlux support. -It is simple to change storage of the expected CSRF token to be in a cookie. -For details, refer to the <> section. +You can change storage of the expected CSRF token to be in a cookie. +For details, see the <> section. -// FIXME: We should add a custom AccessDeniedHandler section in the reference and update the links above +// FIXME: We should add a custom AccessDeniedHandler section in the reference and update the earlier links // FIXME: We need a WebFlux multipart body vs action story. WebFlux always has multipart enabled. [[webflux-csrf-considerations-multipart]] @@ -347,17 +344,14 @@ For details, refer to the <> section. We have <> how protecting multipart requests (file uploads) from CSRF attacks causes a https://en.wikipedia.org/wiki/Chicken_or_the_egg[chicken and the egg] problem. This section discusses how to implement placing the CSRF token in the <> and <> within a WebFlux application. -[NOTE] -==== -More information about using multipart forms with Spring can be found within the https://docs.spring.io/spring/docs/5.2.x/spring-framework-reference/web-reactive.html#webflux-multipart[Multipart Data] section of the Spring reference. -==== +NOTE: For more information about using multipart forms with Spring, see the https://docs.spring.io/spring/docs/5.2.x/spring-framework-reference/web-reactive.html#webflux-multipart[Multipart Data] section of the Spring reference. [[webflux-csrf-considerations-multipart-body]] ==== Place CSRF Token in the Body We have <> the trade-offs of placing the CSRF token in the body. -In a WebFlux application, this can be configured with the following configuration: +In a WebFlux application, you can do so with the following configuration: .Enable obtaining CSRF token from multipart/form-data ==== @@ -393,7 +387,7 @@ fun springSecurityFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain We have <> the trade-offs of placing the CSRF token in the URL. Since the `CsrfToken` is exposed as an `ServerHttpRequest` <>, we can use that to create an `action` with the CSRF token in it. -An example with Thymeleaf is shown below: +The following example uses Thymeleaf: .CSRF Token in Action ==== @@ -409,4 +403,5 @@ An example with Thymeleaf is shown below: === HiddenHttpMethodFilter We have <> overriding the HTTP method. -In a Spring WebFlux application, overriding the HTTP method is done using https://docs.spring.io/spring-framework/docs/5.2.x/javadoc-api/org/springframework/web/filter/reactive/HiddenHttpMethodFilter.html[HiddenHttpMethodFilter]. +In a Spring WebFlux application, overriding the HTTP method is done by using https://docs.spring.io/spring-framework/docs/5.2.x/javadoc-api/org/springframework/web/filter/reactive/HiddenHttpMethodFilter.html[`HiddenHttpMethodFilter`]. +// FIXME: Add an example. diff --git a/docs/manual/src/docs/asciidoc/_includes/reactive/exploits/headers.adoc b/docs/manual/src/docs/asciidoc/_includes/reactive/exploits/headers.adoc index 2ee82ad2a65..64b86ebda10 100644 --- a/docs/manual/src/docs/asciidoc/_includes/reactive/exploits/headers.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/reactive/exploits/headers.adoc @@ -1,19 +1,19 @@ [[webflux-headers]] = Security HTTP Response Headers -<> can be used to increase the security of web applications. -This section is dedicated to WebFlux based support for Security HTTP Response Headers. +You can use <> to increase the security of web applications. +This section is dedicated to WebFlux-based support for Security HTTP Response Headers. [[webflux-headers-default]] == Default Security Headers Spring Security provides a <> to provide secure defaults. -While each of these headers are considered best practice, it should be noted that not all clients utilize the headers, so additional testing is encouraged. +While each of these headers are considered best practice, it should be noted that not all clients use the headers, so additional testing is encouraged. You can customize specific headers. -For example, assume that you want the defaults except you wish to specify `SAMEORIGIN` for <>. +For example, assume that you want the defaults but you wish to specify `SAMEORIGIN` for <>. -You can easily do this with the following Configuration: +You can do so with the following configuration: .Customize Default Security Headers ==== @@ -50,8 +50,7 @@ fun webFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain { ---- ==== -If you do not want the defaults to be added and want explicit control over what should be used, you can disable the defaults. -An example is provided below: +If you do not want the defaults to be added and want explicit control over what should be used, you can disable the defaults: .Disable HTTP Security Response Headers ==== @@ -85,13 +84,13 @@ fun webFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain { [[webflux-headers-cache-control]] == Cache Control -Spring Security includes <> headers by default. +Spring Security includes <> headers by default. -However, if you actually want to cache specific responses, your application can selectively add them to the https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/http/server/reactive/ServerHttpResponse.html[ServerHttpResponse] to override the header set by Spring Security. -This is useful to ensure things like CSS, JavaScript, and images are properly cached. +However, if you actually want to cache specific responses, your application can selectively add them to the https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/http/server/reactive/ServerHttpResponse.html[`ServerHttpResponse`] to override the header set by Spring Security. +This is useful to ensure that such things as CSS, JavaScript, and images are properly cached. -When using Spring WebFluxZz, this is typically done within your configuration. -Details on how to do this can be found in the https://docs.spring.io/spring/docs/5.0.0.RELEASE/spring-framework-reference/web-reactive.html#webflux-config-static-resources[Static Resources] portion of the Spring Reference documentation +When using Spring WebFlux, you typically do so within your configuration. +You can find details on how to do so in the https://docs.spring.io/spring/docs/5.0.0.RELEASE/spring-framework-reference/web-reactive.html#webflux-config-static-resources[Static Resources] portion of the Spring Reference documentation If necessary, you can also disable Spring Security's cache control HTTP response headers. @@ -131,8 +130,8 @@ fun webFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain { [[webflux-headers-content-type-options]] == Content Type Options -Spring Security includes <> headers by default. -However, you can disable it with: +By default, Spring Security includes <> headers. +However, you can disable it: .Content Type Options Disabled ==== @@ -169,9 +168,9 @@ fun webFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain { [[webflux-headers-hsts]] == HTTP Strict Transport Security (HSTS) -Spring Security provides the <> header by default. +By default, Spring Security provides the <> header. However, you can customize the results explicitly. -For example, the following is an example of explicitly providing HSTS: +For example, the following example explicitly provides HSTS: .Strict Transport Security ==== @@ -214,9 +213,9 @@ fun webFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain { [[webflux-headers-frame-options]] == X-Frame-Options -By default, Spring Security disables rendering within an iframe using <>. +By default, Spring Security disables rendering within an iframe by using <>. -You can customize frame options to use the same origin using the following: +You can customize frame options to use the same origin: .X-Frame-Options: SAMEORIGIN ==== @@ -255,8 +254,8 @@ fun webFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain { [[webflux-headers-xss-protection]] == X-XSS-Protection -By default, Spring Security instructs browsers to block reflected XSS attacks using the <. -You can disable `X-XSS-Protection` with the following Configuration: +By default, Spring Security instructs browsers to block reflected XSS attacks by using the <. +You can disable `X-XSS-Protection`: .X-XSS-Protection Customization ==== @@ -293,10 +292,10 @@ fun webFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain { [[webflux-headers-csp]] == Content Security Policy (CSP) -Spring Security does not add <> by default, because a reasonable default is impossible to know without context of the application. -The web application author must declare the security policy(s) to enforce and/or monitor for the protected resources. +By default, Spring Security does not add <>, because a reasonable default is impossible to know without the context of the application. +The web application author must declare the security policies to enforce and monitor the protected resources. -For example, given the following security policy: +For example, consider the following security policy: .Content Security Policy Example ==== @@ -306,7 +305,7 @@ Content-Security-Policy: script-src 'self' https://trustedscripts.example.com; o ---- ==== -You can enable the CSP header as shown below: +Given the preceding policy, you can enable the CSP header: .Content Security Policy ==== @@ -385,8 +384,8 @@ fun webFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain { [[webflux-headers-referrer]] == Referrer Policy -Spring Security does not add <> headers by default. -You can enable the Referrer Policy header using configuration as shown below: +By default, Spring Security does not add <> headers. +You can enable the Referrer Policy header: .Referrer Policy Configuration ==== @@ -427,8 +426,8 @@ fun webFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain { [[webflux-headers-feature]] == Feature Policy -Spring Security does not add <> headers by default. -The following `Feature-Policy` header: +By default, Spring Security does not add <> headers. +Consider the following `Feature-Policy` header: .Feature-Policy Example ==== @@ -438,7 +437,7 @@ Feature-Policy: geolocation 'self' ---- ==== -You can enable the Feature Policy header as shown below: +You can enable the preceding Feature Policy header: .Feature-Policy Configuration ==== @@ -475,8 +474,8 @@ fun webFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain { [[webflux-headers-permissions]] == Permissions Policy -Spring Security does not add <> headers by default. -The following `Permissions-Policy` header: +By default, Spring Security does not add <> headers. +Consider the following `Permissions-Policy` header: .Permissions-Policy Example ==== @@ -486,7 +485,7 @@ Permissions-Policy: geolocation=(self) ---- ==== -You can enable the Permissions Policy header as shown below: +You can enable the preceding Permissions Policy header: .Permissions-Policy Configuration ==== @@ -527,8 +526,8 @@ fun webFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain { [[webflux-headers-clear-site-data]] == Clear Site Data -Spring Security does not add <> headers by default. -The following Clear-Site-Data header: +By default, Spring Security does not add <> headers. +Consider the following `Clear-Site-Data` header: .Clear-Site-Data Example ==== @@ -537,7 +536,7 @@ Clear-Site-Data: "cache", "cookies" ---- ==== -can be sent on log out with the following configuration: +You can send the `Clear-Site-Data` header on logout: .Clear-Site-Data Configuration ==== diff --git a/docs/manual/src/docs/asciidoc/_includes/reactive/exploits/http.adoc b/docs/manual/src/docs/asciidoc/_includes/reactive/exploits/http.adoc index 387a05a7192..3022716e87f 100644 --- a/docs/manual/src/docs/asciidoc/_includes/reactive/exploits/http.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/reactive/exploits/http.adoc @@ -1,16 +1,16 @@ [[webflux-http]] = HTTP -All HTTP based communication should be protected <>. +All HTTP-based communication should be protected with <>. -Below you can find details around WebFlux specific features that assist with HTTPS usage. +This section covers details about using WebFlux-specific features that assist with HTTPS usage. [[webflux-http-redirect]] == Redirect to HTTPS -If a client makes a request using HTTP rather than HTTPS, Spring Security can be configured to redirect to HTTPS. +If a client makes a request using HTTP rather than HTTPS, you can configure Spring Security to redirect to HTTPS. -For example, the following Java configuration will redirect any HTTP requests to HTTPS: +The following Java configuration redirects any HTTP requests to HTTPS: .Redirect to HTTPS ==== @@ -39,9 +39,9 @@ fun springSecurityFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain ---- ==== -The configuration can easily be wrapped around an if statement to only be turned on in production. -Alternatively, it can be enabled by looking for a property about the request that only happens in production. -For example, if the production environment adds a header named `X-Forwarded-Proto` the following Java Configuration could be used: +You can wrap the configuration can be wrapped around an `if` statement to be turned on only in production. +Alternatively, you can enable it by looking for a property about the request that happens only in production. +For example, if the production environment adds a header named `X-Forwarded-Proto`, you should use the following Java Configuration: .Redirect to HTTPS when X-Forwarded ==== diff --git a/docs/manual/src/docs/asciidoc/_includes/reactive/method.adoc b/docs/manual/src/docs/asciidoc/_includes/reactive/method.adoc index 08e8ba2fa78..f2f60c3caaf 100644 --- a/docs/manual/src/docs/asciidoc/_includes/reactive/method.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/reactive/method.adoc @@ -1,14 +1,13 @@ [[jc-erms]] = EnableReactiveMethodSecurity -Spring Security supports method security using https://projectreactor.io/docs/core/release/reference/#context[Reactor's Context] which is setup using `ReactiveSecurityContextHolder`. -For example, this demonstrates how to retrieve the currently logged in user's message. +Spring Security supports method security by using https://projectreactor.io/docs/core/release/reference/#context[Reactor's Context], which is set up by `ReactiveSecurityContextHolder`. +The following example shows how to retrieve the currently logged in user's message: [NOTE] ==== For this to work the return type of the method must be a `org.reactivestreams.Publisher` (i.e. `Mono`/`Flux`) or the function must be a Kotlin coroutine function. This is necessary to integrate with Reactor's `Context`. -==== ==== .Java @@ -27,6 +26,7 @@ StepVerifier.create(messageByUsername) .expectNext("Hi user") .verifyComplete(); ---- +==== .Kotlin [source,kotlin,role="secondary"] @@ -55,6 +55,7 @@ Mono findMessageByUsername(String username) { return Mono.just("Hi " + username); } ---- +==== .Kotlin [source,kotlin,role="secondary"] @@ -88,6 +89,7 @@ public class SecurityConfig { } } ---- +==== .Kotlin [source,kotlin,role="secondary"] @@ -125,6 +127,7 @@ public class HelloWorldMessageService { } } ---- +==== .Kotlin [source,kotlin,role="secondary"] @@ -162,7 +165,7 @@ It is important to note that any of the expressions in standard method security However, at this time we only support return type of `Boolean` or `boolean` of the expression. This means that the expression must not block. -When integrating with <>, the Reactor Context is automatically established by Spring Security according to the authenticated user. +When integrating with <>, the Reactor Context is automatically established by Spring Security according to the authenticated user: ==== .Java @@ -198,8 +201,8 @@ public class SecurityConfig { return new MapReactiveUserDetailsService(rob, admin); } } - ---- +==== .Kotlin [source,kotlin,role="secondary"] diff --git a/docs/manual/src/docs/asciidoc/_includes/reactive/oauth2/access-token.adoc b/docs/manual/src/docs/asciidoc/_includes/reactive/oauth2/access-token.adoc index ac732704a22..9c1fc38adf3 100644 --- a/docs/manual/src/docs/asciidoc/_includes/reactive/oauth2/access-token.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/reactive/oauth2/access-token.adoc @@ -2,8 +2,9 @@ = OAuth2 Client Spring Security's OAuth Support allows obtaining an access token without authenticating. -A basic configuration with Spring Boot can be seen below: +The following example shows basic configuration with Spring Boot: +==== [source,yml] ---- spring: @@ -16,10 +17,11 @@ spring: client-secret: replace-with-client-secret scope: read:user,public_repo ---- +==== -You will need to replace the `client-id` and `client-secret` with values registered with GitHub. +You need to replace the `client-id` and `client-secret` with values registered with GitHub. -The next step is to instruct Spring Security that you wish to act as an OAuth2 Client so that you can obtain an access token. +The next step is to instruct Spring Security that you wish to act as an OAuth2 Client so that you can obtain an access token: .OAuth2 Client ==== @@ -35,7 +37,6 @@ SecurityWebFilterChain configure(ServerHttpSecurity http) throws Exception { } ---- - .Kotlin [source,kotlin,role="secondary"] ---- @@ -49,4 +50,4 @@ fun webFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain { ---- ==== -You can now leverage Spring Security's <> or <> support to obtain and use the access token. +You can now use Spring Security's <> or <> support to obtain and use the access token. diff --git a/docs/manual/src/docs/asciidoc/_includes/reactive/oauth2/login.adoc b/docs/manual/src/docs/asciidoc/_includes/reactive/oauth2/login.adoc index 5883986d8ab..71c262889d8 100644 --- a/docs/manual/src/docs/asciidoc/_includes/reactive/oauth2/login.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/reactive/oauth2/login.adoc @@ -1,9 +1,9 @@ [[webflux-oauth2-login]] = OAuth 2.0 Login -The OAuth 2.0 Login feature provides an application with the capability to have users log in to the application by using their existing account at an OAuth 2.0 Provider (e.g. +The OAuth 2.0 Login feature provides an application with the ability to have users log in to the application by using their existing account at an OAuth 2.0 Provider (such as GitHub) or OpenID Connect 1.0 Provider (such as Google). -OAuth 2.0 Login implements the use cases: "Login with Google" or "Login with GitHub". +OAuth 2.0 Login implements the "Login with Google" or "Login with GitHub" use cases. NOTE: OAuth 2.0 Login is implemented by using the *Authorization Code Grant*, as specified in the https://tools.ietf.org/html/rfc6749#section-4.1[OAuth 2.0 Authorization Framework] and https://openid.net/specs/openid-connect-core-1_0.html#CodeFlowAuth[OpenID Connect Core 1.0]. @@ -12,38 +12,38 @@ NOTE: OAuth 2.0 Login is implemented by using the *Authorization Code Grant*, as Spring Boot 2.0 brings full auto-configuration capabilities for OAuth 2.0 Login. -This section shows how to configure the {gh-samples-url}/boot/oauth2login-webflux[*OAuth 2.0 Login WebFlux sample*] using _Google_ as the _Authentication Provider_ and covers the following topics: +This section shows how to configure the {gh-samples-url}/boot/oauth2login-webflux[*OAuth 2.0 Login WebFlux sample*] by using _Google_ as the _Authentication Provider_ and covers the following topics: -* <> -* <> -* <> -* <> +* <> +* <> +* <> +* <> [[webflux-oauth2-login-sample-setup]] -=== Initial setup +=== Initial Setup To use Google's OAuth 2.0 authentication system for login, you must set up a project in the Google API Console to obtain OAuth 2.0 credentials. NOTE: https://developers.google.com/identity/protocols/OpenIDConnect[Google's OAuth 2.0 implementation] for authentication conforms to the https://openid.net/connect/[OpenID Connect 1.0] specification and is https://openid.net/certification/[OpenID Certified]. -Follow the instructions on the https://developers.google.com/identity/protocols/OpenIDConnect[OpenID Connect] page, starting in the section, "Setting up OAuth 2.0". +Follow the instructions on the https://developers.google.com/identity/protocols/OpenIDConnect[OpenID Connect] page, starting in the "`Setting up OAuth 2.0`" section. -After completing the "Obtain OAuth 2.0 credentials" instructions, you should have a new OAuth Client with credentials consisting of a Client ID and a Client Secret. +After completing the "`Obtain OAuth 2.0 credentials`" instructions, you should have a new OAuth Client with credentials that consist of a Client ID and a Client Secret. [[webflux-oauth2-login-sample-redirect]] -=== Setting the redirect URI +=== Setting the Redirect URI -The redirect URI is the path in the application that the end-user's user-agent is redirected back to after they have authenticated with Google and have granted access to the OAuth Client _(<>)_ on the Consent page. +The redirect URI is the path in the application that the end-user's user-agent is redirected back to after they have authenticated with Google and have been granted access to the OAuth Client (<>) on the consent page. -In the "Set a redirect URI" sub-section, ensure that the *Authorized redirect URIs* field is set to `http://localhost:8080/login/oauth2/code/google`. +In the "`Set a redirect URI`" sub-section, ensure that the *Authorized redirect URIs* field is set to `http://localhost:8080/login/oauth2/code/google`. TIP: The default redirect URI template is `+{baseUrl}/login/oauth2/code/{registrationId}+`. The *_registrationId_* is a unique identifier for the <>. For our example, the `registrationId` is `google`. -IMPORTANT: If the OAuth Client is running behind a proxy server, it is recommended to check <> to ensure the application is correctly configured. -Also, see the supported <> for `redirect-uri`. +IMPORTANT: If the OAuth Client runs behind a proxy server, we recommend checking the <> to ensure the application is correctly configured. +Also, see the supported <> for the `redirect-uri`. [[webflux-oauth2-login-sample-config]] === Configure `application.yml` @@ -53,6 +53,8 @@ To do so: . Go to `application.yml` and set the following configuration: + +.OAuth Client properties +==== [source,yaml] ---- spring: @@ -65,8 +67,6 @@ spring: client-secret: google-client-secret ---- + -.OAuth Client properties -==== <1> `spring.security.oauth2.client.registration` is the base property prefix for OAuth Client properties. <2> Following the base property prefix is the ID for the <>, such as google. ==== @@ -75,7 +75,7 @@ spring: [[webflux-oauth2-login-sample-start]] -=== Boot up the application +=== Boot the Application Launch the Spring Boot 2.0 sample and go to `http://localhost:8080`. You are then redirected to the default _auto-generated_ login page, which displays a link for Google. @@ -92,7 +92,7 @@ At this point, the OAuth Client retrieves your email address and basic profile i == Using OpenID Provider Configuration For well known providers, Spring Security provides the necessary defaults for the OAuth Authorization Provider's configuration. -If you are working with your own Authorization Provider that supports https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfig[OpenID Provider Configuration] or https://tools.ietf.org/html/rfc8414#section-3[Authorization Server Metadata], the https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfigurationResponse[OpenID Provider Configuration Response]'s `issuer-uri` can be used to configure the application. +If you are working with your own Authorization Provider that supports https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfig[OpenID Provider Configuration] or https://tools.ietf.org/html/rfc8414#section-3[Authorization Server Metadata], you can use the https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfigurationResponse[OpenID Provider Configuration Response]'s `issuer-uri` to configure the application. [source,yml] ---- @@ -109,10 +109,9 @@ spring: client-secret: 6cea952f-10d0-4d00-ac79-cc865820dc2c ---- -The `issuer-uri` instructs Spring Security to query in series the endpoints `https://idp.example.com/auth/realms/demo/.well-known/openid-configuration`, `https://idp.example.com/.well-known/openid-configuration/auth/realms/demo`, or `https://idp.example.com/.well-known/oauth-authorization-server/auth/realms/demo` to discover the configuration. +The `issuer-uri` instructs Spring Security to query, in series, the following endpoints to discover the configuration: `https://idp.example.com/auth/realms/demo/.well-known/openid-configuration`, `https://idp.example.com/.well-known/openid-configuration/auth/realms/demo`, or `https://idp.example.com/.well-known/oauth-authorization-server/auth/realms/demo`. -[NOTE] -Spring Security will query the endpoints one at a time, stopping at the first that gives a 200 response. +NOTE: Spring Security queries the endpoints one at a time, stopping at the first that gives a 200 response. The `client-id` and `client-secret` are linked to the provider because `keycloak` is used for both the provider and the registration. @@ -120,7 +119,7 @@ The `client-id` and `client-secret` are linked to the provider because `keycloak [[webflux-oauth2-login-explicit]] == Explicit OAuth2 Login Configuration -A minimal OAuth2 Login configuration is shown below: +The following listing shows a minimal OAuth2 Login configuration: .Minimal OAuth2 Login ==== @@ -168,7 +167,7 @@ fun webFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain { ---- ==== -Additional configuration options can be seen below: +The following example shows additional configuration options: .Advanced OAuth2 Login ==== @@ -206,7 +205,7 @@ fun webFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain { ---- ==== -You may register a `GrantedAuthoritiesMapper` `@Bean` to have it automatically applied to the default configuration, as shown in the following example: +You can register a `GrantedAuthoritiesMapper` `@Bean` to have it be automatically applied to the default configuration: .GrantedAuthoritiesMapper Bean ==== diff --git a/docs/manual/src/docs/asciidoc/_includes/reactive/oauth2/resource-server.adoc b/docs/manual/src/docs/asciidoc/_includes/reactive/oauth2/resource-server.adoc index 65c37bfe95c..b16fcbe0106 100644 --- a/docs/manual/src/docs/asciidoc/_includes/reactive/oauth2/resource-server.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/reactive/oauth2/resource-server.adoc @@ -1,35 +1,33 @@ [[webflux-oauth2-resource-server]] = OAuth 2.0 Resource Server -Spring Security supports protecting endpoints using two forms of OAuth 2.0 https://tools.ietf.org/html/rfc6750.html[Bearer Tokens]: +Spring Security supports protecting endpoints by offering two forms of OAuth 2.0 https://tools.ietf.org/html/rfc6750.html[Bearer Tokens]: * https://tools.ietf.org/html/rfc7519[JWT] * Opaque Tokens This is handy in circumstances where an application has delegated its authority management to an https://tools.ietf.org/html/rfc6749[authorization server] (for example, Okta or Ping Identity). -This authorization server can be consulted by resource servers to authorize requests. +Resource serves can consult this authorization server to authorize requests. -[NOTE] -==== -A complete working example for {gh-samples-url}/boot/oauth2resourceserver-webflux[*JWTs*] is available in the {gh-samples-url}[Spring Security repository]. -==== +NOTE: A complete working example for {gh-samples-url}/boot/oauth2resourceserver-webflux[JWT] is available in the {gh-samples-url}[Spring Security repository]. [[webflux-oauth2resourceserver-jwt-minimaldependencies]] == Minimal Dependencies for JWT Most Resource Server support is collected into `spring-security-oauth2-resource-server`. -However, the support for decoding and verifying JWTs is in `spring-security-oauth2-jose`, meaning that both are necessary in order to have a working resource server that supports JWT-encoded Bearer Tokens. +However, the support for decoding and verifying JWTs is in `spring-security-oauth2-jose`, meaning that both are necessary to have a working resource server that supports JWT-encoded Bearer Tokens. [[webflux-oauth2resourceserver-jwt-minimalconfiguration]] == Minimal Configuration for JWTs When using https://spring.io/projects/spring-boot[Spring Boot], configuring an application as a resource server consists of two basic steps. -First, include the needed dependencies and second, indicate the location of the authorization server. +First, include the needed dependencies. Second, indicate the location of the authorization server. === Specifying the Authorization Server -In a Spring Boot application, to specify which authorization server to use, simply do: +In a Spring Boot application, you need to specify which authorization server to use: +==== [source,yml] ---- spring: @@ -39,65 +37,63 @@ spring: jwt: issuer-uri: https://idp.example.com/issuer ---- +==== -Where `https://idp.example.com/issuer` is the value contained in the `iss` claim for JWT tokens that the authorization server will issue. -Resource Server will use this property to further self-configure, discover the authorization server's public keys, and subsequently validate incoming JWTs. +Where `https://idp.example.com/issuer` is the value contained in the `iss` claim for JWT tokens that the authorization server issues. +This resource server uses this property to further self-configure, discover the authorization server's public keys, and subsequently validate incoming JWTs. -[NOTE] -To use the `issuer-uri` property, it must also be true that one of `https://idp.example.com/issuer/.well-known/openid-configuration`, `https://idp.example.com/.well-known/openid-configuration/issuer`, or `https://idp.example.com/.well-known/oauth-authorization-server/issuer` is a supported endpoint for the authorization server. +NOTE: To use the `issuer-uri` property, it must also be true that one of `https://idp.example.com/issuer/.well-known/openid-configuration`, `https://idp.example.com/.well-known/openid-configuration/issuer`, or `https://idp.example.com/.well-known/oauth-authorization-server/issuer` is a supported endpoint for the authorization server. This endpoint is referred to as a https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfig[Provider Configuration] endpoint or a https://tools.ietf.org/html/rfc8414#section-3[Authorization Server Metadata] endpoint. -And that's it! - === Startup Expectations -When this property and these dependencies are used, Resource Server will automatically configure itself to validate JWT-encoded Bearer Tokens. +When this property and these dependencies are used, Resource Server automatically configures itself to validate JWT-encoded Bearer Tokens. It achieves this through a deterministic startup process: -1. Hit the Provider Configuration or Authorization Server Metadata endpoint, processing the response for the `jwks_url` property -2. Configure the validation strategy to query `jwks_url` for valid public keys -3. Configure the validation strategy to validate each JWTs `iss` claim against `https://idp.example.com`. +. Hit the Provider Configuration or Authorization Server Metadata endpoint, processing the response for the `jwks_url` property. +. Configure the validation strategy to query `jwks_url` for valid public keys. +. Configure the validation strategy to validate each JWT's `iss` claim against `https://idp.example.com`. -A consequence of this process is that the authorization server must be up and receiving requests in order for Resource Server to successfully start up. +A consequence of this process is that the authorization server must be receiving requests in order for Resource Server to successfully start up. -[NOTE] -If the authorization server is down when Resource Server queries it (given appropriate timeouts), then startup will fail. +NOTE: If the authorization server is down when Resource Server queries it (given appropriate timeouts), then startup fails. === Runtime Expectations -Once the application is started up, Resource Server will attempt to process any request containing an `Authorization: Bearer` header: +Once the application is started up, Resource Server tries to process any request that contains an `Authorization: Bearer` header: +==== [source,html] ---- GET / HTTP/1.1 Authorization: Bearer some-token-value # Resource Server will process this ---- +==== -So long as this scheme is indicated, Resource Server will attempt to process the request according to the Bearer Token specification. +So long as this scheme is indicated, Resource Server tries to process the request according to the Bearer Token specification. -Given a well-formed JWT, Resource Server will: +Given a well-formed JWT, Resource Server: -1. Validate its signature against a public key obtained from the `jwks_url` endpoint during startup and matched against the JWTs header -2. Validate the JWTs `exp` and `nbf` timestamps and the JWTs `iss` claim, and -3. Map each scope to an authority with the prefix `SCOPE_`. +1. Validates its signature against a public key obtained from the `jwks_url` endpoint during startup and matched against the JWTs header. +2. Validates the JWTs `exp` and `nbf` timestamps and the JWTs `iss` claim. +3. Maps each scope to an authority with the prefix `SCOPE_`. -[NOTE] -As the authorization server makes available new keys, Spring Security will automatically rotate the keys used to validate the JWT tokens. +NOTE: As the authorization server makes available new keys, Spring Security automatically rotates the keys used to validate the JWT tokens. -The resulting `Authentication#getPrincipal`, by default, is a Spring Security `Jwt` object, and `Authentication#getName` maps to the JWT's `sub` property, if one is present. +By default, the resulting `Authentication#getPrincipal` is a Spring Security `Jwt` object, and `Authentication#getName` maps to the JWT's `sub` property, if one is present. From here, consider jumping to: -<> - -<> +* <> +* <> [[webflux-oauth2resourceserver-jwt-jwkseturi]] === Specifying the Authorization Server JWK Set Uri Directly -If the authorization server doesn't support any configuration endpoints, or if Resource Server must be able to start up independently from the authorization server, then the `jwk-set-uri` can be supplied as well: +If the authorization server does not support any configuration endpoints, or if Resource Server must be able to start up independently from the authorization server, you can supply `jwk-set-uri` as well: +==== [source,yaml] ---- spring: @@ -108,22 +104,21 @@ spring: issuer-uri: https://idp.example.com jwk-set-uri: https://idp.example.com/.well-known/jwks.json ---- +==== -[NOTE] -The JWK Set uri is not standardized, but can typically be found in the authorization server's documentation +NOTE: The JWK Set uri is not standardized, but you can typically find it in the authorization server's documentation. -Consequently, Resource Server will not ping the authorization server at startup. +Consequently, Resource Server does not ping the authorization server at startup. We still specify the `issuer-uri` so that Resource Server still validates the `iss` claim on incoming JWTs. -[NOTE] -This property can also be supplied directly on the <>. +NOTE: You can supply this property directly on the <>. [[webflux-oauth2resourceserver-jwt-sansboot]] === Overriding or Replacing Boot Auto Configuration -There are two `@Bean` s that Spring Boot generates on Resource Server's behalf. +Spring Boot generates two `@Bean` objects on Resource Server's behalf. -The first is a `SecurityWebFilterChain` that configures the app as a resource server. When including `spring-security-oauth2-jose`, this `SecurityWebFilterChain` looks like: +The first bean is a `SecurityWebFilterChain` that configures the application as a resource server. When including `spring-security-oauth2-jose`, this `SecurityWebFilterChain` looks like: .Resource Server SecurityWebFilterChain ==== @@ -158,9 +153,9 @@ fun springSecurityFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain ---- ==== -If the application doesn't expose a `SecurityWebFilterChain` bean, then Spring Boot will expose the above default one. +If the application does not expose a `SecurityWebFilterChain` bean, Spring Boot exposes the default one (shown in the preceding listing). -Replacing this is as simple as exposing the bean within the application: +To replace it, expose the `@Bean` within the application: .Replacing SecurityWebFilterChain ==== @@ -199,9 +194,9 @@ fun springSecurityFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain ---- ==== -The above requires the scope of `message:read` for any URL that starts with `/messages/`. +The preceding configuration requires the scope of `message:read` for any URL that starts with `/messages/`. -Methods on the `oauth2ResourceServer` DSL will also override or replace auto configuration. +Methods on the `oauth2ResourceServer` DSL also override or replace auto configuration. For example, the second `@Bean` Spring Boot creates is a `ReactiveJwtDecoder`, which decodes `String` tokens into validated instances of `Jwt`: @@ -226,16 +221,15 @@ fun jwtDecoder(): ReactiveJwtDecoder { ---- ==== -[NOTE] -Calling `{security-api-url}org/springframework/security/oauth2/jwt/ReactiveJwtDecoders.html#fromIssuerLocation-java.lang.String-[ReactiveJwtDecoders#fromIssuerLocation]` is what invokes the Provider Configuration or Authorization Server Metadata endpoint in order to derive the JWK Set Uri. -If the application doesn't expose a `ReactiveJwtDecoder` bean, then Spring Boot will expose the above default one. +NOTE: Calling `{security-api-url}org/springframework/security/oauth2/jwt/ReactiveJwtDecoders.html#fromIssuerLocation-java.lang.String-[ReactiveJwtDecoders#fromIssuerLocation]` invokes the Provider Configuration or Authorization Server Metadata endpoint to derive the JWK Set URI. +If the application does not expose a `ReactiveJwtDecoder` bean, Spring Boot exposes the above default one. -And its configuration can be overridden using `jwkSetUri()` or replaced using `decoder()`. +Its configuration can be overridden by using `jwkSetUri()` or replaced by using `decoder()`. [[webflux-oauth2resourceserver-jwt-jwkseturi-dsl]] ==== Using `jwkSetUri()` -An authorization server's JWK Set Uri can be configured <> or it can be supplied in the DSL: +You can configure an authorization server's JWK Set URI <> or supply it in the DSL: ==== .Java @@ -280,7 +274,7 @@ Using `jwkSetUri()` takes precedence over any configuration property. [[webflux-oauth2resourceserver-jwt-decoder-dsl]] ==== Using `decoder()` -More powerful than `jwkSetUri()` is `decoder()`, which will completely replace any Boot auto configuration of `JwtDecoder`: +`decoder()` is more powerful than `jwkSetUri()`, because it completely replaces any Spring Boot auto-configuration of `JwtDecoder`: ==== .Java @@ -320,12 +314,12 @@ fun springSecurityFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain ---- ==== -This is handy when deeper configuration, like <>, is necessary. +This is handy when you need deeper configuration, such as <>. [[webflux-oauth2resourceserver-decoder-bean]] ==== Exposing a `ReactiveJwtDecoder` `@Bean` -Or, exposing a `ReactiveJwtDecoder` `@Bean` has the same effect as `decoder()`: +Alternately, exposing a `ReactiveJwtDecoder` `@Bean` has the same effect as `decoder()`: ==== .Java @@ -350,15 +344,16 @@ fun jwtDecoder(): ReactiveJwtDecoder { [[webflux-oauth2resourceserver-jwt-decoder-algorithm]] == Configuring Trusted Algorithms -By default, `NimbusReactiveJwtDecoder`, and hence Resource Server, will only trust and verify tokens using `RS256`. +By default, `NimbusReactiveJwtDecoder`, and hence Resource Server, trust and verify only tokens that use `RS256`. -You can customize this via <> or <>. +You can customize this behavior with <> or by using <>. [[webflux-oauth2resourceserver-jwt-boot-algorithm]] -=== Via Spring Boot +=== Customizing Trusted Algorithms with Spring Boot The simplest way to set the algorithm is as a property: +==== [source,yaml] ---- spring: @@ -369,9 +364,10 @@ spring: jws-algorithm: RS512 jwk-set-uri: https://idp.example.org/.well-known/jwks.json ---- +==== [[webflux-oauth2resourceserver-jwt-decoder-builder]] -=== Using a Builder +=== Customizing Trusted Algorithms by Using a Builder For greater power, though, we can use a builder that ships with `NimbusReactiveJwtDecoder`: @@ -397,7 +393,7 @@ fun jwtDecoder(): ReactiveJwtDecoder { ---- ==== -Calling `jwsAlgorithm` more than once will configure `NimbusReactiveJwtDecoder` to trust more than one algorithm, like so: +Calling `jwsAlgorithm` more than once configures `NimbusReactiveJwtDecoder` to trust more than one algorithm: ==== .Java @@ -421,7 +417,7 @@ fun jwtDecoder(): ReactiveJwtDecoder { ---- ==== -Or, you can call `jwsAlgorithms`: +Alternately, you can call `jwsAlgorithms`: ==== .Java @@ -456,14 +452,14 @@ fun jwtDecoder(): ReactiveJwtDecoder { === Trusting a Single Asymmetric Key Simpler than backing a Resource Server with a JWK Set endpoint is to hard-code an RSA public key. -The public key can be provided via <> or by <>. +The public key can be provided with <> or by <>. [[webflux-oauth2resourceserver-jwt-decoder-public-key-boot]] ==== Via Spring Boot -Specifying a key via Spring Boot is quite simple. -The key's location can be specified like so: +You can specify a key with Spring Boot: +==== [source,yaml] ---- spring: @@ -473,8 +469,9 @@ spring: jwt: public-key-location: classpath:my-key.pub ---- +==== -Or, to allow for a more sophisticated lookup, you can post-process the `RsaKeyConversionServicePostProcessor`: +Alternately, to allow for a more sophisticated lookup, you can post-process the `RsaKeyConversionServicePostProcessor`: .BeanFactoryPostProcessor ==== @@ -504,11 +501,14 @@ fun conversionServiceCustomizer(): BeanFactoryPostProcessor { Specify your key's location: -```yaml +==== +[source,yaml] +---- key.location: hfds://my-key.pub -``` +---- +==== -And then autowire the value: +Then autowire the value: ==== .Java @@ -529,7 +529,7 @@ val key: RSAPublicKey? = null [[webflux-oauth2resourceserver-jwt-decoder-public-key-builder]] ==== Using a Builder -To wire an `RSAPublicKey` directly, you can simply use the appropriate `NimbusReactiveJwtDecoder` builder, like so: +To wire an `RSAPublicKey` directly, use the appropriate `NimbusReactiveJwtDecoder` builder: ==== .Java @@ -554,8 +554,8 @@ fun jwtDecoder(): ReactiveJwtDecoder { [[webflux-oauth2resourceserver-jwt-decoder-secret-key]] === Trusting a Single Symmetric Key -Using a single symmetric key is also simple. -You can simply load in your `SecretKey` and use the appropriate `NimbusReactiveJwtDecoder` builder, like so: +You can also use a single symmetric key. +You can load in your `SecretKey` and use the appropriate `NimbusReactiveJwtDecoder` builder: ==== .Java @@ -580,13 +580,18 @@ fun jwtDecoder(): ReactiveJwtDecoder { [[webflux-oauth2resourceserver-jwt-authorization]] === Configuring Authorization -A JWT that is issued from an OAuth 2.0 Authorization Server will typically either have a `scope` or `scp` attribute, indicating the scopes (or authorities) it's been granted, for example: +A JWT that is issued from an OAuth 2.0 Authorization Server typically has either a `scope` or an `scp` attribute, indicating the scopes (or authorities) it has been granted -- for example: -`{ ..., "scope" : "messages contacts"}` +==== +[source,json] +---- +{ ..., "scope" : "messages contacts"} +---- +==== -When this is the case, Resource Server will attempt to coerce these scopes into a list of granted authorities, prefixing each scope with the string "SCOPE_". +When this is the case, Resource Server tries to coerce these scopes into a list of granted authorities, prefixing each scope with the string, `SCOPE_`. -This means that to protect an endpoint or method with a scope derived from a JWT, the corresponding expressions should include this prefix: +This means that, to protect an endpoint or method with a scope derived from a JWT, the corresponding expressions should include this prefix: ==== .Java @@ -624,7 +629,7 @@ fun springSecurityFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain ---- ==== -Or similarly with method security: +You can do something similar with method security: ==== .Java @@ -646,8 +651,8 @@ fun getMessages(): Flux { } ==== Extracting Authorities Manually However, there are a number of circumstances where this default is insufficient. -For example, some authorization servers don't use the `scope` attribute, but instead have their own custom attribute. -Or, at other times, the resource server may need to adapt the attribute or a composition of attributes into internalized authorities. +For example, some authorization servers do not use the `scope` attribute. Instead, they have their own custom attribute. +At other times, the resource server may need to adapt the attribute or a composition of attributes into internalized authorities. To this end, the DSL exposes `jwtAuthenticationConverter()`: @@ -703,10 +708,10 @@ fun grantedAuthoritiesExtractor(): Converter>, indicating the authorization server's issuer uri, Resource Server will default to verifying the `iss` claim as well as the `exp` and `nbf` timestamp claims. +Using <>, indicating the authorization server's issuer URI, Resource Server defaults to verifying the `iss` claim as well as the `exp` and `nbf` timestamp claims. -In circumstances where validation needs to be customized, Resource Server ships with two standard validators and also accepts custom `OAuth2TokenValidator` instances. +In circumstances where you need to customize validation needs, Resource Server ships with two standard validators and also accepts custom `OAuth2TokenValidator` instances. [[webflux-oauth2resourceserver-jwt-validation-clockskew]] ==== Customizing Timestamp Validation -JWT's typically have a window of validity, with the start of the window indicated in the `nbf` claim and the end indicated in the `exp` claim. +JWT instances typically have a window of validity, with the start of the window indicated in the `nbf` claim and the end indicated in the `exp` claim. -However, every server can experience clock drift, which can cause tokens to appear expired to one server, but not to another. -This can cause some implementation heartburn as the number of collaborating servers increases in a distributed system. +However, every server can experience clock drift, which can cause tokens to appear to be expired to one server but not to another. +This can cause some implementation heartburn, as the number of collaborating servers increases in a distributed system. -Resource Server uses `JwtTimestampValidator` to verify a token's validity window, and it can be configured with a `clockSkew` to alleviate the above problem: +Resource Server uses `JwtTimestampValidator` to verify a token's validity window, and you can configure it with a `clockSkew` to alleviate the clock drift problem: ==== .Java @@ -823,7 +828,7 @@ By default, Resource Server configures a clock skew of 60 seconds. [[webflux-oauth2resourceserver-validation-custom]] ==== Configuring a Custom Validator -Adding a check for the `aud` claim is simple with the `OAuth2TokenValidator` API: +You can Add a check for the `aud` claim with the `OAuth2TokenValidator` API: ==== .Java @@ -858,7 +863,7 @@ class AudienceValidator : OAuth2TokenValidator { ---- ==== -Then, to add into a resource server, it's a matter of specifying the `ReactiveJwtDecoder` instance: +Then, to add into a resource server, you can specifying the `ReactiveJwtDecoder` instance: ==== .Java @@ -896,25 +901,28 @@ fun jwtDecoder(): ReactiveJwtDecoder { [[webflux-oauth2resourceserver-opaque-minimaldependencies]] === Minimal Dependencies for Introspection -As described in <> most of Resource Server support is collected in `spring-security-oauth2-resource-server`. -However unless a custom <> is provided, the Resource Server will fallback to ReactiveOpaqueTokenIntrospector. -Meaning that both `spring-security-oauth2-resource-server` and `oauth2-oidc-sdk` are necessary in order to have a working minimal Resource Server that supports opaque Bearer Tokens. -Please refer to `spring-security-oauth2-resource-server` in order to determin the correct version for `oauth2-oidc-sdk`. +As described in <>, most Resource Server support is collected in `spring-security-oauth2-resource-server`. +However, unless you provide a custom <>, the Resource Server falls back to `ReactiveOpaqueTokenIntrospector`. +This means that both `spring-security-oauth2-resource-server` and `oauth2-oidc-sdk` are necessary to have a working minimal Resource Server that supports opaque Bearer Tokens. +See `spring-security-oauth2-resource-server` in order to determine the correct version for `oauth2-oidc-sdk`. [[webflux-oauth2resourceserver-opaque-minimalconfiguration]] === Minimal Configuration for Introspection -Typically, an opaque token can be verified via an https://tools.ietf.org/html/rfc7662[OAuth 2.0 Introspection Endpoint], hosted by the authorization server. +Typically, you can verify an opaque token with an https://tools.ietf.org/html/rfc7662[OAuth 2.0 Introspection Endpoint], hosted by the authorization server. This can be handy when revocation is a requirement. -When using https://spring.io/projects/spring-boot[Spring Boot], configuring an application as a resource server that uses introspection consists of two basic steps. -First, include the needed dependencies and second, indicate the introspection endpoint details. +When using https://spring.io/projects/spring-boot[Spring Boot], configuring an application as a resource server that uses introspection consists of two steps: + +. Include the needed dependencies. +. Indicate the introspection endpoint details. [[webflux-oauth2resourceserver-opaque-introspectionuri]] ==== Specifying the Authorization Server -To specify where the introspection endpoint is, simply do: +You can specify where the introspection endpoint is: +==== [source,yaml] ---- security: @@ -925,54 +933,55 @@ security: client-id: client client-secret: secret ---- +==== Where `https://idp.example.com/introspect` is the introspection endpoint hosted by your authorization server and `client-id` and `client-secret` are the credentials needed to hit that endpoint. -Resource Server will use these properties to further self-configure and subsequently validate incoming JWTs. +Resource Server uses these properties to further self-configure and subsequently validate incoming JWTs. -[NOTE] -When using introspection, the authorization server's word is the law. -If the authorization server responses that the token is valid, then it is. - -And that's it! +NOTE: When using introspection, the authorization server's word is the law. +If the authorization server responses that the token is valid, it is. ==== Startup Expectations -When this property and these dependencies are used, Resource Server will automatically configure itself to validate Opaque Bearer Tokens. +When this property and these dependencies are used, Resource Server automatically configures itself to validate Opaque Bearer Tokens. -This startup process is quite a bit simpler than for JWTs since no endpoints need to be discovered and no additional validation rules get added. +This startup process is quite a bit simpler than for JWTs, since no endpoints need to be discovered and no additional validation rules get added. ==== Runtime Expectations -Once the application is started up, Resource Server will attempt to process any request containing an `Authorization: Bearer` header: +Once the application has started, Resource Server tries to process any request containing an `Authorization: Bearer` header: -```http +==== +[source,http] +---- GET / HTTP/1.1 Authorization: Bearer some-token-value # Resource Server will process this -``` +---- +==== -So long as this scheme is indicated, Resource Server will attempt to process the request according to the Bearer Token specification. +So long as this scheme is indicated, Resource Server tries to process the request according to the Bearer Token specification. -Given an Opaque Token, Resource Server will +Given an Opaque Token, Resource Server: -1. Query the provided introspection endpoint using the provided credentials and the token -2. Inspect the response for an `{ 'active' : true }` attribute -3. Map each scope to an authority with the prefix `SCOPE_` +. Queries the provided introspection endpoint by using the provided credentials and the token. +. Inspects the response for an `{ 'active' : true }` attribute. +. Maps each scope to an authority with a prefix of `SCOPE_`. -The resulting `Authentication#getPrincipal`, by default, is a Spring Security `{security-api-url}org/springframework/security/oauth2/core/OAuth2AuthenticatedPrincipal.html[OAuth2AuthenticatedPrincipal]` object, and `Authentication#getName` maps to the token's `sub` property, if one is present. +By default, the resulting `Authentication#getPrincipal` is a Spring Security `{security-api-url}org/springframework/security/oauth2/core/OAuth2AuthenticatedPrincipal.html[OAuth2AuthenticatedPrincipal]` object, and `Authentication#getName` maps to the token's `sub` property, if one is present. From here, you may want to jump to: -* <> -* <> -* <> +* <> +* <> +* <> [[webflux-oauth2resourceserver-opaque-attributes]] -=== Looking Up Attributes Post-Authentication +=== Looking Up Attributes After Authentication Once a token is authenticated, an instance of `BearerTokenAuthentication` is set in the `SecurityContext`. -This means that it's available in `@Controller` methods when using `@EnableWebFlux` in your configuration: +This means that it is available in `@Controller` methods when you use `@EnableWebFlux` in your configuration: ==== .Java @@ -994,7 +1003,7 @@ fun foo(authentication: BearerTokenAuthentication): Mono { ---- ==== -Since `BearerTokenAuthentication` holds an `OAuth2AuthenticatedPrincipal`, that also means that it's available to controller methods, too: +Since `BearerTokenAuthentication` holds an `OAuth2AuthenticatedPrincipal`, it is also available to controller methods: ==== .Java @@ -1016,11 +1025,11 @@ fun foo(@AuthenticationPrincipal principal: OAuth2AuthenticatedPrincipal): Mono< ---- ==== -==== Looking Up Attributes Via SpEL +==== Looking Up Attributes with SpEL -Of course, this also means that attributes can be accessed via SpEL. +You can access attributes with the Spring Expression Language (SpEL). -For example, if using `@EnableReactiveMethodSecurity` so that you can use `@PreAuthorize` annotations, you can do: +For example, if you use `@EnableReactiveMethodSecurity` so that you can use `@PreAuthorize` annotations, you can do: ==== .Java @@ -1045,10 +1054,10 @@ fun forFoosEyesOnly(): Mono { [[webflux-oauth2resourceserver-opaque-sansboot]] === Overriding or Replacing Boot Auto Configuration -There are two `@Bean` s that Spring Boot generates on Resource Server's behalf. +Spring Boot generates two `@Bean` instances for Resource Server. -The first is a `SecurityWebFilterChain` that configures the app as a resource server. -When use Opaque Token, this `SecurityWebFilterChain` looks like: +The first is a `SecurityWebFilterChain` that configures the application as a resource server. +When you use an Opaque Token, this `SecurityWebFilterChain` looks like: ==== .Java @@ -1082,9 +1091,9 @@ fun springSecurityFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain ---- ==== -If the application doesn't expose a `SecurityWebFilterChain` bean, then Spring Boot will expose the above default one. +If the application does not expose a `SecurityWebFilterChain` bean, Spring Boot exposes the default bean (shown in the preceding listing). -Replacing this is as simple as exposing the bean within the application: +You can replace it by exposing the bean within the application: .Replacing SecurityWebFilterChain ==== @@ -1130,9 +1139,9 @@ fun springSecurityFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain ---- ==== -The above requires the scope of `message:read` for any URL that starts with `/messages/`. +The preceding example requires the scope of `message:read` for any URL that starts with `/messages/`. -Methods on the `oauth2ResourceServer` DSL will also override or replace auto configuration. +Methods on the `oauth2ResourceServer` DSL also override or replace auto configuration. For example, the second `@Bean` Spring Boot creates is a `ReactiveOpaqueTokenIntrospector`, which decodes `String` tokens into validated instances of `OAuth2AuthenticatedPrincipal`: @@ -1156,14 +1165,14 @@ fun introspector(): ReactiveOpaqueTokenIntrospector { ---- ==== -If the application doesn't expose a `ReactiveOpaqueTokenIntrospector` bean, then Spring Boot will expose the above default one. +If the application does not expose a `ReactiveOpaqueTokenIntrospector` bean, Spring Boot exposes the default one (shown in the preceding listing). -And its configuration can be overridden using `introspectionUri()` and `introspectionClientCredentials()` or replaced using `introspector()`. +You can override its configuration by using `introspectionUri()` and `introspectionClientCredentials()` or replace it by using `introspector()`. [[webflux-oauth2resourceserver-opaque-introspectionuri-dsl]] ==== Using `introspectionUri()` -An authorization server's Introspection Uri can be configured <> or it can be supplied in the DSL: +You can configure an authorization server's Introspection URI <>, or you can supply in the DSL: ==== .Java @@ -1213,7 +1222,7 @@ Using `introspectionUri()` takes precedence over any configuration property. [[webflux-oauth2resourceserver-opaque-introspector-dsl]] ==== Using `introspector()` -More powerful than `introspectionUri()` is `introspector()`, which will completely replace any Boot auto configuration of `ReactiveOpaqueTokenIntrospector`: +`introspector()` is more powerful than `introspectionUri()`. It completely replaces any Boot auto-configuration of `ReactiveOpaqueTokenIntrospector`: ==== .Java @@ -1256,7 +1265,7 @@ fun springSecurityFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain ---- ==== -This is handy when deeper configuration, like <>or <> is necessary. +This is handy when deeper configuration, such as <>or <>, is necessary. [[webflux-oauth2resourceserver-opaque-introspector-bean]] ==== Exposing a `ReactiveOpaqueTokenIntrospector` `@Bean` @@ -1286,13 +1295,18 @@ fun introspector(): ReactiveOpaqueTokenIntrospector { [[webflux-oauth2resourceserver-opaque-authorization]] === Configuring Authorization -An OAuth 2.0 Introspection endpoint will typically return a `scope` attribute, indicating the scopes (or authorities) it's been granted, for example: +An OAuth 2.0 Introspection endpoint typically returns a `scope` attribute, indicating the scopes (or authorities) it has been granted -- for example: -`{ ..., "scope" : "messages contacts"}` +==== +[source,json] +---- +{ ..., "scope" : "messages contacts"} +---- +==== -When this is the case, Resource Server will attempt to coerce these scopes into a list of granted authorities, prefixing each scope with the string "SCOPE_". +When this is the case, Resource Server tries to coerce these scopes into a list of granted authorities, prefixing each scope with a string: `SCOPE_`. -This means that to protect an endpoint or method with a scope derived from an Opaque Token, the corresponding expressions should include this prefix: +This means that, to protect an endpoint or method with a scope derived from an Opaque Token, the corresponding expressions should include this prefix: ==== .Java @@ -1333,7 +1347,7 @@ fun springSecurityFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain ---- ==== -Or similarly with method security: +You can do something similar with method security: ==== .Java @@ -1354,9 +1368,9 @@ fun getMessages(): Flux { } [[webflux-oauth2resourceserver-opaque-authorization-extraction]] ==== Extracting Authorities Manually -By default, Opaque Token support will extract the scope claim from an introspection response and parse it into individual `GrantedAuthority` instances. +By default, Opaque Token support extracts the scope claim from an introspection response and parses it into individual `GrantedAuthority` instances. -For example, if the introspection response were: +Consider the following example: [source,json] ---- @@ -1366,9 +1380,9 @@ For example, if the introspection response were: } ---- -Then Resource Server would generate an `Authentication` with two authorities, one for `message:read` and the other for `message:write`. +If the introspection response were as the preceding example shows, Resource Server would generate an `Authentication` with two authorities, one for `message:read` and the other for `message:write`. -This can, of course, be customized using a custom `ReactiveOpaqueTokenIntrospector` that takes a look at the attribute set and converts in its own way: +You can customize behavior by using a custom `ReactiveOpaqueTokenIntrospector` that looks at the attribute set and converts in its own way: ==== .Java @@ -1415,7 +1429,7 @@ class CustomAuthoritiesOpaqueTokenIntrospector : ReactiveOpaqueTokenIntrospector ---- ==== -Thereafter, this custom introspector can be configured simply by exposing it as a `@Bean`: +Thereafter, you can configure this custom introspector by exposing it as a `@Bean`: ==== .Java @@ -1441,12 +1455,13 @@ fun introspector(): ReactiveOpaqueTokenIntrospector { === Using Introspection with JWTs A common question is whether or not introspection is compatible with JWTs. -Spring Security's Opaque Token support has been designed to not care about the format of the token -- it will gladly pass any token to the introspection endpoint provided. +Spring Security's Opaque Token support has been designed to not care about the format of the token. It gladly passes any token to the provided introspection endpoint. -So, let's say that you've got a requirement that requires you to check with the authorization server on each request, in case the JWT has been revoked. +So, suppose you need to check with the authorization server on each request, in case the JWT has been revoked. -Even though you are using the JWT format for the token, your validation method is introspection, meaning you'd want to do: +Even though you are using the JWT format for the token, your validation method is introspection, meaning you would want to do: +==== [source,yaml] ---- spring: @@ -1458,14 +1473,15 @@ spring: client-id: client client-secret: secret ---- +==== In this case, the resulting `Authentication` would be `BearerTokenAuthentication`. Any attributes in the corresponding `OAuth2AuthenticatedPrincipal` would be whatever was returned by the introspection endpoint. -But, let's say that, oddly enough, the introspection endpoint only returns whether or not the token is active. +However, suppose that, for whatever reason, the introspection endpoint returns only whether or not the token is active. Now what? -In this case, you can create a custom `ReactiveOpaqueTokenIntrospector` that still hits the endpoint, but then updates the returned principal to have the JWTs claims as the attributes: +In this case, you can create a custom `ReactiveOpaqueTokenIntrospector` that still hits the endpoint but then updates the returned principal to have the JWTs claims as the attributes: ==== .Java @@ -1519,7 +1535,7 @@ class JwtOpaqueTokenIntrospector : ReactiveOpaqueTokenIntrospector { ---- ==== -Thereafter, this custom introspector can be configured simply by exposing it as a `@Bean`: +Thereafter, you can configure this custom introspector by exposing it as a `@Bean`: ==== .Java @@ -1544,16 +1560,16 @@ fun introspector(): ReactiveOpaqueTokenIntrospector { [[webflux-oauth2resourceserver-opaque-userinfo]] === Calling a `/userinfo` Endpoint -Generally speaking, a Resource Server doesn't care about the underlying user, but instead about the authorities that have been granted. +Generally speaking, a Resource Server does not care about the underlying user but, instead, cares about the authorities that have been granted. That said, at times it can be valuable to tie the authorization statement back to a user. -If an application is also using `spring-security-oauth2-client`, having set up the appropriate `ClientRegistrationRepository`, then this is quite simple with a custom `OpaqueTokenIntrospector`. -This implementation below does three things: +If an application also uses `spring-security-oauth2-client`, having set up the appropriate `ClientRegistrationRepository`, you can do so with a custom `OpaqueTokenIntrospector`. +The implementation in the next listing does three things: -* Delegates to the introspection endpoint, to affirm the token's validity -* Looks up the appropriate client registration associated with the `/userinfo` endpoint -* Invokes and returns the response from the `/userinfo` endpoint +* Delegates to the introspection endpoint, to affirm the token's validity. +* Looks up the appropriate client registration associated with the `/userinfo` endpoint. +* Invokes and returns the response from the `/userinfo` endpoint. ==== .Java @@ -1610,8 +1626,8 @@ class UserInfoOpaqueTokenIntrospector : ReactiveOpaqueTokenIntrospector { ---- ==== -If you aren't using `spring-security-oauth2-client`, it's still quite simple. -You will simply need to invoke the `/userinfo` with your own instance of `WebClient`: +If you do not use `spring-security-oauth2-client`, you can do so +by invoking the `/userinfo` with your own instance of `WebClient`: ==== .Java @@ -1672,17 +1688,17 @@ fun introspector(): ReactiveOpaqueTokenIntrospector { A resource server is considered multi-tenant when there are multiple strategies for verifying a bearer token, keyed by some tenant identifier. -For example, your resource server may accept bearer tokens from two different authorization servers. -Or, your authorization server may represent a multiplicity of issuers. +For example, your resource server can accept bearer tokens from two different authorization servers. +Alternately, your authorization server can represent a multiplicity of issuers. -In each case, there are two things that need to be done and trade-offs associated with how you choose to do them: +In each case, two things need to be done and trade-offs are associated with how you choose to do them: -1. Resolve the tenant -2. Propagate the tenant +1. Resolve the tenant. +2. Propagate the tenant. === Resolving the Tenant By Claim -One way to differentiate tenants is by the issuer claim. Since the issuer claim accompanies signed JWTs, this can be done with the `JwtIssuerReactiveAuthenticationManagerResolver`, like so: +One way to differentiate tenants is by the issuer claim. Since the issuer claim accompanies signed JWTs, you can do so with the `JwtIssuerReactiveAuthenticationManagerResolver`: ==== .Java @@ -1722,8 +1738,8 @@ This allows for an application startup that is independent from those authorizat ==== Dynamic Tenants -Of course, you may not want to restart the application each time a new tenant is added. -In this case, you can configure the `JwtIssuerReactiveAuthenticationManagerResolver` with a repository of `ReactiveAuthenticationManager` instances, which you can edit at runtime, like so: +You may not want to restart the application each time a new tenant is added. +In this case, you can configure the `JwtIssuerReactiveAuthenticationManagerResolver` with a repository of `ReactiveAuthenticationManager` instances, which you can edit at runtime: ==== .Java @@ -1777,20 +1793,20 @@ return http { ---- ==== -In this case, you construct `JwtIssuerReactiveAuthenticationManagerResolver` with a strategy for obtaining the `ReactiveAuthenticationManager` given the issuer. -This approach allows us to add and remove elements from the repository (shown as a `Map` in the snippet) at runtime. +In this case, you construct `JwtIssuerReactiveAuthenticationManagerResolver` with a strategy for obtaining the `ReactiveAuthenticationManager` given to the issuer. +This approach lets us add and remove elements from the repository (shown as a `Map` in the preceding snippet) at runtime. NOTE: It would be unsafe to simply take any issuer and construct an `ReactiveAuthenticationManager` from it. -The issuer should be one that the code can verify from a trusted source like an allowed list of issuers. +The issuer should be one that the code can verify from a trusted source, such as an allowed list of issuers. [[webflux-oauth2resourceserver-bearertoken-resolver]] == Bearer Token Resolution By default, Resource Server looks for a bearer token in the `Authorization` header. -This, however, can be customized. +However, you can verify this token. For example, you may have a need to read the bearer token from a custom header. -To achieve this, you can wire an instance of `ServerBearerTokenAuthenticationConverter` into the DSL, as you can see in the following example: +To do so, you can wire an instance of `ServerBearerTokenAuthenticationConverter` into the DSL: .Custom Bearer Token Header ==== @@ -1820,8 +1836,8 @@ return http { == Bearer Token Propagation -Now that you're in possession of a bearer token, it might be handy to pass that to downstream services. -This is quite simple with `{security-api-url}org/springframework/security/oauth2/server/resource/web/reactive/function/client/ServerBearerExchangeFilterFunction.html[ServerBearerExchangeFilterFunction]`, which you can see in the following example: +Now that you have a bearer token, you can pass that to downstream services. +This is possible with `{security-api-url}org/springframework/security/oauth2/server/resource/web/reactive/function/client/ServerBearerExchangeFilterFunction.html[ServerBearerExchangeFilterFunction]`: ==== .Java @@ -1847,10 +1863,8 @@ fun rest(): WebClient { ---- ==== -When the above `WebClient` is used to perform requests, Spring Security will look up the current `Authentication` and extract any `{security-api-url}org/springframework/security/oauth2/core/AbstractOAuth2Token.html[AbstractOAuth2Token]` credential. -Then, it will propagate that token in the `Authorization` header. - -For example: +When the `WebClient` shown in the preceding example performs requests, Spring Security looks up the current `Authentication` and extract any `{security-api-url}org/springframework/security/oauth2/core/AbstractOAuth2Token.html[AbstractOAuth2Token]` credential. +Then, it propagates that token in the `Authorization` header -- for example: ==== .Java @@ -1872,9 +1886,9 @@ this.rest.get() ---- ==== -Will invoke the `https://other-service.example.com/endpoint`, adding the bearer token `Authorization` header for you. +The prececing example invokes the `https://other-service.example.com/endpoint`, adding the bearer token `Authorization` header for you. -In places where you need to override this behavior, it's a simple matter of supplying the header yourself, like so: +In places where you need to override this behavior, you can supply the header yourself: ==== .Java @@ -1898,8 +1912,7 @@ rest.get() ---- ==== -In this case, the filter will fall back and simply forward the request onto the rest of the web filter chain. +In this case, the filter falls back and forwards the request onto the rest of the web filter chain. -[NOTE] -Unlike the https://docs.spring.io/spring-security/site/docs/current-SNAPSHOT/api/org/springframework/security/oauth2/client/web/reactive/function/client/ServerOAuth2AuthorizedClientExchangeFilterFunction.html[OAuth 2.0 Client filter function], this filter function makes no attempt to renew the token, should it be expired. -To obtain this level of support, please use the OAuth 2.0 Client filter. +NOTE: Unlike the https://docs.spring.io/spring-security/site/docs/current-SNAPSHOT/api/org/springframework/security/oauth2/client/web/reactive/function/client/ServerOAuth2AuthorizedClientExchangeFilterFunction.html[OAuth 2.0 Client filter function], this filter function makes no attempt to renew the token, should it be expired. +To obtain this level of support, use the OAuth 2.0 Client filter. diff --git a/docs/manual/src/docs/asciidoc/_includes/reactive/registered-oauth2-authorized-client.adoc b/docs/manual/src/docs/asciidoc/_includes/reactive/registered-oauth2-authorized-client.adoc index cd1e4c06cd2..ce986905603 100644 --- a/docs/manual/src/docs/asciidoc/_includes/reactive/registered-oauth2-authorized-client.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/reactive/registered-oauth2-authorized-client.adoc @@ -1,14 +1,11 @@ [[webflux-roac]] = @RegisteredOAuth2AuthorizedClient -Spring Security allows resolving an access token using `@RegisteredOAuth2AuthorizedClient`. +Spring Security allows resolving an access token by using `@RegisteredOAuth2AuthorizedClient`. -[NOTE] -==== -A working example can be found in {gh-samples-url}/boot/oauth2webclient-webflux[*OAuth 2.0 WebClient WebFlux sample*]. -==== +NOTE: You can find a working example in the {gh-samples-url}/boot/oauth2webclient-webflux[OAuth 2.0 WebClient WebFlux sample]. -After configuring Spring Security for <> or as an <>, an `OAuth2AuthorizedClient` can be resolved using the following: +After configuring Spring Security for <> or as an <>, you can resolve an `OAuth2AuthorizedClient` by using the following: ==== .Java @@ -30,14 +27,14 @@ fun explicit(@RegisteredOAuth2AuthorizedClient("client-id") authorizedClient: OA ---- ==== -This integrates into Spring Security to provide the following features: +This code integrates into Spring Security to provide the following features: -* Spring Security will automatically refresh expired tokens (if a refresh token is present) -* If an access token is requested and not present, Spring Security will automatically request the access token. -** For `authorization_code` this involves performing the redirect and then replaying the original request -** For `client_credentials` the token is simply requested and saved +* Spring Security automatically refreshes expired tokens (if a refresh token is present). +* If an access token is requested and not present, Spring Security automatically requests the access token. +** For `authorization_code`, this involves performing the redirect and then replaying the original request. +** For `client_credentials`, the token is simply requested and saved. -If the user authenticated using `oauth2Login()`, then the `client-id` is optional. +If the user authenticated by using `oauth2Login()`, the `client-id` is optional. For example, the following would work: ==== @@ -60,4 +57,4 @@ fun implicit(@RegisteredOAuth2AuthorizedClient authorizedClient: OAuth2Authorize ---- ==== -This is convenient if the user always authenticates with OAuth2 Login and an access token from the same authorization server is needed. +This approach is convenient if the user always authenticates with OAuth2 Login and an access token from the same authorization server is needed. diff --git a/docs/manual/src/docs/asciidoc/_includes/reactive/rsocket.adoc b/docs/manual/src/docs/asciidoc/_includes/reactive/rsocket.adoc index 7cecae769b6..822b0cd1a9c 100644 --- a/docs/manual/src/docs/asciidoc/_includes/reactive/rsocket.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/reactive/rsocket.adoc @@ -2,9 +2,9 @@ = RSocket Security Spring Security's RSocket support relies on a `SocketAcceptorInterceptor`. -The main entry point into security is found in the `PayloadSocketAcceptorInterceptor` which adapts the RSocket APIs to allow intercepting a `PayloadExchange` with `PayloadInterceptor` implementations. +The main entry point into security is in `PayloadSocketAcceptorInterceptor`, which adapts the RSocket APIs to allow intercepting a `PayloadExchange` with `PayloadInterceptor` implementations. -You can find a few sample applications that demonstrate the code below: +You can find two sample applications that demonstrate the code: * Hello RSocket {gh-samples-url}/boot/hellorsocket[hellorsocket] * https://github.com/rwinch/spring-flights/tree/security[Spring Flights] @@ -12,8 +12,9 @@ You can find a few sample applications that demonstrate the code below: == Minimal RSocket Security Configuration -You can find a minimal RSocket Security configuration below: +The following example shows a minimal RSocket Security configuration: +==== [source,java] ----- @Configuration @@ -31,15 +32,17 @@ public class HelloRSocketSecurityConfig { } } ----- +==== This configuration enables <> and sets up <> to require an authenticated user for any request. == Adding SecuritySocketAcceptorInterceptor -For Spring Security to work we need to apply `SecuritySocketAcceptorInterceptor` to the `ServerRSocketFactory`. -This is what connects our `PayloadSocketAcceptorInterceptor` we created with the RSocket infrastructure. -In a Spring Boot application this is done automatically using `RSocketSecurityAutoConfiguration` with the following code. +For Spring Security to work, we need to apply `SecuritySocketAcceptorInterceptor` to the `ServerRSocketFactory`. +Doing so connects our `PayloadSocketAcceptorInterceptor` with the RSocket infrastructure. +In a Spring Boot application, you can do this automatically by using `RSocketSecurityAutoConfiguration` with the following code: +==== [source,java] ---- @Bean @@ -48,45 +51,44 @@ ServerRSocketFactoryProcessor springSecurityRSocketSecurity( return builder -> builder.addSocketAcceptorPlugin(interceptor); } ---- +==== [[rsocket-authentication]] == RSocket Authentication -RSocket authentication is performed with `AuthenticationPayloadInterceptor` which acts as a controller to invoke a `ReactiveAuthenticationManager` instance. +RSocket authentication is performed with `AuthenticationPayloadInterceptor`, which acts as a controller to invoke a `ReactiveAuthenticationManager` instance. [[rsocket-authentication-setup-vs-request]] -=== Authentication at Setup vs Request Time +=== Authentication at Setup versus Request Time -Generally, authentication can occur at setup time and/or request time. +Generally, authentication can occur at setup time or at request time or both. Authentication at setup time makes sense in a few scenarios. -A common scenarios is when a single user (i.e. mobile connection) is leveraging an RSocket connection. -In this case only a single user is leveraging the connection, so authentication can be done once at connection time. +A common scenarios is when a single user (such as a mobile connection) uses an RSocket connection. +In this case, only a single user uses the connection, so authentication can be done once at connection time. -In a scenario where the RSocket connection is shared it makes sense to send credentials on each request. -For example, a web application that connects to an RSocket server as a downstream service would make a single connection that all users leverage. -In this case, if the RSocket server needs to perform authorization based on the web application's users credentials per request makes sense. +In a scenario where the RSocket connection is shared, it makes sense to send credentials on each request. +For example, a web application that connects to an RSocket server as a downstream service would make a single connection that all users use. +In this case, if the RSocket server needs to perform authorization based on the web application's users credentials, authentication for each request makes sense. -In some scenarios authentication at setup and per request makes sense. -Consider a web application as described previously. +In some scenarios, authentication at both setup and for each request makes sense. +Consider a web application, as described previously. If we need to restrict the connection to the web application itself, we can provide a credential with a `SETUP` authority at connection time. -Then each user would have different authorities but not the `SETUP` authority. +Then each user can have different authorities but not the `SETUP` authority. This means that individual users can make requests but not make additional connections. [[rsocket-authentication-simple]] === Simple Authentication -Spring Security has support for https://github.com/rsocket/rsocket/blob/5920ed374d008abb712cb1fd7c9d91778b2f4a68/Extensions/Security/Simple.md[Simple Authentication Metadata Extension]. +Spring Security has support for the https://github.com/rsocket/rsocket/blob/5920ed374d008abb712cb1fd7c9d91778b2f4a68/Extensions/Security/Simple.md[Simple Authentication Metadata Extension]. -[NOTE] -==== -Basic Authentication drafts evolved into Simple Authentication and is only supported for backward compatibility. +NOTE: Basic Authentication evolved into Simple Authentication and is only supported for backward compatibility. See `RSocketSecurity.basicAuthentication(Customizer)` for setting it up. -==== -The RSocket receiver can decode the credentials using `AuthenticationPayloadExchangeConverter` which is automatically setup using the `simpleAuthentication` portion of the DSL. -An explicit configuration can be found below. +The RSocket receiver can decode the credentials by using `AuthenticationPayloadExchangeConverter`, which is automatically setup by using the `simpleAuthentication` portion of the DSL. +The following example shows an explicit configuration: +==== [source,java] ---- @Bean @@ -101,17 +103,21 @@ PayloadSocketAcceptorInterceptor rsocketInterceptor(RSocketSecurity rsocket) { return rsocket.build(); } ---- +==== -The RSocket sender can send credentials using `SimpleAuthenticationEncoder` which can be added to Spring's `RSocketStrategies`. +The RSocket sender can send credentials by using `SimpleAuthenticationEncoder`, which you can add to Spring's `RSocketStrategies`. +==== [source,java] ---- RSocketStrategies.Builder strategies = ...; strategies.encoder(new SimpleAuthenticationEncoder()); ---- +==== -It can then be used to send a username and password to the receiver in the setup: +You can then use it to send a username and password to the receiver in the setup: +==== [source,java] ---- MimeType authenticationMimeType = @@ -122,9 +128,11 @@ Mono requester = RSocketRequester.builder() .rsocketStrategies(strategies.build()) .connectTcp(host, port); ---- +==== -Alternatively or additionally, a username and password can be sent in a request. +Alternatively or additionally, a username and password can be sent in a request: +==== [source,java] ---- Mono requester; @@ -138,16 +146,18 @@ public Mono findRadar(String code) { ); } ---- +==== [[rsocket-authentication-jwt]] === JWT -Spring Security has support for https://github.com/rsocket/rsocket/blob/5920ed374d008abb712cb1fd7c9d91778b2f4a68/Extensions/Security/Bearer.md[Bearer Token Authentication Metadata Extension]. -The support comes in the form of authenticating a JWT (determining the JWT is valid) and then using the JWT to make authorization decisions. +Spring Security has support for the https://github.com/rsocket/rsocket/blob/5920ed374d008abb712cb1fd7c9d91778b2f4a68/Extensions/Security/Bearer.md[Bearer Token Authentication Metadata Extension]. +The support comes in the form of authenticating a JWT (determining that the JWT is valid) and then using the JWT to make authorization decisions. -The RSocket receiver can decode the credentials using `BearerPayloadExchangeConverter` which is automatically setup using the `jwt` portion of the DSL. -An example configuration can be found below: +The RSocket receiver can decode the credentials by using `BearerPayloadExchangeConverter`, which is automatically setup by using the `jwt` portion of the DSL. +The following listing shows an example configuration: +==== [source,java] ---- @Bean @@ -162,10 +172,12 @@ PayloadSocketAcceptorInterceptor rsocketInterceptor(RSocketSecurity rsocket) { return rsocket.build(); } ---- +==== -The configuration above relies on the existence of a `ReactiveJwtDecoder` `@Bean` being present. -An example of creating one from the issuer can be found below: +The preceding configuration relies a `ReactiveJwtDecoder` `@Bean` being present. +The following example creates one from the issuer: +==== [source,java] ---- @Bean @@ -174,10 +186,12 @@ ReactiveJwtDecoder jwtDecoder() { .fromIssuerLocation("https://example.com/auth/realms/demo"); } ---- +==== -The RSocket sender does not need to do anything special to send the token because the value is just a simple String. -For example, the token can be sent at setup time: +The RSocket sender does not need to do anything special to send the token, because the value is a simple `String`. +The following example sends the token at setup time: +==== [source,java] ---- MimeType authenticationMimeType = @@ -187,9 +201,11 @@ Mono requester = RSocketRequester.builder() .setupMetadata(token, authenticationMimeType) .connectTcp(host, port); ---- +==== -Alternatively or additionally, the token can be sent in a request. +Alternatively or additionally, you can send the token in a request: +==== [source,java] ---- MimeType authenticationMimeType = @@ -205,14 +221,16 @@ public Mono findRadar(String code) { ); } ---- +==== [[rsocket-authorization]] == RSocket Authorization -RSocket authorization is performed with `AuthorizationPayloadInterceptor` which acts as a controller to invoke a `ReactiveAuthorizationManager` instance. -The DSL can be used to setup authorization rules based upon the `PayloadExchange`. -An example configuration can be found below: +RSocket authorization is performed with `AuthorizationPayloadInterceptor`, which acts as a controller to invoke a `ReactiveAuthorizationManager` instance. +You can use the DSL to set up authorization rules based upon the `PayloadExchange`. +The following listing shows an example configuration: +==== [[source,java]] ---- rsocket @@ -228,17 +246,18 @@ rsocket .anyExchange().permitAll() // <6> ) ---- -<1> Setting up a connection requires the authority `ROLE_SETUP` -<2> If the route is `fetch.profile.me` authorization only requires the user be authenticated -<3> In this rule we setup a custom matcher where authorization requires the user to have the authority `ROLE_CUSTOM` -<4> This rule leverages custom authorization. -The matcher expresses a variable with the name `username` that is made available in the `context`. +<1> Setting up a connection requires the `ROLE_SETUP` authority. +<2> If the route is `fetch.profile.me`, authorization only requires the user to be authenticated. +<3> In this rule, we set up a custom matcher, where authorization requires the user to have the `ROLE_CUSTOM` authority. +<4> This rule uses custom authorization. +The matcher expresses a variable with a name of `username` that is made available in the `context`. A custom authorization rule is exposed in the `checkFriends` method. -<5> This rule ensures that request that does not already have a rule will require the user to be authenticated. +<5> This rule ensures that a request that does not already have a rule requires the user to be authenticated. A request is where the metadata is included. It would not include additional payloads. <6> This rule ensures that any exchange that does not already have a rule is allowed for anyone. -In this example, it means that payloads that have no metadata have no authorization rules. +In this example, it means that payloads that have no metadata also have no authorization rules. +==== -It is important to understand that authorization rules are performed in order. -Only the first authorization rule that matches will be invoked. +Note that authorization rules are performed in order. +Only the first authorization rule that matches is invoked. diff --git a/docs/manual/src/docs/asciidoc/_includes/reactive/test.adoc b/docs/manual/src/docs/asciidoc/_includes/reactive/test.adoc index 4a9e3a9e390..247dc15a4c5 100644 --- a/docs/manual/src/docs/asciidoc/_includes/reactive/test.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/reactive/test.adoc @@ -1,12 +1,15 @@ [[test-webflux]] = Reactive Test Support +This section describes how to test reactive applications that use Spring Security. + [[test-erms]] == Testing Reactive Method Security -For example, we can test our example from <> using the same setup and annotations we did in <>. -Here is a minimal sample of what we can do: +For example, we can test our example from <> by using the same setup and annotations that we used in <>. +The following minimal sample shows what we can do: +==== [source,java] ---- @RunWith(SpringRunner.class) @@ -39,6 +42,7 @@ public class HelloWorldMessageServiceTests { } } ---- +==== [[test-webtestclient]] == WebTestClientSupport @@ -46,6 +50,7 @@ public class HelloWorldMessageServiceTests { Spring Security provides integration with `WebTestClient`. The basic setup looks like this: +==== [source,java] ---- @RunWith(SpringRunner.class) @@ -69,12 +74,13 @@ public class HelloWebfluxMethodApplicationTests { // ... } ---- +==== === Authentication -After applying the Spring Security support to `WebTestClient` we can use either annotations or `mutateWith` support. -For example: +After applying the Spring Security support to `WebTestClient`, we can use either annotations or `mutateWith` support -- for example: +==== [source,java] ---- @Test @@ -132,13 +138,14 @@ public void messageWhenMutateWithMockAdminThenOk() throws Exception { .expectBody(String.class).isEqualTo("Hello World!"); } ---- +==== === CSRF Support -Spring Security also provides support for CSRF testing with `WebTestClient`. -For example: +Spring Security also provides support for CSRF testing with `WebTestClient` -- for example: +==== [source,java] ---- this.rest @@ -148,14 +155,16 @@ this.rest .uri("/login") ... ---- +==== [[webflux-testing-oauth2]] === 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`. -For example, for a controller that looks like this: +Consider the following example of a controller: +==== [source,java] ---- @GetMapping("/endpoint") @@ -163,11 +172,13 @@ public Mono foo(Principal user) { return Mono.just(user.getName()); } ---- +==== -There's nothing OAuth2-specific about it, so you will likely be able to simply <> and be fine. +Nothing about it is OAuth2-specific, so you can <> and be fine. -But, in cases where your controllers are bound to some aspect of Spring Security's OAuth 2.0 support, like the following: +However, consider a case where your controller is bound to some aspect of Spring Security's OAuth 2.0 support: +==== [source,java] ---- @GetMapping("/endpoint") @@ -175,50 +186,59 @@ public Mono foo(@AuthenticationPrincipal OidcUser user) { return Mono.just(user.getIdToken().getSubject()); } ---- +==== -then Spring Security's test support can come in handy. +In that case, Spring Security's test support is handy. [[webflux-testing-oidc-login]] === Testing OIDC Login -Testing the method above with `WebTestClient` 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. +Testing the method shown in the <> with `WebTestClient` requires simulating some kind of grant flow with an authorization server. +This is a daunting task, which is why Spring Security ships with support for removing this boilerplate. -For example, we can tell Spring Security to include a default `OidcUser` using the `SecurityMockServerConfigurers#oidcLogin` method, like so: +For example, we can tell Spring Security to include a default `OidcUser` by using the `SecurityMockServerConfigurers#oidcLogin` method: +==== [source,java] ---- client .mutateWith(mockOidcLogin()).get().uri("/endpoint").exchange(); ---- +==== -What this will do is configure the associated `MockServerRequest` with an `OidcUser` that includes a simple `OidcIdToken`, `OidcUserInfo`, and `Collection` of granted authorities. +That line configures the associated `MockServerRequest` with an `OidcUser` that includes a simple `OidcIdToken`, an `OidcUserInfo`, and a `Collection` of granted authorities. -Specifically, it will include an `OidcIdToken` with a `sub` claim set to `user`: +Specifically, it includes an `OidcIdToken` with a `sub` claim set to `user`: +==== [source,json] ---- assertThat(user.getIdToken().getClaim("sub")).isEqualTo("user"); ---- +==== -an `OidcUserInfo` with no claims set: +It also includes an `OidcUserInfo` with no claims set: +==== [source,json] ---- assertThat(user.getUserInfo().getClaims()).isEmpty(); ---- +==== -and a `Collection` of authorities with just one authority, `SCOPE_read`: +It also includes a `Collection` of authorities with just one authority, `SCOPE_read`: +==== [source,json] ---- assertThat(user.getAuthorities()).hasSize(1); assertThat(user.getAuthorities()).containsExactly(new SimpleGrantedAuthority("SCOPE_read")); ---- +==== -Spring Security does the necessary work to make sure that the `OidcUser` instance is available for <>. +Spring Security makes sure that the `OidcUser` instance is available for <>. -Further, it also links that `OidcUser` to a simple instance of `OAuth2AuthorizedClient` that it deposits into a mock `ServerOAuth2AuthorizedClientRepository`. +Further, it also links the `OidcUser` to a simple instance of `OAuth2AuthorizedClient` that it deposits into a mock `ServerOAuth2AuthorizedClientRepository`. This can be handy if your tests <>.. [[webflux-testing-oidc-login-authorities]] @@ -226,8 +246,9 @@ This can be handy if your tests < foo(@AuthenticationPrincipal OidcUser oidcUser) { // ... } ---- +==== -In that case, you'd want to specify that claim with the `idToken()` method: +In that case, you can specify that claim with the `idToken()` method: +==== [source,java] ---- client @@ -264,25 +289,27 @@ client ) .get().uri("/endpoint").exchange(); ---- +==== -since `OidcUser` collects its claims from `OidcIdToken`. +That works because `OidcUser` collects its claims from `OidcIdToken`. [[webflux-testing-oidc-login-user]] ==== Additional Configurations -There are additional methods, too, for further configuring the authentication; it simply depends on what data your controller expects: +There are additional methods, too, for further configuring the authentication, depending on what data your controller expects: -* `userInfo(OidcUserInfo.Builder)` - For configuring the `OidcUserInfo` instance -* `clientRegistration(ClientRegistration)` - For configuring the associated `OAuth2AuthorizedClient` with a given `ClientRegistration` -* `oidcUser(OidcUser)` - For configuring the complete `OidcUser` instance +* `userInfo(OidcUserInfo.Builder)`: Configures the `OidcUserInfo` instance +* `clientRegistration(ClientRegistration)`: Configures the associated `OAuth2AuthorizedClient` with a given `ClientRegistration` +* `oidcUser(OidcUser)`: Configures the complete `OidcUser` instance That last one is handy if you: -1. Have your own implementation of `OidcUser`, or -2. Need to change the name attribute +* Have your own implementation of `OidcUser` or +* Need to change the name attribute -For example, let's say that your authorization server sends the principal name in the `user_name` claim instead of the `sub` claim. +For example, suppose that your authorization server sends the principal name in the `user_name` claim instead of the `sub` claim. In that case, you can configure an `OidcUser` by hand: +==== [source,java] ---- OidcUser oidcUser = new DefaultOidcUser( @@ -294,15 +321,17 @@ client .mutateWith(mockOidcLogin().oidcUser(oidcUser)) .get().uri("/endpoint").exchange(); ---- +==== [[webflux-testing-oauth2-login]] === Testing OAuth 2.0 Login -As with <>, 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. +As with <>, testing OAuth 2.0 Login presents a similar challenge: mocking a grant flow. +Because of that, Spring Security also has test support for non-OIDC use cases. -Let's say that we've got a controller that gets the logged-in user as an `OAuth2User`: +Suppose that we have a controller that gets the logged-in user as an `OAuth2User`: +==== [source,java] ---- @GetMapping("/endpoint") @@ -310,32 +339,39 @@ public Mono foo(@AuthenticationPrincipal OAuth2User oauth2User) { return Mono.just(oauth2User.getAttribute("sub")); } ---- +==== -In that case, we can tell Spring Security to include a default `OAuth2User` using the `SecurityMockServerConfigurers#oauth2User` method, like so: +In that case, we can tell Spring Security to include a default `OAuth2User` by using the `SecurityMockServerConfigurers#oauth2User` method: +==== [source,java] ---- client .mutateWith(mockOAuth2Login()) .get().uri("/endpoint").exchange(); ---- +==== -What this will do is configure the associated `MockServerRequest` with an `OAuth2User` that includes a simple `Map` of attributes and `Collection` of granted authorities. +The preceding example configures the associated `MockServerRequest` with an `OAuth2User` that includes a simple `Map` of attributes and a `Collection` of granted authorities. -Specifically, it will include a `Map` with a key/value pair of `sub`/`user`: +Specifically, it includes a `Map` with a key/value pair of `sub`/`user`: +==== [source,json] ---- assertThat((String) user.getAttribute("sub")).isEqualTo("user"); ---- +==== -and a `Collection` of authorities with just one authority, `SCOPE_read`: +It also includes a `Collection` of authorities with just one authority, `SCOPE_read`: +==== [source,json] ---- assertThat(user.getAuthorities()).hasSize(1); assertThat(user.getAuthorities()).containsExactly(new SimpleGrantedAuthority("SCOPE_read")); ---- +==== Spring Security does the necessary work to make sure that the `OAuth2User` instance is available for <>. @@ -347,8 +383,9 @@ This can be handy if your tests < foo(@AuthenticationPrincipal OAuth2User oauth2User) { // ... } ---- +==== -In that case, you'd want to specify that attribute with the `attributes()` method: +In that case, you can specify that attribute with the `attributes()` method: +==== [source,java] ---- client @@ -385,22 +426,24 @@ client ) .get().uri("/endpoint").exchange(); ---- +==== [[webflux-testing-oauth2-login-user]] ==== Additional Configurations -There are additional methods, too, for further configuring the authentication; it simply depends on what data your controller expects: +There are additional methods, too, for further configuring the authentication, depending on what data your controller expects: -* `clientRegistration(ClientRegistration)` - For configuring the associated `OAuth2AuthorizedClient` with a given `ClientRegistration` -* `oauth2User(OAuth2User)` - For configuring the complete `OAuth2User` instance +* `clientRegistration(ClientRegistration)`: Configures the associated `OAuth2AuthorizedClient` with a given `ClientRegistration` +* `oauth2User(OAuth2User)`: Configures the complete `OAuth2User` instance That last one is handy if you: -1. Have your own implementation of `OAuth2User`, or -2. Need to change the name attribute +* Have your own implementation of `OAuth2User` or +* Need to change the name attribute -For example, let's say that your authorization server sends the principal name in the `user_name` claim instead of the `sub` claim. +For example, suppose that your authorization server sends the principal name in the `user_name` claim instead of the `sub` claim. In that case, you can configure an `OAuth2User` by hand: +==== [source,java] ---- OAuth2User oauth2User = new DefaultOAuth2User( @@ -412,14 +455,16 @@ client .mutateWith(mockOAuth2Login().oauth2User(oauth2User)) .get().uri("/endpoint").exchange(); ---- +==== [[webflux-testing-oauth2-client]] === 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: +For example, your controller may rely on the client credentials grant to get a token that is not associated with the user at all: -[source,json] +==== +[source,java] ---- @GetMapping("/endpoint") public Mono foo(@RegisteredOAuth2AuthorizedClient("my-app") OAuth2AuthorizedClient authorizedClient) { @@ -429,51 +474,61 @@ public Mono foo(@RegisteredOAuth2AuthorizedClient("my-app") OAuth2Author .bodyToMono(String.class); } ---- +==== -Simulating this handshake with the authorization server could be cumbersome. -Instead, you can use `SecurityMockServerConfigurers#oauth2Client` to add a `OAuth2AuthorizedClient` into a mock `ServerOAuth2AuthorizedClientRepository`: +Simulating this handshake with the authorization server can be cumbersome. +Instead, you can use `SecurityMockServerConfigurers#oauth2Client` to add a `OAuth2AuthorizedClient` to a mock `ServerOAuth2AuthorizedClientRepository`: +==== [source,java] ---- client .mutateWith(mockOAuth2Client("my-app")) .get().uri("/endpoint").exchange(); ---- +==== -What this will do is create an `OAuth2AuthorizedClient` that has a simple `ClientRegistration`, `OAuth2AccessToken`, and resource owner name. +This creates an `OAuth2AuthorizedClient` that has a simple `ClientRegistration`, a `OAuth2AccessToken`, and a resource owner name. -Specifically, it will include a `ClientRegistration` with a client id of "test-client" and client secret of "test-secret": +Specifically, it includes a `ClientRegistration` with a client ID of `test-client` and a client secret of `test-secret`: +==== [source,json] ---- assertThat(authorizedClient.getClientRegistration().getClientId()).isEqualTo("test-client"); assertThat(authorizedClient.getClientRegistration().getClientSecret()).isEqualTo("test-secret"); ---- +==== -a resource owner name of "user": +It also includes a resource owner name of `user`: +==== [source,json] ---- assertThat(authorizedClient.getPrincipalName()).isEqualTo("user"); ---- +==== -and an `OAuth2AccessToken` with just one scope, `read`: +It also includes an `OAuth2AccessToken` with one scope, `read`: +==== [source,json] ---- assertThat(authorizedClient.getAccessToken().getScopes()).hasSize(1); assertThat(authorizedClient.getAccessToken().getScopes()).containsExactly("read"); ---- +==== -The client can then be retrieved as normal using `@RegisteredOAuth2AuthorizedClient` in a controller method. +You can then retrieve the client as usual by using `@RegisteredOAuth2AuthorizedClient` in a controller method. [[webflux-testing-oauth2-client-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: +Consider the following example of how a controller can inspect the scopes: -[source,json] +==== +[source,java] ---- @GetMapping("/endpoint") public Mono foo(@RegisteredOAuth2AuthorizedClient("my-app") OAuth2AuthorizedClient authorizedClient) { @@ -487,9 +542,11 @@ public Mono foo(@RegisteredOAuth2AuthorizedClient("my-app") OAuth2Author // ... } ---- +==== -then you can configure the scope using the `accessToken()` method: +Given a controller that inspects scopes, you can configure the scope by using the `accessToken()` method: +==== [source,java] ---- client @@ -498,22 +555,24 @@ client ) .get().uri("/endpoint").exchange(); ---- +==== [[webflux-testing-oauth2-client-registration]] ==== Additional Configurations -There are additional methods, too, for further configuring the authentication; it simply depends on what data your controller expects: +You can also use additional methods to further configure the authentication depending on what data your controller expects: -* `principalName(String)` - For configuring the resource owner name -* `clientRegistration(Consumer)` - For configuring the associated `ClientRegistration` -* `clientRegistration(ClientRegistration)` - For configuring the complete `ClientRegistration` +* `principalName(String)`; Configures the resource owner name +* `clientRegistration(Consumer)`: Configures the associated `ClientRegistration` +* `clientRegistration(ClientRegistration)`: Configures the complete `ClientRegistration` That last one is handy if you want to use a real `ClientRegistration` -For example, let's say that you are wanting to use one of your app's `ClientRegistration` definitions, as specified in your `application.yml`. +For example, suppose that you want to use one of your application's `ClientRegistration` definitions, as specified in your `application.yml`. In that case, your test can autowire the `ReactiveClientRegistrationRepository` and look up the one your test needs: +==== [source,java] ---- @Autowired @@ -527,32 +586,36 @@ client ) .get().uri("/exchange").exchange(); ---- +==== [[webflux-testing-jwt]] === Testing JWT Authentication -In order to make an authorized request on a resource server, you need a bearer token. -If your resource server is configured for JWTs, then this would mean that the bearer token needs to be signed and then encoded according to the JWT specification. -All of this can be quite daunting, especially when this isn't the focus of your test. +To make an authorized request on a resource server, you need a bearer token. +If your resource server is configured for JWTs, the bearer token needs to be signed and then encoded according to the JWT specification. +All of this can be quite daunting, especially when this is not the focus of your test. -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: +Fortunately, there are a number of simple ways in which you can overcome this difficulty and let your tests focus on authorization and not on representing bearer tokens. +We look at two of them in the next two subsections. ==== `mockJwt() WebTestClientConfigurer` -The first way is via a `WebTestClientConfigurer`. +The first way is with a `WebTestClientConfigurer`. The simplest of these would look something like this: +==== [source,java] ---- client .mutateWith(mockJwt()).get().uri("/endpoint").exchange(); ---- +==== -What this will do is create a mock `Jwt`, passing it correctly through any authentication APIs so that it's available for your authorization mechanisms to verify. +This example creates a mock `Jwt` and passes it through any authentication APIs so that it is available for your authorization mechanisms to verify. By default, the `JWT` that it creates has the following characteristics: +==== [source,json] ---- { @@ -563,9 +626,11 @@ By default, the `JWT` that it creates has the following characteristics: } } ---- +==== -And the resulting `Jwt`, were it tested, would pass in the following way: +The resulting `Jwt`, were it tested, would pass in the following way: +==== [source,java] ---- assertThat(jwt.getTokenValue()).isEqualTo("token"); @@ -574,11 +639,13 @@ assertThat(jwt.getSubject()).isEqualTo("sub"); GrantedAuthority authority = jwt.getAuthorities().iterator().next(); assertThat(authority.getAuthority()).isEqualTo("read"); ---- +==== -These values can, of course be configured. +Note that you configure these values. -Any headers or claims can be configured with their corresponding methods: +You can also configure any headers or claims with their corresponding methods: +==== [source,java] ---- client @@ -593,28 +660,34 @@ client .mutateWith(mockJwt().jwt(jwt -> jwt.claims(claims -> claims.remove("scope")))) .get().uri("/endpoint").exchange(); ---- +==== The `scope` and `scp` claims are processed the same way here as they are in a normal bearer token request. However, this can be overridden simply by providing the list of `GrantedAuthority` instances that you need for your test: +==== [source,java] ---- client .mutateWith(jwt().authorities(new SimpleGrantedAuthority("SCOPE_messages"))) .get().uri("/endpoint").exchange(); ---- +==== -Or, if you have a custom `Jwt` to `Collection` converter, you can also use that to derive the authorities: +Alternatively, if you have a custom `Jwt` to `Collection` converter, you can also use that to derive the authorities: +==== [source,java] ---- client .mutateWith(jwt().authorities(new MyConverter())) .get().uri("/endpoint").exchange(); ---- +==== -You can also specify a complete `Jwt`, for which `{security-api-url}org/springframework/security/oauth2/jwt/Jwt.Builder.html[Jwt.Builder]` comes quite handy: +You can also specify a complete `Jwt`, for which `{security-api-url}org/springframework/security/oauth2/jwt/Jwt.Builder.html[Jwt.Builder]` is quite handy: +==== [source,java] ---- Jwt jwt = Jwt.withTokenValue("token") @@ -626,12 +699,14 @@ client .mutateWith(mockJwt().jwt(jwt)) .get().uri("/endpoint").exchange(); ---- +==== -==== `authentication()` `WebTestClientConfigurer` +==== `authentication()` and `WebTestClientConfigurer` The second way is by using the `authentication()` `Mutator`. -Essentially, you can instantiate your own `JwtAuthenticationToken` and provide it in your test, like so: +You can instantiate your own `JwtAuthenticationToken` and provide it in your test: +==== [source,java] ---- Jwt jwt = Jwt.withTokenValue("token") @@ -645,8 +720,9 @@ client .mutateWith(authentication(token)) .get().uri("/endpoint").exchange(); ---- +==== -Note that as an alternative to these, you can also mock the `ReactiveJwtDecoder` bean itself with a `@MockBean` annotation. +Note that, as an alternative to these, you can also mock the `ReactiveJwtDecoder` bean itself with a `@MockBean` annotation. [[webflux-testing-opaque-token]] === Testing Opaque Token Authentication @@ -654,8 +730,9 @@ Note that as an alternative to these, you can also mock the `ReactiveJwtDecoder` Similar to <>, 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. -Let's say that we've got a controller that retrieves the authentication as a `BearerTokenAuthentication`: +Suppose you have a controller that retrieves the authentication as a `BearerTokenAuthentication`: +==== [source,java] ---- @GetMapping("/endpoint") @@ -663,42 +740,50 @@ public Mono foo(BearerTokenAuthentication authentication) { return Mono.just((String) authentication.getTokenAttributes("sub")); } ---- +==== -In that case, we can tell Spring Security to include a default `BearerTokenAuthentication` using the `SecurityMockServerConfigurers#opaqueToken` method, like so: +In that case, you can tell Spring Security to include a default `BearerTokenAuthentication` by using the `SecurityMockServerConfigurers#opaqueToken` method: +==== [source,java] ---- client .mutateWith(mockOpaqueToken()) .get().uri("/endpoint").exchange(); ---- +==== -What this will do is configure the associated `MockHttpServletRequest` with a `BearerTokenAuthentication` that includes a simple `OAuth2AuthenticatedPrincipal`, `Map` of attributes, and `Collection` of granted authorities. +This example configures the associated `MockHttpServletRequest` with a `BearerTokenAuthentication` that includes a simple `OAuth2AuthenticatedPrincipal`, a `Map` of attributes, and a `Collection` of granted authorities. -Specifically, it will include a `Map` with a key/value pair of `sub`/`user`: +Specifically, it includes a `Map` with a key/value pair of `sub`/`user`: +==== [source,json] ---- assertThat((String) token.getTokenAttributes().get("sub")).isEqualTo("user"); ---- +==== -and a `Collection` of authorities with just one authority, `SCOPE_read`: +It also includes a `Collection` of authorities with just one authority, `SCOPE_read`: +==== [source,json] ---- assertThat(token.getAuthorities()).hasSize(1); assertThat(token.getAuthorities()).containsExactly(new SimpleGrantedAuthority("SCOPE_read")); ---- +==== -Spring Security does the necessary work to make sure that the `BearerTokenAuthentication` instance is available for your controller methods. +Spring Security makes sure that the `BearerTokenAuthentication` instance is available for your controller methods. [[webflux-testing-opaque-token-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. -In this case, you can supply what granted authorities you need using the `authorities()` method: +In those cases, you can supply the granted authorities you need by using the `authorities()` method: +==== [source,java] ---- client @@ -707,15 +792,17 @@ client ) .get().uri("/endpoint").exchange(); ---- +==== [[webflux-testing-opaque-token-attributes]] ==== 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. +While granted authorities are quite common across all of Spring Security, we also have attributes in the case of OAuth 2.0. -Let's say, for example, that you've got a `user_id` attribute that indicates the user's id in your system. -You might access it like so in a controller: +Suppose, for example, that you have a `user_id` attribute that indicates the user's ID in your system. +You might access it as follows in a controller: +==== [source,java] ---- @GetMapping("/endpoint") @@ -724,9 +811,11 @@ public Mono foo(BearerTokenAuthentication authentication) { // ... } ---- +==== -In that case, you'd want to specify that attribute with the `attributes()` method: +In that case, you can specify that attribute with the `attributes()` method: +==== [source,java] ---- client @@ -735,21 +824,23 @@ client ) .get().uri("/endpoint").exchange(); ---- +==== [[webflux-testing-opaque-token-principal]] ==== Additional Configurations -There are additional methods, too, for further configuring the authentication; it simply depends on what data your controller expects. +You can also use additional methods to further configure the authentication, depending on what data your controller expects. -One such is `principal(OAuth2AuthenticatedPrincipal)`, which you can use to configure the complete `OAuth2AuthenticatedPrincipal` instance that underlies the `BearerTokenAuthentication` +One such method is `principal(OAuth2AuthenticatedPrincipal)`, which you can use to configure the complete `OAuth2AuthenticatedPrincipal` instance that underlies the `BearerTokenAuthentication`. -It's handy if you: -1. Have your own implementation of `OAuth2AuthenticatedPrincipal`, or -2. Want to specify a different principal name +It is handy if you: +* Have your own implementation of `OAuth2AuthenticatedPrincipal` or +* Want to specify a different principal name -For example, let's say that your authorization server sends the principal name in the `user_name` attribute instead of the `sub` attribute. +For example, suppose that your authorization server sends the principal name in the `user_name` attribute instead of the `sub` attribute. In that case, you can configure an `OAuth2AuthenticatedPrincipal` by hand: +==== [source,java] ---- Map attributes = Collections.singletonMap("user_name", "foo_user"); @@ -762,5 +853,6 @@ client .mutateWith(mockOpaqueToken().principal(principal)) .get().uri("/endpoint").exchange(); ---- +==== -Note that as an alternative to using `mockOpaqueToken()` test support, you can also mock the `OpaqueTokenIntrospector` bean itself with a `@MockBean` annotation. +Note that, as an alternative to using `mockOpaqueToken()` test support, you can also mock the `OpaqueTokenIntrospector` bean itself with a `@MockBean` annotation. diff --git a/docs/manual/src/docs/asciidoc/_includes/reactive/webclient.adoc b/docs/manual/src/docs/asciidoc/_includes/reactive/webclient.adoc index 181ac58b2cf..5de656a0e80 100644 --- a/docs/manual/src/docs/asciidoc/_includes/reactive/webclient.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/reactive/webclient.adoc @@ -1,13 +1,9 @@ = WebClient -[NOTE] -==== -The following documentation is for use within Reactive environments. -For Servlet environments, refer to <> environments. -==== - +NOTE: The documentation in this section is for use within Reactive environments. +For Servlet environments, see <>. -Spring Framework has built in support for setting a Bearer token. +Spring Framework has built-in support for setting a Bearer token: ==== .Java @@ -29,17 +25,17 @@ webClient.get() Spring Security builds on this support to provide additional benefits: -* Spring Security will automatically refresh expired tokens (if a refresh token is present) -* If an access token is requested and not present, Spring Security will automatically request the access token. -** For authorization_code this involves performing the redirect and then replaying the original request -** For client_credentials the token is simply requested and saved +* Spring Security automatically refreshes expired tokens (if a refresh token is present). +* If an access token is requested and not present, Spring Security automatically requests the access token. +** For `authorization_code`, this involves performing the redirect and then replaying the original request. +** For `client_credentials`, the token is requested and saved. * Support for the ability to transparently include the current OAuth token or explicitly select which token should be used. [[webclient-setup]] == WebClient OAuth2 Setup -The first step is ensuring to setup the `WebClient` correctly. -An example of setting up `WebClient` in a fully reactive environment can be found below: +The first step is ensuring that the `WebClient` is set up correctly. +The following example shows how to set up `WebClient` in a fully reactive environment: ==== .Java @@ -81,8 +77,8 @@ fun webClient(clientRegistrations: ReactiveClientRegistrationRepository, [[webclient-implicit]] == Implicit OAuth2AuthorizedClient -If we set `defaultOAuth2AuthorizedClient` to `true` in our setup and the user authenticated with oauth2Login (i.e. OIDC), then the current authentication is used to automatically provide the access token. -Alternatively, if we set `defaultClientRegistrationId` to a valid `ClientRegistration` id, that registration is used to provide the access token. +If we set `defaultOAuth2AuthorizedClient` to `true` in our setup and the user authenticated with `oauth2Login` (OIDC), the current authentication is used to automatically provide the access token. +Alternatively, if we set `defaultClientRegistrationId` to a valid `ClientRegistration` ID, that registration is used to provide the access token. This is convenient, but in environments where not all endpoints should get the access token, it is dangerous (you might provide the wrong access token to an endpoint). ==== @@ -110,8 +106,8 @@ val body: Mono = webClient [[webclient-explicit]] == Explicit OAuth2AuthorizedClient -The `OAuth2AuthorizedClient` can be explicitly provided by setting it on the requests attributes. -In the example below we resolve the `OAuth2AuthorizedClient` using Spring WebFlux or Spring MVC argument resolver support. +You can explicitly provide the `OAuth2AuthorizedClient` by setting it on the request attributes. +In the next example, we resolve the `OAuth2AuthorizedClient` by using Spring WebFlux or the Spring MVC argument resolver support. However, it does not matter how the `OAuth2AuthorizedClient` is resolved. ==== @@ -147,8 +143,8 @@ fun explicit(@RegisteredOAuth2AuthorizedClient("client-id") authorizedClient: OA [[webclient-clientregistrationid]] == clientRegistrationId -Alternatively, it is possible to specify the `clientRegistrationId` on the request attributes and the `WebClient` will attempt to lookup the `OAuth2AuthorizedClient`. -If it is not found, one will automatically be acquired. +Alternatively, you can specify the `clientRegistrationId` on the request attributes, and the `WebClient` tries to look up the `OAuth2AuthorizedClient`. +If it is not found, one is automatically acquired. ==== .Java diff --git a/docs/manual/src/docs/asciidoc/_includes/reactive/webflux.adoc b/docs/manual/src/docs/asciidoc/_includes/reactive/webflux.adoc index d6a5263a354..d181b8c1007 100644 --- a/docs/manual/src/docs/asciidoc/_includes/reactive/webflux.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/reactive/webflux.adoc @@ -2,7 +2,7 @@ = WebFlux Security Spring Security's WebFlux support relies on a `WebFilter` and works the same for Spring WebFlux and Spring WebFlux.Fn. -You can find a few sample applications that demonstrate the code below: +A few sample applications demonstrate the code: * Hello WebFlux {gh-samples-url}/boot/hellowebflux[hellowebflux] * Hello WebFlux.Fn {gh-samples-url}/boot/hellowebfluxfn[hellowebfluxfn] @@ -11,7 +11,7 @@ You can find a few sample applications that demonstrate the code below: == Minimal WebFlux Security Configuration -You can find a minimal WebFlux Security configuration below: +The following listing shows a minimal WebFlux Security configuration: .Minimal WebFlux Security Configuration ==== @@ -53,11 +53,11 @@ class HelloWebfluxSecurityConfig { ----- ==== -This configuration provides form and http basic authentication, sets up authorization to require an authenticated user for accessing any page, sets up a default log in page and a default log out page, sets up security related HTTP headers, CSRF protection, and more. +This configuration provides form and HTTP basic authentication, sets up authorization to require an authenticated user for accessing any page, sets up a default login page and a default logout page, sets up security related HTTP headers, adds CSRF protection, and more. == Explicit WebFlux Security Configuration -You can find an explicit version of the minimal WebFlux Security configuration below: +The following page shows an explicit version of the minimal WebFlux Security configuration: .Explicit WebFlux Security Configuration ==== @@ -123,17 +123,18 @@ class HelloWebfluxSecurityConfig { ==== This configuration explicitly sets up all the same things as our minimal configuration. -From here you can easily make the changes to the defaults. +From here, you can more easily make changes to the defaults. -You can find more examples of explicit configuration in unit tests, by searching https://github.com/spring-projects/spring-security/search?q=path%3Aconfig%2Fsrc%2Ftest%2F+EnableWebFluxSecurity[EnableWebFluxSecurity in the `config/src/test/` directory]. +You can find more examples of explicit configuration in unit tests, by searching for https://github.com/spring-projects/spring-security/search?q=path%3Aconfig%2Fsrc%2Ftest%2F+EnableWebFluxSecurity[`EnableWebFluxSecurity` in the `config/src/test/` directory]. [[jc-webflux-multiple-filter-chains]] === Multiple Chains Support -You can configure multiple `SecurityWebFilterChain` instances to separate configuration by `RequestMatcher` s. +You can configure multiple `SecurityWebFilterChain` instances to separate configuration by `RequestMatcher` instances. -For example, you can isolate configuration for URLs that start with `/api`, like so: +For example, you can isolate configuration for URLs that start with `/api`: +==== [source,java] ---- @Configuration @@ -171,15 +172,15 @@ static class MultiSecurityHttpConfig { } ---- -<1> Configure a `SecurityWebFilterChain` with an `@Order` to specify which `SecurityWebFilterChain` Spring Security should consider first -<2> Use `PathPatternParserServerWebExchangeMatcher` to state that this `SecurityWebFilterChain` will only apply to URL paths that start with `/api/` -<3> Specify the authentication mechanisms that will be used for `/api/**` endpoints -<4> Create another instance of `SecurityWebFilterChain` with lower precedence to match all other URLs -<5> Specify the authentication mechanisms that will be used for the rest of the application - -Spring Security will select one `SecurityWebFilterChain` `@Bean` for each request. -It will match the requests in order by the `securityMatcher` definition. +<1> Configure a `SecurityWebFilterChain` with an `@Order` to specify which `SecurityWebFilterChain` Spring Security should consider first. +<2> Use `PathPatternParserServerWebExchangeMatcher` to state that this `SecurityWebFilterChain` applies only to URL paths that start with `/api/`. +<3> Specify the authentication mechanisms that is used for `/api/**` endpoints. +<4> Create another instance of `SecurityWebFilterChain` with lower precedence to match all other URLs. +<5> Specify the authentication mechanisms that is used for the rest of the application. +==== -In this case, that means that if the URL path starts with `/api`, then Spring Security will use `apiHttpSecurity`. -If the URL does not start with `/api` then Spring Security will default to `webHttpSecurity`, which has an implied `securityMatcher` that matches any request. +Spring Security selects one `SecurityWebFilterChain` `@Bean` for each request. +It matches the requests in order by the `securityMatcher` definition. +In this case, that means that, if the URL path starts with `/api`, Spring Security uses `apiHttpSecurity`. +If the URL does not start with `/api`, Spring Security defaults to `webHttpSecurity`, which has an implied `securityMatcher` that matches any request. diff --git a/docs/manual/src/docs/asciidoc/_includes/reactive/x509.adoc b/docs/manual/src/docs/asciidoc/_includes/reactive/x509.adoc index 694b905093a..515ae7533ea 100644 --- a/docs/manual/src/docs/asciidoc/_includes/reactive/x509.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/reactive/x509.adoc @@ -1,9 +1,11 @@ [[reactive-x509]] = Reactive X.509 Authentication -Similar to <>, reactive x509 authentication filter allows extracting an authentication token from a certificate provided by a client. +Similar to <>, the reactive x509 authentication filter allows extracting an authentication token from a certificate provided by a client. -Below is an example of a reactive x509 security configuration: +The folloiwng example shows a reactive x509 security configuration: + +==== [source,java] ---- @Bean @@ -16,11 +18,13 @@ public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) { return http.build(); } ---- +==== -In the configuration above, when neither `principalExtractor` nor `authenticationManager` is provided defaults will be used. The default principal extractor is `SubjectDnX509PrincipalExtractor` which extracts the CN (common name) field from a certificate provided by a client. The default authentication manager is `ReactivePreAuthenticatedAuthenticationManager` which performs user account validation, checking that user account with a name extracted by `principalExtractor` exists and it is not locked, disabled, or expired. +In the preceding configuration, when neither `principalExtractor` nor `authenticationManager` is provided, defaults are used. The default principal extractor is `SubjectDnX509PrincipalExtractor`, which extracts the CN (common name) field from a certificate provided by a client. The default authentication manager is `ReactivePreAuthenticatedAuthenticationManager`, which performs user account validation, checking that a user account with a name extracted by `principalExtractor` exists and that it is not locked, disabled, or expired. -The next example demonstrates how these defaults can be overridden. +The following example demonstrates how these defaults can be overridden: +==== [source,java] ---- @Bean @@ -46,7 +50,8 @@ public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) { return http.build(); } ---- +==== -In this example, a username is extracted from the OU field of a client certificate instead of CN, and account lookup using `ReactiveUserDetailsService` is not performed at all. Instead, if the provided certificate issued to an OU named "Trusted Org Unit", a request will be authenticated. +In the previous example, a username is extracted from the OU field of a client certificate instead of CN, and account lookup using `ReactiveUserDetailsService` is not performed at all. Instead, if the provided certificate issued to an OU named "`Trusted Org Unit`", a request is authenticated. For an example of configuring Netty and `WebClient` or `curl` command-line tool to use mutual TLS and enable X.509 authentication, please refer to https://github.com/spring-projects/spring-security-samples/tree/main/servlet/java-configuration/authentication/x509. diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/appendix/database-schema.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/appendix/database-schema.adoc index ab840e131fb..8998047ec2c 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/appendix/database-schema.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/appendix/database-schema.adoc @@ -1,19 +1,19 @@ [[appendix-schema]] = Security Database Schema -There are various database schema used by the framework and this appendix provides a single reference point to them all. -You only need to provide the tables for the areas of functionality you require. +The framework uses various database schema. This appendix provides a single reference point to them all. +You need only provide the tables for the areas of functionality you require. DDL statements are given for the HSQLDB database. -You can use these as a guideline for defining the schema for the database you are using. +You can use these as a guideline for defining the schema for the database you use. == User Schema -The standard JDBC implementation of the `UserDetailsService` (`JdbcDaoImpl`) requires tables to load the password, account status (enabled or disabled) and a list of authorities (roles) for the user. -You will need to adjust this schema to match the database dialect you are using. +The standard JDBC implementation of the `UserDetailsService` (`JdbcDaoImpl`) requires tables to load the password, account status (enabled or disabled), and a list of authorities (roles) for the user. +You need to adjust this schema to match the database dialect you use: +==== [source] ---- - create table users( username varchar_ignorecase(50) not null primary key, password varchar_ignorecase(50) not null, @@ -27,8 +27,13 @@ create table authorities ( ); create unique index ix_auth_username on authorities (username,authority); ---- +==== === For Oracle database + +The following listing shows the Oracle variant of the schema creation commands: + +==== [source] ---- CREATE TABLE USERS ( @@ -45,15 +50,15 @@ CREATE TABLE AUTHORITIES ( ALTER TABLE AUTHORITIES ADD CONSTRAINT AUTHORITIES_UNIQUE UNIQUE (USERNAME, AUTHORITY); ALTER TABLE AUTHORITIES ADD CONSTRAINT AUTHORITIES_FK1 FOREIGN KEY (USERNAME) REFERENCES USERS (USERNAME) ENABLE; ---- +==== === Group Authorities Spring Security 2.0 introduced support for group authorities in `JdbcDaoImpl`. -The table structure if groups are enabled is as follows. -You will need to adjust this schema to match the database dialect you are using. +You need to adjust the following schema to match the database dialect you use: +==== [source] ---- - create table groups ( id bigint generated by default as identity(start with 0) primary key, group_name varchar_ignorecase(50) not null @@ -72,16 +77,18 @@ create table group_members ( constraint fk_group_members_group foreign key(group_id) references groups(id) ); ---- +==== -Remember that these tables are only required if you are using the provided JDBC `UserDetailsService` implementation. -If you write your own or choose to implement `AuthenticationProvider` without a `UserDetailsService`, then you have complete freedom over how you store the data, as long as the interface contract is satisfied. +Remember that these tables are required only if you us the provided JDBC `UserDetailsService` implementation. +If you write your own or choose to implement `AuthenticationProvider` without a `UserDetailsService`, you have complete freedom over how you store the data, as long as the interface contract is satisfied. == Persistent Login (Remember-Me) Schema -This table is used to store data used by the more secure <> remember-me implementation. -If you are using `JdbcTokenRepositoryImpl` either directly or through the namespace, then you will need this table. -Remember to adjust this schema to match the database dialect you are using. +This table is used to store the data used by the more secure <> remember-me implementation. +If you use `JdbcTokenRepositoryImpl` either directly or through the namespace, you need this table. +Remember to adjust this schema to match the database dialect you use: +==== [source] ---- @@ -93,21 +100,22 @@ create table persistent_logins ( ); ---- +==== [[dbschema-acl]] == ACL Schema -There are four tables used by the Spring Security <> implementation. +The Spring Security <> implementation uses four tables. -. `acl_sid` stores the security identities recognised by the ACL system. -These can be unique principals or authorities which may apply to multiple principals. -. `acl_class` defines the domain object types to which ACLs apply. +* `acl_sid` stores the security identities recognised by the ACL system. +These can be unique principals or authorities, which may apply to multiple principals. +* `acl_class` defines the domain object types to which ACLs apply. The `class` column stores the Java class name of the object. -. `acl_object_identity` stores the object identity definitions of specific domain objects. -. `acl_entry` stores the ACL permissions which apply to a specific object identity and security identity. +* `acl_object_identity` stores the object identity definitions of specific domain objects. +* `acl_entry` stores the ACL permissions, each of which applies to a specific object identity and security identity. -It is assumed that the database will auto-generate the primary keys for each of the identities. +We assume that the database auto-generates the primary keys for each of the identities. The `JdbcMutableAclService` has to be able to retrieve these when it has created a new row in the `acl_sid` or `acl_class` tables. -It has two properties which define the SQL needed to retrieve these values `classIdentityQuery` and `sidIdentityQuery`. +It has two properties that define the SQL needed to retrieve these values `classIdentityQuery` and `sidIdentityQuery`. Both of these default to `call identity()` The ACL artifact JAR contains files for creating the ACL schema in HyperSQL (HSQLDB), PostgreSQL, MySQL/MariaDB, Microsoft SQL Server, and Oracle Database. @@ -116,9 +124,9 @@ These schemas are also demonstrated in the following sections. === HyperSQL The default schema works with the embedded HSQLDB database that is used in unit tests within the framework. +==== [source,ddl] ---- - create table acl_sid( id bigint generated by default as identity(start with 100) not null primary key, principal boolean not null, @@ -159,8 +167,16 @@ create table acl_entry( constraint foreign_fk_5 foreign key(sid) references acl_sid(id) ); ---- +==== === PostgreSQL + +For PostgreSQL, you have to set the `classIdentityQuery` and `sidIdentityQuery` properties of `JdbcMutableAclService` to the following values, respectively: + +* `select currval(pg_get_serial_sequence('acl_class', 'id'))` +* `select currval(pg_get_serial_sequence('acl_sid', 'id'))` + +==== [source,ddl] ---- create table acl_sid( @@ -203,13 +219,11 @@ create table acl_entry( constraint foreign_fk_5 foreign key(sid) references acl_sid(id) ); ---- - -You will have to set the `classIdentityQuery` and `sidIdentityQuery` properties of `JdbcMutableAclService` to the following values, respectively: - -* `select currval(pg_get_serial_sequence('acl_class', 'id'))` -* `select currval(pg_get_serial_sequence('acl_sid', 'id'))` +==== === MySQL and MariaDB + +==== [source,ddl] ---- CREATE TABLE acl_sid ( @@ -252,8 +266,11 @@ CREATE TABLE acl_entry ( CONSTRAINT fk_acl_entry_acl FOREIGN KEY (sid) REFERENCES acl_sid (id) ) ENGINE=InnoDB; ---- +==== === Microsoft SQL Server + +==== [source,ddl] ---- CREATE TABLE acl_sid ( @@ -296,8 +313,10 @@ CREATE TABLE acl_entry ( CONSTRAINT fk_acl_entry_acl FOREIGN KEY (sid) REFERENCES acl_sid (id) ); ---- - +==== === Oracle Database + +==== [source,ddl] ---- CREATE TABLE ACL_SID ( @@ -363,13 +382,14 @@ BEGIN SELECT ACL_ENTRY_SQ.NEXTVAL INTO :NEW.ID FROM DUAL; END; ---- - +==== [[dbschema-oauth2-client]] == OAuth 2.0 Client Schema -The JDBC implementation of <> (`JdbcOAuth2AuthorizedClientService`) requires a table for persisting `OAuth2AuthorizedClient`(s). -You will need to adjust this schema to match the database dialect you are using. +The JDBC implementation of <> (`JdbcOAuth2AuthorizedClientService`) requires a table for persisting `OAuth2AuthorizedClient` instances. +You need to adjust this schema to match the database dialect you use. +==== [source,ddl] ---- CREATE TABLE oauth2_authorized_client ( @@ -386,3 +406,4 @@ CREATE TABLE oauth2_authorized_client ( PRIMARY KEY (client_registration_id, principal_name) ); ---- +==== diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/appendix/faq.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/appendix/faq.adoc index 196c3992fe5..e3481e3ab0f 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/appendix/faq.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/appendix/faq.adoc @@ -1,6 +1,8 @@ [[appendix-faq]] == Spring Security FAQ +This FAQ has the following sections: + * <> * <> * <> @@ -9,57 +11,59 @@ [[appendix-faq-general-questions]] === General Questions -. <> -. <> -. <> -. <> +This FAQ answers the following general questions: + +* <> +* <> +* <> +* <> [[appendix-faq-other-concerns]] -==== Will Spring Security take care of all my application security requirements? +==== Can 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. -Check out the https://www.owasp.org/[OWASP web site] for information on the major issues facing web application developers and the countermeasures you can use against them. +Spring Security provides you with a 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 with which you should be familiar, preferably before you start development so that you can design and code with them in mind from the beginning. +Check out the https://www.owasp.org/[OWASP web site] for information on the major issues that face web application developers and the countermeasures you can use against them. [[appendix-faq-web-xml]] -==== Why not just use web.xml security? +==== Why Not 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: +Suppose you are developing an enterprise application based on Spring. +You typically need to address four security concerns : authentication, web request security, service layer security (your methods that implement business logic), and domain object instance security (different domain objects can have different permissions). With these typical requirements in mind, we have the following considerations: -. __Authentication__: The servlet specification provides an approach to authentication. -However, you will need to configure the container to perform authentication which typically requires editing of container-specific "realm" settings. -This makes a non-portable configuration, and if you need to write an actual Java class to implement the container's authentication interface, it becomes even more non-portable. -With Spring Security you achieve complete portability - right down to the WAR level. +* _Authentication_: The servlet specification provides an approach to authentication. +However, you need to configure the container to perform authentication, which typically requires editing of container-specific "`realm`" settings. +This makes a non-portable configuration. Also, if you need to write an actual Java class to implement the container's authentication interface, it becomes even more non-portable. +With Spring Security, you achieve complete portability -- right down to the WAR level. Also, Spring Security offers a choice of production-proven authentication providers and mechanisms, meaning you can switch your authentication approaches at deployment time. This is particularly valuable for software vendors writing products that need to work in an unknown target environment. -. __Web request security:__ The servlet specification provides an approach to secure your request URIs. -However, these URIs can only be expressed in the servlet specification's own limited URI path format. +* _Web request security:_ The servlet specification provides an approach to secure your request URIs. +However, these URIs can be expressed only in the servlet specification's own limited URI path format. Spring Security provides a far more comprehensive approach. -For instance, you can use Ant paths or regular expressions, you can consider parts of the URI other than simply the requested page (e.g. -you can consider HTTP GET parameters) and you can implement your own runtime source of configuration data. -This means your web request security can be dynamically changed during the actual execution of your webapp. +For instance, you can use Ant paths or regular expressions, you can consider parts of the URI other than simply the requested page (for example, +you can consider HTTP GET parameters), and you can implement your own runtime source of configuration data. +This means that you can dynamically change your web request security during the actual execution of your web application. -. __Service layer and domain object security:__ The absence of support in the servlet specification for services layer security or domain object instance security represent serious limitations for multi-tiered applications. -Typically developers either ignore these requirements, or implement security logic within their MVC controller code (or even worse, inside the views). There are serious disadvantages with this approach: +* _Service layer and domain object security:_ The absence of support in the servlet specification for services layer security or domain object instance security represents serious limitations for multi-tiered applications. +Typically, developers either ignore these requirements or implement security logic within their MVC controller code (or, even worse, inside the views). There are serious disadvantages with this approach: -.. __Separation of concerns:__ Authorization is a crosscutting concern and should be implemented as such. -MVC controllers or views implementing authorization code makes it more difficult to test both the controller and authorization logic, more difficult to debug, and will often lead to code duplication. +** _Separation of concerns:_ Authorization is a crosscutting concern and should be implemented as such. +MVC controllers or views that implement authorization code makes it more difficult to test both the controller and the authorization logic, is more difficult to debug, and often leads to code duplication. -.. __Support for rich clients and web services:__ If an additional client type must ultimately be supported, any authorization code embedded within the web layer is non-reusable. -It should be considered that Spring remoting exporters only export service layer beans (not MVC controllers). As such authorization logic needs to be located in the services layer to support a multitude of client types. +** _Support for rich clients and web services:_ If an additional client type must ultimately be supported, any authorization code embedded within the web layer is non-reusable. +It should be considered that Spring remoting exporters export only service layer beans (not MVC controllers). As a result, authorization logic needs to be located in the services layer to support a multitude of client types. -.. __Layering issues:__ An MVC controller or view is simply the incorrect architectural layer to implement authorization decisions concerning services layer methods or domain object instances. -Whilst the Principal may be passed to the services layer to enable it to make the authorization decision, doing so would introduce an additional argument on every services layer method. -A more elegant approach is to use a ThreadLocal to hold the Principal, although this would likely increase development time to a point where it would become more economical (on a cost-benefit basis) to simply use a dedicated security framework. +** _Layering issues:_ An MVC controller or view is the incorrect architectural layer in which to implement authorization decisions concerning services layer methods or domain object instances. +While the principal may be passed to the services layer to enable it to make the authorization decision, doing so would introduce an additional argument on every services layer method. +A more elegant approach is to use a `ThreadLocal` to hold the principal, although this would likely increase development time to a point where it would become more economical (on a cost-benefit basis) to use a dedicated security framework. -.. __Authorisation code quality:__ It is often said of web frameworks that they "make it easier to do the right things, and harder to do the wrong things". Security frameworks are the same, because they are designed in an abstract manner for a wide range of purposes. -Writing your own authorization code from scratch does not provide the "design check" a framework would offer, and in-house authorization code will typically lack the improvements that emerge from widespread deployment, peer review and new versions. +** _Authorisation code quality:_ It is often said of web frameworks that they "`make it easier to do the right things, and harder to do the wrong things`". Security frameworks are the same, because they are designed in an abstract manner for a wide range of purposes. +Writing your own authorization code from scratch does not provide the "`design check`" a framework would offer, and in-house authorization code typically lacks the improvements that emerge from widespread deployment, peer review, and new versions. -For simple applications, servlet specification security may just be enough. +For simple applications, servlet specification security may be enough. Although when considered within the context of web container portability, configuration requirements, limited web request security flexibility, and non-existent services layer and domain object instance security, it becomes clear why developers often look to alternative solutions. @@ -67,138 +71,141 @@ Although when considered within the context of web container portability, config ==== 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. +Ideally, you should use the latest release versions to avoid problems. Spring Security 2.0.x requires a minimum JDK version of 1.4 and is built against Spring 2.0.x. -It should also be compatible with applications using Spring 2.5.x. +It should also be compatible with applications that use 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. -What could be wrong? +==== I have a complex scenario. What could be wrong? + +(This answer address complex scenarios in general by dealing with a particular scenario.) -Or substitute an alternative complex scenario... +Suppose you are new to Spring Security and 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). You have copied some configuration files but have found that it does not work. What could be wrong? -Realistically, you need an understanding of the technologies you are intending to use before you can successfully build applications with them. +You need an understanding of the technologies you intend to use before you can successfully build applications with them. Security is complicated. -Setting up a simple configuration using a login form and some hard-coded users using Spring Security's namespace is reasonably straightforward. +Setting up a simple configuration by using a login form and some hard-coded users with Spring Security's namespace is reasonably straightforward. Moving to using a backed JDBC database is also easy enough. -But if you try and jump straight to a complicated deployment scenario like this you will almost certainly be frustrated. -There is a big jump in the learning curve required to set up systems like CAS, configure LDAP servers and install SSL certificates properly. +However, if you try to jump straight to a complicated deployment scenario like this scenario, you are almost certain to be frustrated. +There is a big jump in the learning curve required to set up systems such as CAS, configure LDAP servers, and install SSL certificates properly. So you need to take things one step at a time. -From a Spring Security perspective, the first thing you should do is follow the "Getting Started" guide on the web site. +From a Spring Security perspective, the first thing you should do is follow the "`Getting Started`" guide on the web site. This will take you through a series of steps to get up and running and get some idea of how the framework operates. -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. +If you use other technologies with which you are not familiar, 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 -. Authentication -.. <> -.. <> -.. <> -.. <> -.. <> -.. <> -. Session Management -.. <> -.. <> -.. <> -.. <> -.. <> -. Miscellaneous -.. <> -.. <> -.. <> -.. <> -.. <> +This section addresses the most common problems that people encounter when using Spring Security: + +* Authentication +** <> +** <> +** <> +** <> +** <> +** <> +* Session Management +** <> +** <> +** <> +** <> +** <> +* Miscellaneous +** <> +** <> +** <> +** <> +** <> [[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 is 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. +It does not say why, as it is good practice to avoid giving details that might help an attacker guess account names or passwords. -This also means that if you ask this question in the forum, you will not get an answer unless you provide additional information. -As with any issue you should check the output from the debug log, note any exception stacktraces and related messages. -Step through the code in a debugger to see where the authentication fails and why. -Write a test case which exercises your authentication configuration outside of the application. +This also means that, if you ask this question online, you should not expect an answer unless you provide additional information. +As with any issue, you should check the output from the debug log and note any exception stacktraces and related messages. +You should step through the code in a debugger to see where the authentication fails and why. +You should also write a test case which exercises your authentication configuration outside of the application. More often than not, the failure is due to a difference in the password data stored in a database and that entered by the user. -If you are using hashed passwords, make sure the value stored in your database is __exactly__ the same as the value produced by the `PasswordEncoder` configured in your application. +If you use hashed passwords, make sure the value stored in your database is _exactly_ the same as the value produced by the `PasswordEncoder` configured in your application. [[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 is 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. +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`. -If your AccessDecisionManager includes an AuthenticatedVoter, you can use the attribute "IS_AUTHENTICATED_ANONYMOUSLY". This is automatically available if you are using the standard namespace configuration setup. +If your `AccessDecisionManager` includes an `AuthenticatedVoter`, you can use the `IS_AUTHENTICATED_ANONYMOUSLY` attribute. This is automatically available if you use the standard namespace configuration setup. -From Spring Security 2.0.1 onwards, when you are using namespace-based configuration, a check will be made on loading the application context and a warning message logged if your login page appears to be protected. +From Spring Security 2.0.1 onwards, when you use namespace-based configuration, a check is made on loading the application context and a warning message logged if your login page appears to be protected. [[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 a message of "Access is denied (user is anonymous);". What is wrong? -This is a debug level message which occurs the first time an anonymous user attempts to access a protected resource. +The following listing shows a debug level message that occurs the first time an anonymous user attempts to access a protected resource: +==== [source] ---- - DEBUG [ExceptionTranslationFilter] - Access is denied (user is anonymous); redirecting to authentication entry point org.springframework.security.AccessDeniedException: Access is denied at org.springframework.security.vote.AffirmativeBased.decide(AffirmativeBased.java:68) at org.springframework.security.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:262) - ---- +==== -It is normal and shouldn't be anything to worry about. +It is normal and is not something 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 have 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. +The most common reason for this is that your browser has cached the page and you are seeing a copy that is being retrieved from the browsers cache. +Verify this by checking whether the browser is actually sending the request (check your server access logs and 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. 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 a message of "An Authentication object was not found in the SecurityContext". What is 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. +The following listing shows another debug-level message that occurs the first time an anonymous user attempts to access a protected resource. However, this listing shows what happens when you do not have an `AnonymousAuthenticationFilter` in your filter chain configuration: +==== [source] ---- - DEBUG [ExceptionTranslationFilter] - Authentication exception occurred; redirecting to authentication entry point org.springframework.security.AuthenticationCredentialsNotFoundException: An Authentication object was not found in the SecurityContext at org.springframework.security.intercept.AbstractSecurityInterceptor.credentialsNotFound(AbstractSecurityInterceptor.java:342) at org.springframework.security.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:254) ---- +==== -It is normal and shouldn't be anything to worry about. +It is normal and is not something to worry about. [[appendix-faq-ldap-authentication]] -==== I can't get LDAP authentication to work. -What's wrong with my configuration? +==== I cannot get LDAP authentication to work. What is wrong with my configuration? -Note that the permissions for an LDAP directory often do not allow you to read the password for a user. -Hence it is often not possible to use the <> where Spring Security compares the stored password with the one submitted by the user. -The most common approach is to use LDAP "bind", which is one of the operations supported by https://en.wikipedia.org/wiki/Lightweight_Directory_Access_Protocol[the LDAP protocol]. With this approach, Spring Security validates the password by attempting to authenticate to the directory as the user. +Note that the permissions for an LDAP directory often do not let you read the password for a user. +Hence, it is often not possible to use the <> where Spring Security compares the stored password with the one submitted by the user. +The most common approach is to use LDAP "`bind`", which is one of the operations supported by https://en.wikipedia.org/wiki/Lightweight_Directory_Access_Protocol[the LDAP protocol]. With this approach, Spring Security validates the password by trying to authenticate to the directory as the user. The most common problem with LDAP authentication is a lack of knowledge of the directory server tree structure and configuration. -This will be different in different companies, so you have to find it out yourself. -Before adding a Spring Security LDAP configuration to an application, it's a good idea to write a simple test using standard Java LDAP code (without Spring Security involved), and make sure you can get that to work first. +This differs from one company to another, so you have to find it out yourself. +Before adding a Spring Security LDAP configuration to an application, you should write a simple test by using standard Java LDAP code (without Spring Security involved) and make sure you can get that to work first. For example, to authenticate a user, you could use the following code: +==== [source,java] ---- - @Test public void ldapAuthenticationIsSuccessful() throws Exception { Hashtable env = new Hashtable(); @@ -211,125 +218,126 @@ public void ldapAuthenticationIsSuccessful() throws Exception { InitialLdapContext ctx = new InitialLdapContext(env, null); } - ---- +==== ==== Session Management -Session management issues are a common source of forum questions. +Session management issues are a common source of 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. -You should also understand the difference between secure and non-secure cookies and the implications of using HTTP/HTTPS and switching between the two. +You should also understand the difference between secure and non-secure cookies and the implications of using HTTP and HTTPS and switching between the two. Spring Security has nothing to do with maintaining the session or providing session identifiers. 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. -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? +==== I am using Spring Security's concurrent session control to prevent users from logging in more than once at the same time. When I open another browser window after logging in, it does not stop me from logging in again. Why can I log in more than once? Browsers generally maintain a single session per browser instance. You cannot have two separate sessions at once. -So if you log in again in another window or tab you are just reauthenticating in the same session. -The server doesn't know anything about tabs, windows or browser instances. -All it sees are HTTP requests and it ties those to a particular session according to the value of the JSESSIONID cookie that they contain. -When a user authenticates during a session, Spring Security's concurrent session control checks the number of __other authenticated sessions__ that they have. -If they are already authenticated with the same session, then re-authenticating will have no effect. +So, if you log in again in another window or tab, you are reauthenticating in the same session. +The server does not know anything about tabs, windows, or browser instances. +All it sees are HTTP requests, and it ties those to a particular session according to the value of the `JSESSIONID` cookie that they contain. +When a user authenticates during a session, Spring Security's concurrent session control checks the number of _other authenticated sessions_ that they have. +If they are already authenticated with the same session, re-authenticating has no effect. [[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. -If you're using an older container, Spring Security invalidates the existing session, creates a new session, and transfers the session data to the new session. -Changing the session identifier in this manner prevents"session-fixation" attacks. +If you us a Servlet 3.1 or newer container, the session ID is simply changed. +If you use an older container, Spring Security invalidates the existing session, creates a new session, and transfers the session data to the new session. +Changing the session identifier in this manner prevents "`session-fixation`" attacks. 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. -It doesn't work - I just end up back at the login page after authenticating. +==== I use Tomcat (or some other servlet container) and have enabled HTTPS for my login page, switching back to HTTP afterwards. It does not work. I 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. +This happens because sessions created under HTTPS, for which the session cookie is marked as "`secure`", cannot subsequently be used under HTTP. The browser does not send the cookie back to the server, and any session state (including the security context information) is lost. Starting a session in HTTP first should work, as the session cookie is not marked as secure. However, Spring Security's https://docs.spring.io/spring-security/site/docs/3.1.x/reference/springsecurity-single.html#ns-session-fixation[Session Fixation Protection] can interfere with this because it results in a new session ID cookie being sent back to the user's browser, usually with the secure flag. -To get around this, you can disable session fixation protection, but in newer Servlet containers you can also configure session cookies to never use the secure flag. -Note that switching between HTTP and HTTPS is not a good idea in general, as any application which uses HTTP at all is vulnerable to man-in-the-middle attacks. +To get around this, you can disable session fixation protection. However, in newer Servlet containers, you can also configure session cookies to never use the secure flag. + +IMPORTANT: Switching between HTTP and HTTPS is not a good idea in general, as any application that uses HTTP at all is vulnerable to man-in-the-middle attacks. To be truly secure, the user should begin accessing your site in HTTPS and continue using it until they log out. Even clicking on an HTTPS link from a page accessed over HTTP is potentially risky. -If you need more convincing, check out a tool like https://www.thoughtcrime.org/software/sslstrip/[sslstrip]. +If you need more convincing, check out a tool such as https://www.thoughtcrime.org/software/sslstrip/[sslstrip]. -==== I'm not switching between HTTP and HTTPS but my session is still getting lost +==== I am not switching between HTTP and HTTPS, but my session is still lost. What happened? -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. +Sessions are maintained either by exchanging a session cookie or by adding a `jsessionid` parameter to URLs (this happens automatically if you use 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`, the session is 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 am trying to use the concurrent session-control support, but it does not let me log back in, even if I am sure I have logged out and have not exceeded the allowed sessions. What is wrong? -Make sure you have added the listener to your web.xml file. +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. -Without it, the session information will not be removed from the registry. - +Without it, the session information is not removed from the registry. +The following example adds a listener in a `web.xml` file: +==== [source,xml] ---- org.springframework.security.web.session.HttpSessionEventPublisher ---- +==== [[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 creates a session somewhere, even though I have configured it not to, by setting the create-session attribute to never. What is wrong? -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. -To prevent a JSP from creating a session, add the directive `<%@ page session="false" %>` to the top of the page. +This usually means that the user's application is creating a session somewhere but that they are not aware of it. +The most common culprit is a JSP. Many people are not aware that JSPs create sessions by default. +To prevent a JSP from creating a session, add the `<%@ page session="false" %>` directive to the top of the page. -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. +If you have 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 is to add a `javax.servlet.http.HttpSessionListener`, which calls `Thread.dumpStack()` in the `sessionCreated` method, to your application. [[appendix-faq-forbidden-csrf]] -==== I get a 403 Forbidden when performing a POST +==== I get a 403 Forbidden when performing a POST. What is wrong? -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). +If an HTTP 403 Forbidden error is returned for HTTP POST but it works for HTTP GET, 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 (the latter is 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 am forwarding a request to another URL by using the RequestDispatcher, but my security constraints are not 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 element, a child element of . +By default, filters are not applied to forwards or includes. +If you really want the security filters to be applied to forwards or includes, you have to configure these explicitly in your `web.xml` file by using the `` element, which is a child element of the `` element. [[appendix-faq-method-security-in-web-context]] -==== I have added Spring Security's 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 element to my application context, but, if I add security annotations to my Spring MVC controller beans (Struts actions etc.), they do not seem to have an effect. Why not? -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. -The beans in these "child" contexts are not visible to the rest of the application. -The"parent" application context is loaded by the `ContextLoaderListener` you define in your `web.xml` and is visible to all the child contexts. -This parent context is usually where you define your security configuration, including the `` element). As a result any security constraints applied to methods in these web beans will not be enforced, since the beans cannot be seen from the `DispatcherServlet` context. -You need to either move the `` declaration to the web context or moved the beans you want secured into the main application context. +In a Spring web application, the application context that 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 the `web.xml` file. An application can have multiple `DispatcherServlet` instances, each with its own isolated application context. +The beans in these "`child`" contexts are not visible to the rest of the application. +The "`parent`" application context is loaded by the `ContextLoaderListener` you define in your `web.xml` file and is visible to all the child contexts. +This parent context is usually where you define your security configuration, including the `` element. As a result, any security constraints applied to methods in these web beans are not enforced, since the beans cannot be seen from the `DispatcherServlet` context. +You need to either move the `` declaration to the web context or move the beans you want secured into the main application context. -Generally we would recommend applying method security at the service layer rather than on individual web controllers. +Generally, we recommend applying method security at the service layer rather than on individual web controllers. [[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. -Why can't I see the user information? +==== 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 I not see the user information? -If you have excluded the request from the security filter chain using the attribute `filters='none'` in the `` element that matches the URL pattern, then the `SecurityContextHolder` will not be populated for that request. +If you have excluded the request from the security filter chain by using the `filters='none'` attribute in the `` element that matches the URL pattern, the `SecurityContextHolder` is not populated for that request. Check the debug log to see whether the request is passing through the filter chain. -(You are reading the debug log, right?). +(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 does not respect my method security annotations when using the URL attribute. Why not? -Method security will not hide links when using the `url` attribute in `` 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. +Method security does not hide links when using the `url` attribute in ``, because we cannot readily reverse engineer what URL is mapped to what controller endpoint. We are limited because controllers can rely on headers, the current user, and other details to determine what method to invoke. [[appendix-faq-architecture]] === Spring Security Architecture Questions +This section addresses common Spring Security architecture questions: + . <> . <> . <> @@ -342,56 +350,56 @@ Method security will not hide links when using the `url` attribute in `> that lists the first-level dependencies for each Spring Security module, with some information on whether they are optional and when they are required. -If you are building your project with maven, then adding the appropriate Spring Security modules as dependencies to your pom.xml will automatically pull in the core jars that the framework requires. -Any which are marked as "optional" in the Spring Security POM files will have to be added to your own pom.xml file if you need them. +If you build your project with Maven, adding the appropriate Spring Security modules as dependencies to your `pom.xml` file automatically pulls in the core jars that the framework requires. +Any that are marked as "`optional`" in the Spring Security `pom.xml` files have to be added to your own `pom.xml` file if you need them. [[appendix-faq-apacheds-deps]] ==== 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: +If you use Maven, you need to add the following to your `pom.xml` file dependencies: +==== [source] ---- - org.apache.directory.server apacheds-core @@ -404,8 +412,8 @@ If you are using Maven, you need to add the following to your pom dependencies: 1.5.5 runtime - ---- +==== The other required jars should be pulled in transitively. @@ -413,16 +421,18 @@ The other required jars should be pulled in transitively. ==== 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. +It has no function other than to load that data for use by other components within the framework. It is not responsible for authenticating the user. -Authenticating a user with a username/password combination is most commonly performed by the `DaoAuthenticationProvider`, which is injected with a `UserDetailsService` to allow it to load the password (and other data) for a user in order to compare it with the submitted value. -Note that if you are using LDAP, <>. +Authenticating a user with a username and password combination is most commonly performed by the `DaoAuthenticationProvider`, which is injected with a `UserDetailsService` to let it to load the password (and other data) for a user, to compare it with the submitted value. +Note that, if you use LDAP, <>. -If you want to customize the authentication process then you should implement `AuthenticationProvider` yourself. -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. +If you want to customize the authentication process, you should implement `AuthenticationProvider` yourself. +See this https://spring.io/blog/2010/08/02/spring-security-in-google-app-engine/[ blog article] for an example that integrate Spring Security authentication with Google App Engine. [[appendix-faq-howto]] -=== Common "Howto" Requests +=== Common "How to" Questions + +This section addresses the most common "How to" (or "How do I") questions about Spring Security: . <> . <> @@ -435,72 +445,70 @@ 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. -How do I add support for extra login fields (e.g. -a company name)? +==== I need to login in with more information than just the username. How do I add support for extra login fields (such as a company name)? -This question comes up repeatedly in the Spring Security forum so you will find more information there by searching the archives (or through google). +This question comes up repeatedly, so you can find more information by searching online. -The submitted login information is processed by an instance of `UsernamePasswordAuthenticationFilter`. You will need to customize this class to handle the extra data field(s). One option is to use your own customized authentication token class (rather than the standard `UsernamePasswordAuthenticationToken`), another is simply to concatenate the extra fields with the username (for example, using a ":" as the separator) and pass them in the username property of `UsernamePasswordAuthenticationToken`. +The submitted login information is processed by an instance of `UsernamePasswordAuthenticationFilter`. You need to customize this class to handle the extra data fields. One option is to use your own customized authentication token class (rather than the standard `UsernamePasswordAuthenticationToken`). Another option is to concatenate the extra fields with the username (for example, by using a `:` character as the separator) and pass them in the username property of `UsernamePasswordAuthenticationToken`. -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. +You also need to customize the actual authentication process. +If you use a custom authentication token class, for example, you will have to write an `AuthenticationProvider` (or extend the standard `DaoAuthenticationProvider`) to handle it. If you have concatenated the fields, you can implement your own `UserDetailsService` to split them up and load 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 (such as /thing1#thing2 and /thing1#thing3? -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. +You cannot do this, since the fragment is not transmitted from the browser to the server. +From the server's perspective, the URLs are identical. 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? -Obviously you can't (without resorting to something like thread-local variables) since the only information supplied to the interface is the username. +You cannot (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. -In a standard web setup, the `getDetails()` method on the `Authentication` object will return an instance of `WebAuthenticationDetails`. If you need additional information, you can inject a custom `AuthenticationDetailsSource` into the authentication filter you are using. -If you are using the namespace, for example with the `` element, then you should remove this element and replace it with a `` declaration pointing to an explicitly configured `UsernamePasswordAuthenticationFilter`. +In a standard web setup, the `getDetails()` method on the `Authentication` object returns an instance of `WebAuthenticationDetails`. If you need additional information, you can inject a custom `AuthenticationDetailsSource` into the authentication filter you are using. +If you use the namespace, for example with the `` element, you should remove this element and replace it with a `` declaration that points to an explicitly configured `UsernamePasswordAuthenticationFilter`. [[appendix-faq-access-session-from-user-service]] ==== 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. +You cannot, since the `UserDetailsService` has no awareness of the servlet API. If you want to store custom user data, you should customize the `UserDetails` object that is returned. +This can then be accessed at any point, through the thread-local `SecurityContextHolder`. A call to `SecurityContextHolder.getContext().getAuthentication().getPrincipal()` returns this custom object. -If you really need to access the session, then it must be done by customizing the web tier. +If you really need to access the session, you must do so by by customizing the web tier. [[appendix-faq-password-in-user-service]] ==== How do I access the user's password in a UserDetailsService? -You can't (and shouldn't). You are probably misunderstanding its purpose. -See "<>" above. +You cannot (and should not, even if you find a way to do so). You are probably misunderstanding its purpose. +See "<>", earlier in the FAQ. [[appendix-faq-dynamic-url-metadata]] -==== How do I define the secured URLs within an application dynamically? +==== How do I dynamically define the secured URLs within an application? -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. +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. The first thing you should ask yourself is if you really need to do this. -If an application requires securing, then it also requires that the security be tested thoroughly based on a defined policy. +If an application needs to be secure, it also requires that the security be tested thoroughly based on a defined policy. It may require auditing and acceptance testing before being rolled out into a production environment. -A security-conscious organization should be aware that the benefits of their diligent testing process could be wiped out instantly by allowing the security settings to be modified at runtime by changing a row or two in a configuration database. -If you have taken this into account (perhaps using multiple layers of security within your application) then Spring Security allows you to fully customize the source of security metadata. +A security-conscious organization should be aware that the benefits of their diligent testing process could be wiped out instantly by letting the security settings be modified at runtime by changing a row or two in a configuration database. +If you have taken this into account (perhaps by using multiple layers of security within your application), Spring Security lets you fully customize the source of security metadata. You can make it fully dynamic if you choose. -Both method and web security are protected by subclasses of `AbstractSecurityInterceptor` which is configured with a `SecurityMetadataSource` from which it obtains the metadata for a particular method or filter invocation. -For web security, the interceptor class is `FilterSecurityInterceptor` and it uses the marker interface `FilterInvocationSecurityMetadataSource`. The "secured object" type it operates on is a `FilterInvocation`. The default implementation which is used (both in the namespace `` and when configuring the interceptor explicitly, stores the list of URL patterns and their corresponding list of "configuration attributes" (instances of `ConfigAttribute`) in an in-memory map. +Both method and web security are protected by subclasses of `AbstractSecurityInterceptor`, which is configured with a `SecurityMetadataSource` from which it obtains the metadata for a particular method or filter invocation. +For web security, the interceptor class is `FilterSecurityInterceptor`, and it uses the `FilterInvocationSecurityMetadataSource` marker interface. The "`secured object`" type it operates on is a `FilterInvocation`. The default implementation (which is used both in the namespace `` and when configuring the interceptor explicitly) stores the list of URL patterns and their corresponding list of "`configuration attributes`" (instances of `ConfigAttribute`) in an in-memory map. -To load the data from an alternative source, you must be using an explicitly declared security filter chain (typically Spring Security's `FilterChainProxy`) in order to customize the `FilterSecurityInterceptor` bean. -You can't use the namespace. -You would then implement `FilterInvocationSecurityMetadataSource` to load the data as you please for a particular `FilterInvocation` footnote:[The `FilterInvocation` object contains the `HttpServletRequest`, so you can obtain the URL or any other relevant information on which to base your decision on what the list of returned attributes will contain.]. A very basic outline would look something like this: +To load the data from an alternative source, you must use an explicitly declared security filter chain (typically Spring Security's `FilterChainProxy`) to customize the `FilterSecurityInterceptor` bean. +You cannot use the namespace. +You would then implement `FilterInvocationSecurityMetadataSource` to load the data as you please for a particular `FilterInvocation`. The `FilterInvocation` object contains the `HttpServletRequest`, so you can obtain the URL or any other relevant information on which to base your decision, based on what the list of returned attributes contains. A basic outline would look something like the following example: +==== [source,java] ---- - public class MyFilterSecurityMetadataSource implements FilterInvocationSecurityMetadataSource { public List getAttributes(Object object) { @@ -523,8 +531,8 @@ You would then implement `FilterInvocationSecurityMetadataSource` to load the da return FilterInvocation.class.isAssignableFrom(clazz); } } - ---- +==== For more information, look at the code for `DefaultFilterInvocationSecurityMetadataSource`. @@ -532,54 +540,53 @@ 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? -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. +The `LdapAuthenticationProvider` bean (which handles normal LDAP authentication in Spring Security) is configured with two separate strategy interfaces, one that performs the authentication and one that 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 let you specify how these should be retrieved. -To use JDBC instead, you can implement the interface yourself, using whatever SQL is appropriate for your schema: +To use JDBC instead, you can implement the interface yourself, by using whatever SQL is appropriate for your schema: +==== [source,java] ---- - - public class MyAuthoritiesPopulator implements LdapAuthoritiesPopulator { - @Autowired - JdbcTemplate template; - - List getGrantedAuthorities(DirContextOperations userData, String username) { - List = template.query("select role from roles where username = ?", - new String[] {username}, - new RowMapper() { - /** - * We're assuming here that you're using the standard convention of using the role - * prefix "ROLE_" to mark attributes which are supported by Spring Security's RoleVoter. - */ - public GrantedAuthority mapRow(ResultSet rs, int rowNum) throws SQLException { - return new SimpleGrantedAuthority("ROLE_" + rs.getString(1); - } - } - } - } - +public class MyAuthoritiesPopulator implements LdapAuthoritiesPopulator { + @Autowired + JdbcTemplate template; + + List getGrantedAuthorities(DirContextOperations userData, String username) { + List = template.query("select role from roles where username = ?", + new String[] {username}, + new RowMapper() { + /** + * We assume here that you use the standard convention of using the role + * prefix (`ROLE_`) to mark attributes that are supported by Spring Security's RoleVoter. + */ + public GrantedAuthority mapRow(ResultSet rs, int rowNum) throws SQLException { + return new SimpleGrantedAuthority("ROLE_" + rs.getString(1); + } + }); + } +} ---- +==== -You would then add a bean of this type to your application context and inject it into the `LdapAuthenticationProvider`. This is covered in the section on configuring LDAP using explicit Spring beans in the LDAP chapter of the reference manual. -Note that you can't use the namespace for configuration in this case. -You should also consult the Javadoc for the relevant classes and interfaces. +You would then add a bean of this type to your application context and inject it into the `LdapAuthenticationProvider`. This is covered in the section on configuring LDAP by using explicit Spring beans in the LDAP chapter of the reference manual. +Note that you cannot use the namespace for configuration in this case. +You should also consult the security-api-url[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. -What can I do short of abandoning namespace use? +==== 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. -If you want to do something simple, like modify a bean, or inject a different dependency, you can do this by adding a `BeanPostProcessor` to your configuration. -More information can be found in the https://docs.spring.io/spring/docs/3.0.x/spring-framework-reference/htmlsingle/spring-framework-reference.html#beans-factory-extension-bpp[Spring Reference Manual]. In order to do this, you need to know a bit about which beans are created, so you should also read the blog article in the above question on <>. +The namespace functionality is intentionally limited, so it does not cover everything that you can do with plain beans. +If you want to do something simple, such as modifying a bean or injecting a different dependency, you can do so by adding a `BeanPostProcessor` to your configuration. +You can find more information in the https://docs.spring.io/spring/docs/3.0.x/spring-framework-reference/htmlsingle/spring-framework-reference.html#beans-factory-extension-bpp[Spring Reference Manual]. To do so, you need to know a bit about which beans are created, so you should also read the blog article mentioned in the earlier question on <>. -Normally, you would add the functionality you require to the `postProcessBeforeInitialization` method of `BeanPostProcessor`. Let's say that you want to customize the `AuthenticationDetailsSource` used by the `UsernamePasswordAuthenticationFilter`, (created by the `form-login` element). You want to extract a particular header called `CUSTOM_HEADER` from the request and make use of it while authenticating the user. -The processor class would look like this: +Normally, you would add the functionality you require to the `postProcessBeforeInitialization` method of `BeanPostProcessor`. Suppose that you want to customize the `AuthenticationDetailsSource` used by the `UsernamePasswordAuthenticationFilter` (created by the `form-login` element). You want to extract a particular header called `CUSTOM_HEADER` from the request and use it while authenticating the user. +The processor class would look like the following listing: +==== [source,java] ---- - public class BeanPostProcessor implements BeanPostProcessor { public Object postProcessAfterInitialization(Object bean, String name) { @@ -599,8 +606,8 @@ public class BeanPostProcessor implements BeanPostProcessor { return bean; } } - ---- +==== You would then register this bean in your application context. -Spring will automatically invoke it on the beans defined in the application context. +Spring automatically invoke it on the beans defined in the application context. diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/appendix/index.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/appendix/index.adoc index 5f01cc38d06..682e833a16e 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/appendix/index.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/appendix/index.adoc @@ -1,6 +1,8 @@ = Appendix +This appendix contains additional information that may help you understand topics within the Spring Security Reference Guide. + include::database-schema.adoc[leveloffset=+1] include::namespace.adoc[] diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/appendix/namespace.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/appendix/namespace.adoc index 3d5b0dca6b7..19d1dae7642 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/appendix/namespace.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/appendix/namespace.adoc @@ -9,27 +9,29 @@ If you are familiar with this format, you may wish to examine the https://raw.gi [[nsa-web]] === Web Application Security +This section deals with the XML namespace elements and attributes that deal with the security of web applications. + [[nsa-debug]] ==== Enables Spring Security debugging infrastructure. -This will provide human-readable (multi-line) debugging information to monitor requests coming into the security filters. -This may include sensitive information, such as request parameters or headers, and should only be used in a development environment. +This element provides human-readable (multi-line) debugging information to monitor requests that come to the security filters. +This may include sensitive information (such as request parameters or headers) and should only be used in a development environment. [[nsa-http]] ==== -If you use an `` element within your application, a `FilterChainProxy` bean named "springSecurityFilterChain" is created and the configuration within the element is used to build a filter chain within +If you use an `` element within your application, a `FilterChainProxy` bean named `springSecurityFilterChain` is created, and the configuration within the element is used to build a filter chain within `FilterChainProxy`. -As of Spring Security 3.1, additional `http` elements can be used to add extra filter chains footnote:[See the pass:specialcharacters,macros[<>] for how to set up the mapping from your `web.xml` ]. -Some core filters are always created in a filter chain and others will be added to the stack depending on the attributes and child elements which are present. +As of Spring Security 3.1, you can use additional `http` elements to add extra filter chains. See the <> for how to set up the mapping from your `web.xml`. +Some core filters are always created in a filter chain and others are added to the stack depending on the attributes and child elements that are present. The positions of the standard filters are fixed (see <> in the namespace introduction), removing a common source of errors with previous versions of the framework when users had to configure the filter chain explicitly in the `FilterChainProxy` bean. -You can, of course, still do this if you need full control of the configuration. +You can still controle the order of the filters if you need full control of the configuration. -All filters which require a reference to the <> will be automatically injected with the internal instance created by the namespace configuration. +All filters that require a reference to the <> are automatically injected with the internal instance created by the namespace configuration. -Each `` namespace block always creates an `SecurityContextPersistenceFilter`, an `ExceptionTranslationFilter` and a `FilterSecurityInterceptor`. +Each `` namespace block always creates an `SecurityContextPersistenceFilter`, an `ExceptionTranslationFilter`, and a `FilterSecurityInterceptor`. These are fixed and cannot be replaced with alternatives. @@ -39,119 +41,126 @@ The attributes on the `` element control some of the properties on the cor [[nsa-http-access-decision-manager-ref]] -* **access-decision-manager-ref** -Optional attribute specifying the ID of the `AccessDecisionManager` implementation which should be used for authorizing HTTP requests. -By default an `AffirmativeBased` implementation is used for with a `RoleVoter` and an `AuthenticatedVoter`. +`access-decision-manager-ref`:: +Optional attribute specifying the ID of the `AccessDecisionManager` implementation that should be used for authorizing HTTP requests. +By default, an `AffirmativeBased` implementation is used for with a `RoleVoter` and an `AuthenticatedVoter`. [[nsa-http-authentication-manager-ref]] -* **authentication-manager-ref** +`authentication-manager-ref`:: A reference to the `AuthenticationManager` used for the `FilterChain` created by this http element. [[nsa-http-auto-config]] -* **auto-config** -Automatically registers a login form, BASIC authentication, logout services. -If set to "true", all of these capabilities are added (although you can still customize the configuration of each by providing the respective element). -If unspecified, defaults to "false". +`auto-config`:: +Automatically registers a login form, BASIC authentication, and logout services. +If set to `true`, all of these capabilities are added. (You can still customize the configuration of each by providing the respective element). +If unspecified, it defaults to `false`. Use of this attribute is not recommended. -Use explicit configuration elements instead to avoid confusion. +Instead, you should use explicit configuration elements to avoid confusion. [[nsa-http-create-session]] -* **create-session** +`create-session`:: Controls the eagerness with which an HTTP session is created by Spring Security classes. Options include: -** `always` - Spring Security will proactively create a session if one does not exist. -** `ifRequired` - Spring Security will only create a session only if one is required (default value). -** `never` - Spring Security will never create a session, but will make use of one if the application does. -** `stateless` - Spring Security will not create a session and ignore the session for obtaining a Spring `Authentication`. +* `always`: Spring Security proactively creates a session if one does not exist. +* `ifRequired` (default): Spring Security creates a session only if one is required. +* `never`: Spring Security never creates a session, but it will make use of one if the application creates one. +* `stateless`: Spring Security does not create a session and ignores the session for obtaining a Spring `Authentication`. [[nsa-http-disable-url-rewriting]] -* **disable-url-rewriting** +`disable-url-rewriting`:: Prevents session IDs from being appended to URLs in the application. Clients must use cookies if this attribute is set to `true`. The default is `true`. [[nsa-http-entry-point-ref]] -* **entry-point-ref** -Normally the `AuthenticationEntryPoint` used will be set depending on which authentication mechanisms have been configured. -This attribute allows this behaviour to be overridden by defining a customized `AuthenticationEntryPoint` bean which will start the authentication process. +`entry-point-ref`:: +Normally, which `AuthenticationEntryPoint` is used depends on which authentication mechanisms have been configured. +This attribute lets this behavior be overridden by defining a customized `AuthenticationEntryPoint` bean, which starts the authentication process. [[nsa-http-jaas-api-provision]] -* **jaas-api-provision** -If available, runs the request as the `Subject` acquired from the `JaasAuthenticationToken` which is implemented by adding a `JaasApiIntegrationFilter` bean to the stack. +`jaas-api-provision`:: +If available, runs the request as the `Subject` acquired from the `JaasAuthenticationToken`, which is implemented by adding a `JaasApiIntegrationFilter` bean to the stack. Defaults to `false`. [[nsa-http-name]] -* **name** -A bean identifier, used for referring to the bean elsewhere in the context. +`name`:: +A bean identifier used for referring to the bean elsewhere in the context. [[nsa-http-once-per-request]] -* **once-per-request** +`once-per-request`:: Corresponds to the `observeOncePerRequest` property of `FilterSecurityInterceptor`. Defaults to `true`. [[nsa-http-pattern]] -* **pattern** -Defining a pattern for the <> element controls the requests which will be filtered through the list of filters which it defines. +`pattern`:: +Defines a pattern for the <> element controls the requests which are filtered through the list of filters that it defines. The interpretation is dependent on the configured <>. -If no pattern is defined, all requests will be matched, so the most specific patterns should be declared first. +If no pattern is defined, all requests are matched, so the most specific patterns should be declared first. [[nsa-http-realm]] -* **realm** +`realm`:: Sets the realm name used for basic authentication (if enabled). Corresponds to the `realmName` property on `BasicAuthenticationEntryPoint`. [[nsa-http-request-matcher]] -* **request-matcher** +`request-matcher`:: Defines the `RequestMatcher` strategy used in the `FilterChainProxy` and the beans created by the `intercept-url` to match incoming requests. -Options are currently `mvc`, `ant`, `regex` and `ciRegex`, for Spring MVC, ant, regular-expression and case-insensitive regular-expression respectively. -A separate instance is created for each <> element using its <>, <> and <> attributes. -Ant paths are matched using an `AntPathRequestMatcher`, regular expressions are matched using a `RegexRequestMatcher` and for Spring MVC path matching the `MvcRequestMatcher` is used. +The current options are + +* `mvc`: Spring MVC +* `ant` (default): Ant +* `regex`: Regular expression +* `ciRegex`: Case-insensitive regular-expression respectively. +A separate instance is created for each <> element, by using its <>, <>, and <> attributes. +Ant paths are matched by using an `AntPathRequestMatcher`. Regular expressions are matched by using a `RegexRequestMatcher`. For Spring MVC path matching, the `MvcRequestMatcher` is used. See the Javadoc for these classes for more details on exactly how the matching is performed. -Ant paths are the default strategy. [[nsa-http-request-matcher-ref]] -* **request-matcher-ref** -A reference to a bean that implements `RequestMatcher` that will determine if this `FilterChain` should be used. -This is a more powerful alternative to <>. +`request-matcher-ref`:: +A reference to a bean that implements `RequestMatcher`, which determines whenter this `FilterChain` should be used. +This is a more powerful alternative to <>. [[nsa-http-security]] -* **security** -A request pattern can be mapped to an empty filter chain, by setting this attribute to `none`. -No security will be applied and none of Spring Security's features will be available. +`security`:: +A request pattern can be mapped to an empty filter chain by setting this attribute to `none`. +In that case, no security is applied and none of Spring Security's features are available. [[nsa-http-security-context-repository-ref]] -* **security-context-repository-ref** +`security-context-repository-ref`:: Allows injection of a custom `SecurityContextRepository` into the `SecurityContextPersistenceFilter`. [[nsa-http-servlet-api-provision]] -* **servlet-api-provision** -Provides versions of `HttpServletRequest` security methods such as `isUserInRole()` and `getPrincipal()` which are implemented by adding a `SecurityContextHolderAwareRequestFilter` bean to the stack. -Defaults to `true`. +`servlet-api-provision`:: +Provides versions of `HttpServletRequest` security methods, such as `isUserInRole()` and `getPrincipal()`, which are implemented by adding a `SecurityContextHolderAwareRequestFilter` bean to the stack. +Default: `true`. [[nsa-http-use-expressions]] -* **use-expressions** +`use-expressions`:: Enables EL-expressions in the `access` attribute, as described in the chapter on <>. -The default value is true. +Default: `true`. [[nsa-http-children]] ===== Child Elements of + +The `` element has the following child elements, which we describe later in this appendix: + * <> * <> * <> @@ -177,26 +186,26 @@ The default value is true. [[nsa-access-denied-handler]] ==== -This element allows you to set the `errorPage` property for the default `AccessDeniedHandler` used by the `ExceptionTranslationFilter`, using the <> attribute, or to supply your own implementation using the<> attribute. -This is discussed in more detail in the section on the <>. +This element lets you set the `errorPage` property for the default `AccessDeniedHandler` used by the `ExceptionTranslationFilter` (by using the <> attribute) or to supply your own implementation by using the<> attribute. +This is discussed in more detail in the section on the <>. [[nsa-access-denied-handler-parents]] ===== Parent Elements of -* <> +The parent element of the `` element is <>. [[nsa-access-denied-handler-attributes]] ===== Attributes [[nsa-access-denied-handler-error-page]] -* **error-page** -The access denied page that an authenticated user will be redirected to if they request a page which they don't have the authority to access. +`error-page`:: +The access denied page to which an authenticated user is redirected if they request a page to which they do not have access. [[nsa-access-denied-handler-ref]] -* **ref** +`ref`:: Defines a reference to a Spring bean of type `AccessDeniedHandler`. @@ -207,26 +216,26 @@ If no `CorsFilter` or `CorsConfigurationSource` is specified and Spring MVC is o [[nsa-cors-attributes]] ===== Attributes -The attributes on the `` element control the headers element. +The attributes on the `` element control the headers element are: [[nsa-cors-ref]] -* **ref** +`ref`:: Optional attribute that specifies the bean name of a `CorsFilter`. [[nsa-cors-configuration-source-ref]] -* **cors-configuration-source-ref** +cors-configuration-source-ref:: Optional attribute that specifies the bean name of a `CorsConfigurationSource` to be injected into a `CorsFilter` created by the XML namespace. [[nsa-cors-parents]] ===== Parent Elements of -* <> +The parent element of the `` element is <>. [[nsa-headers]] ==== -This element allows for configuring additional (security) headers to be send with the response. -It enables easy configuration for several headers and also allows for setting custom headers through the <> element. -Additional information, can be found in the <> section of the reference. +This element allows for configuring additional (security) headers to be sent with the response. +It enables configuration for several headers and also allows for setting custom headers through the <> element. +You can find additional information in the <> section of the reference. ** `Cache-Control`, `Pragma`, and `Expires` - Can be set using the <> element. This ensures that the browser does not cache your secured pages. @@ -248,30 +257,30 @@ https://www.w3.org/TR/CSP2/[Content Security Policy (CSP)] is a mechanism that w [[nsa-headers-attributes]] ===== Attributes -The attributes on the `` element control the headers element. +The attributes on the `` element control the `` element in the HTML output. [[nsa-headers-defaults-disabled]] -* **defaults-disabled** -Optional attribute that specifies to disable the default Spring Security's HTTP response headers. -The default is false (the default headers are included). +`defaults-disabled`:: +Optional attribute that specifies whether to disable the default Spring Security's HTTP response headers. +The default is `false` (the default headers are included). [[nsa-headers-disabled]] -* **disabled** -Optional attribute that specifies to disable Spring Security's HTTP response headers. +`disabled`:: +Optional attribute that specifies whether to disable Spring Security's HTTP response headers. The default is false (the headers are enabled). [[nsa-headers-parents]] ===== Parent Elements of -* <> - +The parent element of the `` element is the <`>> element. [[nsa-headers-children]] ===== Child Elements of +The `` element has the following possible children: * <> * <> @@ -286,237 +295,245 @@ The default is false (the headers are enabled). * <> - [[nsa-cache-control]] ==== -Adds `Cache-Control`, `Pragma`, and `Expires` headers to ensure that the browser does not cache your secured pages. +The `` element adds the `Cache-Control`, `Pragma`, and `Expires` headers to ensure that the browser does not cache your secured pages. [[nsa-cache-control-attributes]] ===== Attributes +The `` element can have the following attribute: + [[nsa-cache-control-disabled]] -* **disabled** -Specifies if Cache Control should be disabled. -Default false. +`disabled`:: +Specifies whether cache control should be disabled. +Default: `false`. [[nsa-cache-control-parents]] ===== Parent Elements of - -* <> - +The parent of the `` element is the <`>> element. [[nsa-hsts]] ==== -When enabled adds the https://tools.ietf.org/html/rfc6797[Strict-Transport-Security] header to the response for any secure request. -This allows the server to instruct browsers to automatically use HTTPS for future requests. +When enabled, the `` element adds the https://tools.ietf.org/html/rfc6797[Strict-Transport-Security] header to the response for any secure request. +This lets the server instruct browsers to automatically use HTTPS for future requests. [[nsa-hsts-attributes]] ===== Attributes +The `` element has the following available attributes: + [[nsa-hsts-disabled]] -* **disabled** -Specifies if Strict-Transport-Security should be disabled. -Default false. +`disabled`:: +Specifies whether Strict-Transport-Security should be disabled. +Default: `false`. [[nsa-hsts-include-subdomains]] -* **include-sub-domains** -Specifies if subdomains should be included. -Default true. +`include-sub-domains`:: +Specifies whether subdomains should be included. +Default: true. [[nsa-hsts-max-age-seconds]] -* **max-age-seconds** +`max-age-seconds`:: Specifies the maximum amount of time the host should be considered a Known HSTS Host. Default one year. [[nsa-hsts-request-matcher-ref]] -* **request-matcher-ref** -The RequestMatcher instance to be used to determine if the header should be set. -Default is if HttpServletRequest.isSecure() is true. +`request-matcher-ref`:: +The `RequestMatcher` instance to be used to determine if the header should be set. +The default is to see whether `HttpServletRequest.isSecure()` is `true`. [[nsa-hsts-preload]] -* **preload** -Specifies if preload should be included. -Default false. +preload:: +Specifies whether preload should be included. +Default: `false`. [[nsa-hsts-parents]] ===== Parent Elements of -* <> - +The parent element of the `` element is the <`>> element. [[nsa-hpkp]] ==== -When enabled adds the https://tools.ietf.org/html/rfc7469[Public Key Pinning Extension for HTTP] header to the response for any secure request. -This allows HTTPS websites to resist impersonation by attackers using mis-issued or otherwise fraudulent certificates. +When enabled, the `` element adds the https://tools.ietf.org/html/rfc7469[Public Key Pinning Extension for HTTP] header to the response for any secure request. +This lets HTTPS websites resist impersonation by attackers that use mis-issued or otherwise fraudulent certificates. [[nsa-hpkp-attributes]] ===== Attributes +The `` element can have the following elements: + [[nsa-hpkp-disabled]] -* **disabled** +`disabled`:: Specifies if HTTP Public Key Pinning (HPKP) should be disabled. -Default true. +Default: `true`. [[nsa-hpkp-include-subdomains]] -* **include-sub-domains** -Specifies if subdomains should be included. -Default false. +`include-sub-domains`:: +Specifies whether subdomains should be included. +Default: `false`. [[nsa-hpkp-max-age-seconds]] -* **max-age-seconds** -Sets the value for the max-age directive of the Public-Key-Pins header. -Default 60 days. +max-age-seconds:: +Sets the value for the `max-age` directive of the `Public-Key-Pins` header. +Default: 60 days (5,184,000 seconds) [[nsa-hpkp-report-only]] -* **report-only** -Specifies if the browser should only report pin validation failures. -Default true. +`report-only`:: +Specifies whether the browser should report only pin validation failures. +Default: `true`. [[nsa-hpkp-report-uri]] -* **report-uri** +`report-uri`: Specifies the URI to which the browser should report pin validation failures. [[nsa-hpkp-parents]] ===== Parent Elements of -* <> +The parent element of the element is the <`>> element. [[nsa-pins]] ==== -The list of pins +This section describes the attributes and child elements of the `` element. [[nsa-pins-children]] ===== Child Elements of -* <> +The element has a single child element: <`>>. There can be multiple elements. [[nsa-pin]] ==== -A pin is specified using the base64-encoded SPKI fingerprint as value and the cryptographic hash algorithm as attribute +A element is specified by using the base64-encoded SPKI fingerprint as the value and the cryptographic hash algorithm as the attribute. [[nsa-pin-attributes]] ===== Attributes [[nsa-pin-algorithm]] -* **algorithm** +`algorithm`:: The cryptographic hash algorithm. -Default is SHA256. +Default: SHA256. [[nsa-pin-parents]] ===== Parent Elements of -* <> +The parent element of the element is the <`>> element. [[nsa-content-security-policy]] ==== -When enabled adds the https://www.w3.org/TR/CSP2/[Content Security Policy (CSP)] header to the response. -CSP is a mechanism that web applications can leverage to mitigate content injection vulnerabilities, such as cross-site scripting (XSS). +When enabled, the `` element adds the https://www.w3.org/TR/CSP2/[Content Security Policy (CSP)] header to the response. +CSP is a mechanism that web applications can use to mitigate content injection vulnerabilities, such as cross-site scripting (XSS). [[nsa-content-security-policy-attributes]] ===== Attributes +The element has the following attributes: + [[nsa-content-security-policy-policy-directives]] -* **policy-directives** -The security policy directive(s) for the Content-Security-Policy header or if report-only is set to true, then the Content-Security-Policy-Report-Only header is used. +`policy-directives`:: +The security policy directive(s) for the Content-Security-Policy header. If report-only is set to `true`, the Content-Security-Policy-Report-Only header is used. [[nsa-content-security-policy-report-only]] -* **report-only** -Set to true, to enable the Content-Security-Policy-Report-Only header for reporting policy violations only. -Defaults to false. +`report-only`:: +Whether to enable the Content-Security-Policy-Report-Only header for reporting policy violations only. +Default: `false`. [[nsa-content-security-policy-parents]] ===== Parent Elements of -* <> +The parent element of the element is <`>>. [[nsa-referrer-policy]] ==== -When enabled adds the https://www.w3.org/TR/referrer-policy/[Referrer Policy] header to the response. +When enabled, the `` element adds the https://www.w3.org/TR/referrer-policy/[Referrer Policy] header to the response. [[nsa-referrer-policy-attributes]] ===== Attributes +The `` element has the following attribute: + [[nsa-referrer-policy-policy]] -* **policy** -The policy for the Referrer-Policy header. -Default "no-referrer". +policy:: +The policy for the `Referrer-Policy` header. +Default: `no-referrer`. [[nsa-referrer-policy-parents]] ===== Parent Elements of -* <> +The parent element of the `` element is the <`>> element. [[nsa-feature-policy]] ==== -When enabled adds the https://wicg.github.io/feature-policy/[Feature Policy] header to the response. +When enabled, the `` element adds the https://wicg.github.io/feature-policy/[Feature Policy] header to the response. [[nsa-feature-policy-attributes]] ===== Attributes +The `` element has the following attribute: + [[nsa-feature-policy-policy-directives]] -* **policy-directives** +`policy-directives`:: The security policy directive(s) for the Feature-Policy header. [[nsa-feature-policy-parents]] ===== Parent Elements of -* <> +The parent element of the element is the <`>> element. [[nsa-frame-options]] ==== -When enabled adds the https://tools.ietf.org/html/draft-ietf-websec-x-frame-options[X-Frame-Options header] to the response, this allows newer browsers to do some security checks and prevent https://en.wikipedia.org/wiki/Clickjacking[clickjacking] attacks. +When enabled, the `` element adds the https://tools.ietf.org/html/draft-ietf-websec-x-frame-options[X-Frame-Options header] to the response. Doing so lets newer browsers do some security checks and prevent https://en.wikipedia.org/wiki/Clickjacking[clickjacking] attacks. [[nsa-frame-options-attributes]] ===== Attributes +The `` element has the following attributes: + [[nsa-frame-options-disabled]] -* **disabled** -If disabled, the X-Frame-Options header will not be included. -Default false. +`disabled`:: +If disabled, the X-Frame-Options header is not included. +Default: `false`. [[nsa-frame-options-policy]] -* **policy** -** `DENY` The page cannot be displayed in a frame, regardless of the site attempting to do so. +`policy`:: +* `DENY` (default): The page cannot be displayed in a frame, regardless of the site attempting to do so. This is the default when frame-options-policy is specified. -** `SAMEORIGIN` The page can only be displayed in a frame on the same origin as the page itself - -+ +* `SAMEORIGIN`: The page can be displayed in a frame only on the same origin as the page itself. -In other words, if you specify DENY, not only will attempts to load the page in a frame fail when loaded from other sites, attempts to do so will fail when loaded from the same site. -On the other hand, if you specify SAMEORIGIN, you can still use the page in a frame as long as the site including it in a frame it is the same as the one serving the page. +In other words, if you specify `DENY`, not only do attempts to load the page in a frame fail when loaded from other sites, attempts to do so fail when loaded from the same site. +On the other hand, if you specify `SAMEORIGIN`, you can still use the page in a frame as long as the site including it in a frame is the same site as the one serving the page. [[nsa-frame-options-parents]] ===== Parent Elements of -* <> +The parent element of the `` element is the <`>> element. [[nsa-permissions-policy]] ==== @@ -536,82 +553,85 @@ The policy value to write for the `Permissions-Policy` header [[nsa-xss-protection]] ==== -Adds the https://blogs.msdn.com/b/ie/archive/2008/07/02/ie8-security-part-iv-the-xss-filter.aspx[X-XSS-Protection header] to the response to assist in protecting against https://en.wikipedia.org/wiki/Cross-site_scripting#Non-Persistent[reflected / Type-1 Cross-Site Scripting (XSS)] attacks. -This is in no-way a full protection to XSS attacks! +The `` adds the https://blogs.msdn.com/b/ie/archive/2008/07/02/ie8-security-part-iv-the-xss-filter.aspx[X-XSS-Protection header] to the response, to assist in protecting against https://en.wikipedia.org/wiki/Cross-site_scripting#Non-Persistent[reflected / Type-1 Cross-Site Scripting (XSS)] attacks. +NOTE: Full protection against XSS attacks is not possible. [[nsa-xss-protection-attributes]] ===== Attributes +The `` element has the following attributes: [[nsa-xss-protection-disabled]] -* **xss-protection-disabled** -Do not include the header for https://en.wikipedia.org/wiki/Cross-site_scripting#Non-Persistent[reflected / Type-1 Cross-Site Scripting (XSS)] protection. +`xss-protection-disabled`:: +If set to `true`, do not include the header for https://en.wikipedia.org/wiki/Cross-site_scripting#Non-Persistent[reflected / Type-1 Cross-Site Scripting (XSS)] protection. [[nsa-xss-protection-enabled]] * **xss-protection-enabled** -Explicitly enable or disable https://en.wikipedia.org/wiki/Cross-site_scripting#Non-Persistent[reflected / Type-1 Cross-Site Scripting (XSS)] protection. +Whether to explicitly enable or disable https://en.wikipedia.org/wiki/Cross-site_scripting#Non-Persistent[reflected / Type-1 Cross-Site Scripting (XSS)] protection. [[nsa-xss-protection-block]] * **xss-protection-block** -When true and xss-protection-enabled is true, adds mode=block to the header. +When `true` and `xss-protection-enabled` is `true`, adds `mode=block` to the header. This indicates to the browser that the page should not be loaded at all. -When false and xss-protection-enabled is true, the page will still be rendered when an reflected attack is detected but the response will be modified to protect against the attack. -Note that there are sometimes ways of bypassing this mode which can often times make blocking the page more desirable. +When `false` and `xss-protection-enabled` is `true`, the page is still rendered when a reflected attack is detected, but the response is modified to protect against the attack. +Note that there are sometimes ways of bypassing this mode, which can often times make blocking the page more desirable. [[nsa-xss-protection-parents]] ===== Parent Elements of -* <> +The parent element of the `` is the <`>> element. [[nsa-content-type-options]] ==== -Add the X-Content-Type-Options header with the value of nosniff to the response. +The `` element adds the `X-Content-Type-Options` header with a value of `nosniff` to the response. This https://blogs.msdn.com/b/ie/archive/2008/09/02/ie8-security-part-vi-beta-2-update.aspx[disables MIME-sniffing] for IE8+ and Chrome extensions. [[nsa-content-type-options-attributes]] ===== Attributes +The `` element has the following attribute: + [[nsa-content-type-options-disabled]] -* **disabled** -Specifies if Content Type Options should be disabled. -Default false. +`disabled`:: +Specifies whether Content Type Options should be disabled. +Default: `false`. [[nsa-content-type-options-parents]] ===== Parent Elements of - -* <> +The parent element of the `` element is the <`>> element. [[nsa-header]] ====
-Add additional headers to the response, both the name and value need to be specified. +The `
` element adds additional headers to the response. Both the name and value of each added header need to be specified in a `` element (a child of the `
` element). To add multiple headers, add multiple `` elements. [[nsa-header-attributes]] ===== Attributes +The `` element has the following attributes: [[nsa-header-name]] -* **header-name** -The `name` of the header. +`header-name`:: +The `name` of the header to add. [[nsa-header-value]] -* **value** +value:: The `value` of the header to add. [[nsa-header-ref]] -* **ref** +`ref`:: Reference to a custom implementation of the `HeaderWriter` interface. @@ -619,143 +639,145 @@ Reference to a custom implementation of the `HeaderWriter` interface. ===== Parent Elements of
-* <> +The parent element of the `
` is the <`>> element. [[nsa-anonymous]] ==== -Adds an `AnonymousAuthenticationFilter` to the stack and an `AnonymousAuthenticationProvider`. -Required if you are using the `IS_AUTHENTICATED_ANONYMOUSLY` attribute. +The `` element adds an `AnonymousAuthenticationFilter` to the stack and adds an `AnonymousAuthenticationProvider`. +This element is required if you use the `IS_AUTHENTICATED_ANONYMOUSLY` attribute. [[nsa-anonymous-parents]] ===== Parent Elements of - -* <> +The parent element of the `` element is the <`>> element. [[nsa-anonymous-attributes]] ===== Attributes +The `` element has the following attributes: [[nsa-anonymous-enabled]] -* **enabled** -With the default namespace setup, the anonymous "authentication" facility is automatically enabled. -You can disable it using this property. +`enabled`:: +With the default namespace setup, the anonymous "`authentication`" facility is automatically enabled. +You can disable it by setting this property. [[nsa-anonymous-granted-authority]] -* **granted-authority** +`granted-authority`:: The granted authority that should be assigned to the anonymous request. -Commonly this is used to assign the anonymous request particular roles, which can subsequently be used in authorization decisions. -If unset, defaults to `ROLE_ANONYMOUS`. +Commonly, this attribute is used to assign the anonymous request particular roles, which can subsequently be used in authorization decisions. +If unset, it defaults to `ROLE_ANONYMOUS`. [[nsa-anonymous-key]] -* **key** -The key shared between the provider and filter. +`key`:: +The key shared between the provider and the filter. This generally does not need to be set. -If unset, it will default to a secure randomly generated value. -This means setting this value can improve startup time when using the anonymous functionality since secure random values can take a while to be generated. +If unset, it defaults to a secure randomly generated value. +This means that setting this value can improve startup time when using the anonymous functionality, since secure random values can take a while to be generated. [[nsa-anonymous-username]] -* **username** +username:: The username that should be assigned to the anonymous request. -This allows the principal to be identified, which may be important for logging and auditing. -if unset, defaults to `anonymousUser`. +This lets the principal be identified, which may be important for logging and auditing. +Defaults: `anonymousUser` [[nsa-csrf]] ==== -This element will add https://en.wikipedia.org/wiki/Cross-site_request_forgery[Cross Site Request Forger (CSRF)] protection to the application. -It also updates the default RequestCache to only replay "GET" requests upon successful authentication. -Additional information can be found in the <> section of the reference. +The `> section of the reference. [[nsa-csrf-parents]] -===== Parent Elements of - +===== Parent Element of -* <> +The parent element of the `` element is the <> element. [[nsa-csrf-attributes]] ===== Attributes +The `` element has the following attributes: + [[nsa-csrf-disabled]] -* **disabled** -Optional attribute that specifies to disable Spring Security's CSRF protection. -The default is false (CSRF protection is enabled). -It is highly recommended to leave CSRF protection enabled. +`disabled`:: +Optional attribute that specifies whether to disable Spring Security's CSRF protection. +Default: `false` (CSRF protection is enabled) +We highly recommended leaving CSRF protection enabled. [[nsa-csrf-token-repository-ref]] -* **token-repository-ref** -The CsrfTokenRepository to use. -The default is `HttpSessionCsrfTokenRepository`. +`token-repository-ref`:: +The `CsrfTokenRepository` to use. +Default: `HttpSessionCsrfTokenRepository` [[nsa-csrf-request-matcher-ref]] -* **request-matcher-ref** -The RequestMatcher instance to be used to determine if CSRF should be applied. -Default is any HTTP method except "GET", "TRACE", "HEAD", "OPTIONS". +request-matcher-ref:: +The `RequestMatcher` instance to be used to determine whether CSRF should be applied. +The default is any HTTP method except `GET`, `TRACE`, `HEAD`, `OPTIONS`. [[nsa-custom-filter]] ==== -This element is used to add a filter to the filter chain. -It doesn't create any additional beans but is used to select a bean of type `javax.servlet.Filter` which is already defined in the application context and add that at a particular position in the filter chain maintained by Spring Security. +The `` element adds a filter to the filter chain. +It does not create any additional beans but is used to select a bean of type `javax.servlet.Filter` which is already defined in the application context and add that at a particular position in the filter chain maintained by Spring Security. Full details can be found in the <>. [[nsa-custom-filter-parents]] ===== Parent Elements of - -* <> +The parent element of the `` is the <`>> element. [[nsa-custom-filter-attributes]] ===== Attributes +The `` element has the following attributes: [[nsa-custom-filter-after]] -* **after** -The filter immediately after which the custom-filter should be placed in the chain. -This feature will only be needed by advanced users who wish to mix their own filters into the security filter chain and have some knowledge of the standard Spring Security filters. +`after`:: +The filter immediately after which the custom filter should be placed in the chain. +This feature is needed only by advanced users who wish to mix their own filters into the security filter chain and have some knowledge of the standard Spring Security filters. The filter names map to specific Spring Security implementation filters. [[nsa-custom-filter-before]] -* **before** -The filter immediately before which the custom-filter should be placed in the chain +`before`:: +The filter immediately before which the custom filter should be placed in the chain. [[nsa-custom-filter-position]] -* **position** -The explicit position at which the custom-filter should be placed in the chain. -Use if you are replacing a standard filter. +`position`:: +The explicit position at which the custom filter should be placed in the chain. +Use this attribute to replace a standard filter. [[nsa-custom-filter-ref]] -* **ref** +ref:: Defines a reference to a Spring bean that implements `Filter`. [[nsa-expression-handler]] ==== -Defines the `SecurityExpressionHandler` instance which will be used if expression-based access-control is enabled. -A default implementation (with no ACL support) will be used if not supplied. +Defines the `SecurityExpressionHandler` instance to be used if expression-based access control is enabled. +A default implementation (with no ACL support) is used if none is supplied. [[nsa-expression-handler-parents]] ===== Parent Elements of +The `` has the following parent elements: * <> * <> @@ -767,188 +789,192 @@ A default implementation (with no ACL support) will be used if not supplied. [[nsa-expression-handler-attributes]] ===== Attributes +The `` element has the following attribute: [[nsa-expression-handler-ref]] -* **ref** +`ref`:: Defines a reference to a Spring bean that implements `SecurityExpressionHandler`. [[nsa-form-login]] ==== -Used to add an `UsernamePasswordAuthenticationFilter` to the filter stack and an `LoginUrlAuthenticationEntryPoint` to the application context to provide authentication on demand. -This will always take precedence over other namespace-created entry points. -If no attributes are supplied, a login page will be generated automatically at the URL "/login" footnote:[ -This feature is really just provided for convenience and is not intended for production (where a view technology will have been chosen and can be used to render a customized login page). -The class `DefaultLoginPageGeneratingFilter` is responsible for rendering the login page and will provide login forms for both normal form login and/or OpenID if required. -] The behaviour can be customized using the <` Attributes>>. +Used to add an `UsernamePasswordAuthenticationFilter` to the filter stack and a `LoginUrlAuthenticationEntryPoint` to the application context, to provide authentication on demand. +This always takes precedence over other namespace-created entry points. +If no attributes are supplied, a login page is generated automatically at the `/login` URL. +You can customize this behavior by setting the <` Attributes>>. + +NOTE: This feature is provided for convenience and is not intended for production (where a view technology should have been chosen and can be used to render a customized login page). +The class `DefaultLoginPageGeneratingFilter` class is responsible for rendering the login page and provide login forms for both normal form login and OpenID if required. [[nsa-form-login-parents]] ===== Parent Elements of -* <> +The parent element of the `` element is the <`>> element. [[nsa-form-login-attributes]] ===== Attributes +The `form-login` element has the following attributes: [[nsa-form-login-always-use-default-target]] -* **always-use-default-target** -If set to `true`, the user will always start at the value given by <>, regardless of how they arrived at the login page. +`always-use-default-target` +If set to `true`, the user always starts at the value given by <>, regardless of how they arrived at the login page. Maps to the `alwaysUseDefaultTargetUrl` property of `UsernamePasswordAuthenticationFilter`. -Default value is `false`. +Default: `false`. [[nsa-form-login-authentication-details-source-ref]] -* **authentication-details-source-ref** -Reference to an `AuthenticationDetailsSource` which will be used by the authentication filter +`authentication-details-source-ref`:: +Reference to an `AuthenticationDetailsSource`, which is used by the authentication filter. [[nsa-form-login-authentication-failure-handler-ref]] -* **authentication-failure-handler-ref** -Can be used as an alternative to <>, giving you full control over the navigation flow after an authentication failure. +`authentication-failure-handler-ref`:: +Can be used as an alternative to <>, giving you full control over the navigation flow after an authentication failure. The value should be the name of an `AuthenticationFailureHandler` bean in the application context. [[nsa-form-login-authentication-failure-url]] * **authentication-failure-url** Maps to the `authenticationFailureUrl` property of `UsernamePasswordAuthenticationFilter`. -Defines the URL the browser will be redirected to on login failure. -Defaults to `/login?error`, which will be automatically handled by the automatic login page generator, re-rendering the login page with an error message. +Defines the URL to which the browser is redirected on login failure. +Defaults to `/login?error`, which is automatically handled by the automatic login page generator, re-rendering the login page with an error message. [[nsa-form-login-authentication-success-handler-ref]] -* **authentication-success-handler-ref** -This can be used as an alternative to <> and <>, giving you full control over the navigation flow after a successful authentication. +`authentication-success-handler-ref`:: +You an use this as an alternative to <> and <>, giving you full control over the navigation flow after a successful authentication. The value should be the name of an `AuthenticationSuccessHandler` bean in the application context. -By default, an implementation of `SavedRequestAwareAuthenticationSuccessHandler` is used and injected with the <>. +By default, an implementation of `SavedRequestAwareAuthenticationSuccessHandler` is used and injected with the <>. [[nsa-form-login-default-target-url]] -* **default-target-url** +default-target-url:: Maps to the `defaultTargetUrl` property of `UsernamePasswordAuthenticationFilter`. -If not set, the default value is "/" (the application root). -A user will be taken to this URL after logging in, provided they were not asked to login while attempting to access a secured resource, when they will be taken to the originally requested URL. +If not set, the default value is `/` (the application root). +A user is taken to this URL after logging in, provided they were not asked to login while attempting to access a secured resource, when they will be taken to the originally requested URL. [[nsa-form-login-login-page]] -* **login-page** +`login-page`:: The URL that should be used to render the login page. Maps to the `loginFormUrl` property of the `LoginUrlAuthenticationEntryPoint`. -Defaults to "/login". +Default: `/login`. [[nsa-form-login-login-processing-url]] -* **login-processing-url** +`login-processing-url`:: Maps to the `filterProcessesUrl` property of `UsernamePasswordAuthenticationFilter`. -The default value is "/login". +Default: `/login`. [[nsa-form-login-password-parameter]] * **password-parameter** -The name of the request parameter which contains the password. -Defaults to "password". +The name of the request parameter that contains the password. +Default: `password`. [[nsa-form-login-username-parameter]] -* **username-parameter** -The name of the request parameter which contains the username. -Defaults to "username". +username-parameter:: +The name of the request parameter that contains the username. +Default: `username`. [[nsa-form-login-authentication-success-forward-url]] -* **authentication-success-forward-url** -Maps a `ForwardAuthenticationSuccessHandler` to `authenticationSuccessHandler` property of `UsernamePasswordAuthenticationFilter`. +`authentication-success-forward-url`:: +Maps a `ForwardAuthenticationSuccessHandler` to the `authenticationSuccessHandler` property of `UsernamePasswordAuthenticationFilter`. [[nsa-form-login-authentication-failure-forward-url]] -* **authentication-failure-forward-url** -Maps a `ForwardAuthenticationFailureHandler` to `authenticationFailureHandler` property of `UsernamePasswordAuthenticationFilter`. +`authentication-failure-forward-url`:: +Maps a `ForwardAuthenticationFailureHandler` to the `authenticationFailureHandler` property of `UsernamePasswordAuthenticationFilter`. [[nsa-oauth2-login]] ==== -The <> feature configures authentication support using an OAuth 2.0 and/or OpenID Connect 1.0 Provider. +The <> feature configures authentication support by using an OAuth 2.0 or OpenID Connect 1.0 Provider. [[nsa-oauth2-login-parents]] ===== Parent Elements of -* <> +The parent element of the `` element is the <`>> element. [[nsa-oauth2-login-attributes]] ===== Attributes +The `` has the following attributes: [[nsa-oauth2-login-client-registration-repository-ref]] -* **client-registration-repository-ref** +`client-registration-repository-ref`:: Reference to the `ClientRegistrationRepository`. [[nsa-oauth2-login-authorized-client-repository-ref]] -* **authorized-client-repository-ref** +`authorized-client-repository-ref`:: Reference to the `OAuth2AuthorizedClientRepository`. [[nsa-oauth2-login-authorized-client-service-ref]] -* **authorized-client-service-ref** +`authorized-client-service-ref`:: Reference to the `OAuth2AuthorizedClientService`. [[nsa-oauth2-login-authorization-request-repository-ref]] -* **authorization-request-repository-ref** +`authorization-request-repository-ref`:: Reference to the `AuthorizationRequestRepository`. [[nsa-oauth2-login-authorization-request-resolver-ref]] -* **authorization-request-resolver-ref** +`authorization-request-resolver-ref`:: Reference to the `OAuth2AuthorizationRequestResolver`. [[nsa-oauth2-login-access-token-response-client-ref]] -* **access-token-response-client-ref** +`access-token-response-client-ref`:: Reference to the `OAuth2AccessTokenResponseClient`. [[nsa-oauth2-login-user-authorities-mapper-ref]] -* **user-authorities-mapper-ref** +`user-authorities-mapper-ref`:: Reference to the `GrantedAuthoritiesMapper`. [[nsa-oauth2-login-user-service-ref]] -* **user-service-ref** +`user-service-ref`:: Reference to the `OAuth2UserService`. [[nsa-oauth2-login-oidc-user-service-ref]] -* **oidc-user-service-ref** +`oidc-user-service-ref`:: Reference to the OpenID Connect `OAuth2UserService`. [[nsa-oauth2-login-login-processing-url]] -* **login-processing-url** +`login-processing-url`:: The URI where the filter processes authentication requests. [[nsa-oauth2-login-login-page]] -* **login-page** -The URI to send users to login. +`login-page`:: +The URI to which to send users to login. [[nsa-oauth2-login-authentication-success-handler-ref]] -* **authentication-success-handler-ref** +`authentication-success-handler-ref`:: Reference to the `AuthenticationSuccessHandler`. [[nsa-oauth2-login-authentication-failure-handler-ref]] -* **authentication-failure-handler-ref** +`authentication-failure-handler-ref`:: Reference to the `AuthenticationFailureHandler`. [[nsa-oauth2-login-jwt-decoder-factory-ref]] -* **jwt-decoder-factory-ref** +`jwt-decoder-factory-ref`:: Reference to the `JwtDecoderFactory` used by `OidcAuthorizationCodeAuthenticationProvider`. @@ -960,31 +986,32 @@ Configures <> support. [[nsa-oauth2-client-parents]] ===== Parent Elements of -* <> +The parent of the `` is the <`>> element. [[nsa-oauth2-client-attributes]] ===== Attributes +The `` element has the following attributes: [[nsa-oauth2-client-client-registration-repository-ref]] -* **client-registration-repository-ref** +`client-registration-repository-ref`:: Reference to the `ClientRegistrationRepository`. [[nsa-oauth2-client-authorized-client-repository-ref]] -* **authorized-client-repository-ref** +`authorized-client-repository-ref`:: Reference to the `OAuth2AuthorizedClientRepository`. [[nsa-oauth2-client-authorized-client-service-ref]] -* **authorized-client-service-ref** +`authorized-client-service-ref`:: Reference to the `OAuth2AuthorizedClientService`. [[nsa-oauth2-client-children]] ===== Child Elements of -* <> +The `` has one child element: <`>>. [[nsa-authorization-code-grant]] @@ -995,49 +1022,52 @@ Configures < [[nsa-authorization-code-grant-parents]] ===== Parent Elements of -* <> +The parent element of the `` element is the <> element. [[nsa-authorization-code-grant-attributes]] ===== Attributes +The `` element has the following attributes: [[nsa-authorization-code-grant-authorization-request-repository-ref]] -* **authorization-request-repository-ref** +`authorization-request-repository-ref`:: Reference to the `AuthorizationRequestRepository`. [[nsa-authorization-code-grant-authorization-request-resolver-ref]] -* **authorization-request-resolver-ref** +`authorization-request-resolver-ref`:: Reference to the `OAuth2AuthorizationRequestResolver`. [[nsa-authorization-code-grant-access-token-response-client-ref]] -* **access-token-response-client-ref** +`access-token-response-client-ref`:: Reference to the `OAuth2AccessTokenResponseClient`. [[nsa-client-registrations]] ==== -A container element for client(s) registered (<>) with an OAuth 2.0 or OpenID Connect 1.0 Provider. +The `` is a container element for client(s) registered (<>) with an OAuth 2.0 or OpenID Connect 1.0 Provider. [[nsa-client-registrations-children]] ===== Child Elements of +The `` element has the following child elements: + * <> * <> [[nsa-client-registration]] ==== -Represents a client registered with an OAuth 2.0 or OpenID Connect 1.0 Provider. +The `` represents a client registered with an OAuth 2.0 or OpenID Connect 1.0 Provider. You can have multiple `` elements. [[nsa-client-registration-parents]] ===== Parent Elements of -* <> +The parent element of the `` is the <>. [[nsa-client-registration-attributes]] @@ -1045,17 +1075,17 @@ Represents a client registered with an OAuth 2.0 or OpenID Connect 1.0 Provider. [[nsa-client-registration-registration-id]] -* **registration-id** +registration-`id`:: The ID that uniquely identifies the `ClientRegistration`. [[nsa-client-registration-client-id]] -* **client-id** +`client-id`:: The client identifier. [[nsa-client-registration-client-secret]] -* **client-secret** +`client-secret`:: The client secret. @@ -1066,945 +1096,939 @@ The supported values are *client_secret_basic*, *client_secret_post*, *private_k [[nsa-client-registration-authorization-grant-type]] -* **authorization-grant-type** +`authorization-grant-type`:: The OAuth 2.0 Authorization Framework defines four https://tools.ietf.org/html/rfc6749#section-1.3[Authorization Grant] types. The supported values are `authorization_code`, `client_credentials`, `password`, as well as, extension grant type `urn:ietf:params:oauth:grant-type:jwt-bearer`. [[nsa-client-registration-redirect-uri]] -* **redirect-uri** -The client's registered redirect URI that the _Authorization Server_ redirects the end-user's user-agent to after the end-user has authenticated and authorized access to the client. +`redirect-uri`:: +The client's registered redirect URI to which the _Authorization Server_ redirects the end-user's user-agent after the end-user has authenticated and authorized access to the client. [[nsa-client-registration-scope]] -* **scope** -The scope(s) requested by the client during the Authorization Request flow, such as openid, email, or profile. +`scope`:: +The scope(s) requested by the client during the Authorization Request flow, such as `openid`, `email`, or `profile`. [[nsa-client-registration-client-name]] -* **client-name** +`client-name`:: A descriptive name used for the client. The name may be used in certain scenarios, such as when displaying the name of the client in the auto-generated login page. [[nsa-client-registration-provider-id]] -* **provider-id** -A reference to the associated provider. May reference a `` element or use one of the common providers (google, github, facebook, okta). +`provider-id` +A reference to the associated provider. May reference a `` element or use one of the common providers (Google, Github, Facebook, Okta, and others). [[nsa-provider]] ==== -The configuration information for an OAuth 2.0 or OpenID Connect 1.0 Provider. +The `` element contains the configuration information for an OAuth 2.0 or OpenID Connect 1.0 Provider. [[nsa-provider-parents]] ===== Parent Elements of -* <> +The parent element of the `` element is the <`>> element. [[nsa-provider-attributes]] ===== Attributes +The `` element has the following attributes: + [[nsa-provider-provider-id]] -* **provider-id** +`provider-id`:: The ID that uniquely identifies the provider. [[nsa-provider-authorization-uri]] -* **authorization-uri** -The Authorization Endpoint URI for the Authorization Server. +`authorization-uri`:: +The authorization endpoint URI for the authorization server. [[nsa-provider-token-uri]] -* **token-uri** -The Token Endpoint URI for the Authorization Server. +`token-uri`:: +The token endpoint URI for the authorization server. [[nsa-provider-user-info-uri]] -* **user-info-uri** -The UserInfo Endpoint URI used to access the claims/attributes of the authenticated end-user. +`user-info-uri`:: +The UserInfo endpoint URI used to access the claims and attributes of the authenticated end user. [[nsa-provider-user-info-authentication-method]] -* **user-info-authentication-method** -The authentication method used when sending the access token to the UserInfo Endpoint. -The supported values are *header*, *form* and *query*. +`user-info-authentication-method`:: +The authentication method used when sending the access token to the UserInfo endpoint. +The supported values are `header`, `form`, and `query`. [[nsa-provider-user-info-user-name-attribute]] -* **user-info-user-name-attribute** -The name of the attribute returned in the UserInfo Response that references the Name or Identifier of the end-user. +`user-info-user-name-attribute`:: +The name of the attribute returned in the UserInfo response that references the name or edentifier of the end-user. [[nsa-provider-jwk-set-uri]] -* **jwk-set-uri** -The URI used to retrieve the https://tools.ietf.org/html/rfc7517[JSON Web Key (JWK)] Set from the Authorization Server, which contains the cryptographic key(s) used to verify the https://tools.ietf.org/html/rfc7515[JSON Web Signature (JWS)] of the ID Token and optionally the UserInfo Response. +`jwk-set-uri`:: +The URI used to retrieve the https://tools.ietf.org/html/rfc7517[JSON Web Key (JWK)] set from the authorization server, which contains the cryptographic key(s) used to verify the https://tools.ietf.org/html/rfc7515[JSON Web Signature (JWS)] of the ID Token and (optionally) the UserInfo response. [[nsa-provider-issuer-uri]] -* **issuer-uri** -The URI used to initially configure a `ClientRegistration` using discovery of an OpenID Connect Provider's https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfig[Configuration endpoint] or an Authorization Server's https://tools.ietf.org/html/rfc8414#section-3[Metadata endpoint]. +issuer-uri:: +The URI used to initially configure a `ClientRegistration` by using discovery of an OpenID Connect Provider's https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfig[configuration endpoint] or an Authorization Server's https://tools.ietf.org/html/rfc8414#section-3[metadata endpoint]. [[nsa-oauth2-resource-server]] ==== -Adds a `BearerTokenAuthenticationFilter`, `BearerTokenAuthenticationEntryPoint`, and `BearerTokenAccessDeniedHandler` to the configuration. +Adds a `BearerTokenAuthenticationFilter`, a `BearerTokenAuthenticationEntryPoint`, and a `BearerTokenAccessDeniedHandler` to the configuration. In addition, either `` or `` must be specified. [[nsa-oauth2-resource-server-parents]] ===== Parents Elements of -* <> +The parent element of the `` is the <`>> element. [[nsa-oauth2-resource-server-children]] ===== Child Elements of -* <> -* <> +The `` element has the following child elements: + +* <`>> +* <`>> [[nsa-oauth2-resource-server-attributes]] ===== Attributes +The `` element has the following attributes: + [[nsa-oauth2-resource-server-authentication-manager-resolver-ref]] -* **authentication-manager-resolver-ref** -Reference to an `AuthenticationManagerResolver` which will resolve the `AuthenticationManager` at request time +`authentication-manager-resolver-ref`:: +Reference to an `AuthenticationManagerResolver`, which resolves the `AuthenticationManager` at request time. [[nsa-oauth2-resource-server-bearer-token-resolver-ref]] -* **bearer-token-resolver-ref** -Reference to a `BearerTokenResolver` which will retrieve the bearer token from the request +`bearer-token-resolver-ref`:: +Reference to a `BearerTokenResolver`, which retrieves the bearer token from the request. [[nsa-oauth2-resource-server-entry-point-ref]] -* **entry-point-ref** -Reference to a `AuthenticationEntryPoint` which will handle unauthorized requests +`entry-point-ref`:: +Reference to a `AuthenticationEntryPoint`, which handles unauthorized requests. [[nsa-jwt]] -==== -Represents an OAuth 2.0 Resource Server that will authorize JWTs +==== The element +The `` element represents an OAuth 2.0 Resource Server that authorizes JWTs (JSON Web Tokens). [[nsa-jwt-parents]] ===== Parent Elements of -* <> +The parent element of the `` element is the <`>> element. [[nsa-jwt-attributes]] ===== Attributes +The `` element has the following attributes: + [[nsa-jwt-jwt-authentication-converter-ref]] -* **jwt-authentication-converter-ref** -Reference to a `Converter` +`jwt-authentication-converter-ref`:: +Reference to a `Converter`. [[nsa-jwt-decoder-ref]] -* **jwt-decoder-ref** -Reference to a `JwtDecoder`. This is a larger component that overrides `jwk-set-uri` +`jwt-decoder-ref`:: +Reference to a `JwtDecoder`. This is a larger component that overrides `jwk-set-uri`. [[nsa-jwt-jwk-set-uri]] -* **jwk-set-uri** -The JWK Set Uri used to load signing verification keys from an OAuth 2.0 Authorization Server +`jwk-set-uri`:: +The JWK Set URI used to load signing verification keys from an OAuth 2.0 Authorization Server. [[nsa-opaque-token]] -==== -Represents an OAuth 2.0 Resource Server that will authorize opaque tokens +==== The Element +Represents an OAuth 2.0 Resource Server that authorizes opaque tokens. [[nsa-opaque-token-parents]] ===== Parent Elements of -* <> +The parent element of the `> element. [[nsa-opaque-token-attributes]] ===== Attributes [[nsa-opaque-token-introspector-ref]] -* **introspector-ref** +`introspector-ref`:: Reference to an `OpaqueTokenIntrospector`. This is a larger component that overrides `introspection-uri`, `client-id`, and `client-secret`. [[nsa-opaque-token-introspection-uri]] -* **introspection-uri** -The Introspection Uri used to introspect the details of an opaque token. Should be accompanied with a `client-id` and `client-secret`. +`introspection-uri`:: +The Introspection URI used to introspect the details of an opaque token. It should be accompanied by a `client-id` and `client-secret`. [[nsa-opaque-token-client-id]] -* **client-id** -The Client Id to use for client authentication against the provided `introspection-uri`. +`client-id`:: +The client ID to use for client authentication against the provided `introspection-uri`. [[nsa-opaque-token-client-secret]] -* **client-secret** -The Client Secret to use for client authentication against the provided `introspection-uri`. +`client-secret`:: +The client secret to use for client authentication against the provided `introspection-uri`. [[nsa-http-basic]] ==== -Adds a `BasicAuthenticationFilter` and `BasicAuthenticationEntryPoint` to the configuration. -The latter will only be used as the configuration entry point if form-based login is not enabled. +The adds a `BasicAuthenticationFilter` and `BasicAuthenticationEntryPoint` to the configuration. +The latter is used as the configuration entry point only if form-based login is not enabled. [[nsa-http-basic-parents]] ===== Parent Elements of -* <> +The parent element of the `` element is the <`>> element. [[nsa-http-basic-attributes]] ===== Attributes +The `` element has the following attributes: + [[nsa-http-basic-authentication-details-source-ref]] -* **authentication-details-source-ref** -Reference to an `AuthenticationDetailsSource` which will be used by the authentication filter +`authentication-details-source-ref`:: +Reference to an `AuthenticationDetailsSource`, which is used by the authentication filter. [[nsa-http-basic-entry-point-ref]] -* **entry-point-ref** -Sets the `AuthenticationEntryPoint` which is used by the `BasicAuthenticationFilter`. +`entry-point-ref`:: +Sets the `AuthenticationEntryPoint`, which is used by the `BasicAuthenticationFilter`. [[nsa-http-firewall]] ==== Element -This is a top-level element which can be used to inject a custom implementation of `HttpFirewall` into the `FilterChainProxy` created by the namespace. +`` is a top-level element that you can use to inject a custom implementation of `HttpFirewall` into the `FilterChainProxy` created by the namespace. The default implementation should be suitable for most applications. [[nsa-http-firewall-attributes]] ===== Attributes +`` has a single attribute: [[nsa-http-firewall-ref]] -* **ref** +`ref`:: Defines a reference to a Spring bean that implements `HttpFirewall`. [[nsa-intercept-url]] ==== -This element is used to define the set of URL patterns that the application is interested in and to configure how they should be handled. -It is used to construct the `FilterInvocationSecurityMetadataSource` used by the `FilterSecurityInterceptor`. -It is also responsible for configuring a `ChannelProcessingFilter` if particular URLs need to be accessed by HTTPS, for example. +`` element defines the set of URL patterns that the application is interested in and configures how they should be handled. +It constructs the `FilterInvocationSecurityMetadataSource` used by the `FilterSecurityInterceptor`. +It is also responsible for configuring a `ChannelProcessingFilter` (if particular URLs need to be accessed by HTTPS, for example). When matching the specified patterns against an incoming request, the matching is done in the order in which the elements are declared. -So the most specific patterns should come first and the most general should come last. +So, the most specific patterns should come first and the most general should come last. [[nsa-intercept-url-parents]] ===== Parent Elements of +The parent elements of the `` element are: -* <> -* <> - +* <`>> +* <`>> [[nsa-intercept-url-attributes]] ===== Attributes +The `` element has the following parameters: [[nsa-intercept-url-access]] -* **access** -Lists the access attributes which will be stored in the `FilterInvocationSecurityMetadataSource` for the defined URL pattern/method combination. +`access`:: +Lists the access attributes, which are stored in the `FilterInvocationSecurityMetadataSource` for the defined URL pattern and method combination. This should be a comma-separated list of the security configuration attributes (such as role names). [[nsa-intercept-url-method]] -* **method** -The HTTP Method which will be used in combination with the pattern and servlet path (optional) to match an incoming request. -If omitted, any method will match. -If an identical pattern is specified with and without a method, the method-specific match will take precedence. +`method`:: +The HTTP Method that is used in combination with the pattern and servlet path (optional) to match an incoming request. +If omitted, any method matchs. +If an identical pattern is specified with and without a method, the method-specific match takes precedence. [[nsa-intercept-url-pattern]] -* **pattern** -The pattern which defines the URL path. -The content will depend on the `request-matcher` attribute from the containing http element, so will default to ant path syntax. +`pattern`:: +The pattern that defines the URL path. +The content depends on the `request-matcher` attribute from the containing `` element, so it defaults to Ant path syntax. [[nsa-intercept-url-request-matcher-ref]] -* **request-matcher-ref** -A reference to a `RequestMatcher` that will be used to determine if this `` is used. +`request-matcher-ref`:: +A reference to a `RequestMatcher` that is used to determine if this `` is used. [[nsa-intercept-url-requires-channel]] -* **requires-channel** -Can be "http" or "https" depending on whether a particular URL pattern should be accessed over HTTP or HTTPS respectively. -Alternatively the value "any" can be used when there is no preference. -If this attribute is present on any `` element, then a `ChannelProcessingFilter` will be added to the filter stack and its additional dependencies added to the application context. +`requires-channel`:: +Can be `http` or `https`, depending on whether a particular URL pattern should be accessed over HTTP or HTTPS, respectively. +Alternatively, you can use a value of `any` when you have no preference. +If this attribute is present on any `` element, a `ChannelProcessingFilter` is added to the filter stack and its additional dependencies are added to the application context. -If a `` configuration is added, this will be used to by the `SecureChannelProcessor` and `InsecureChannelProcessor` beans to determine the ports used for redirecting to HTTP/HTTPS. +If a `` configuration is added, it is used by the `SecureChannelProcessor` and `InsecureChannelProcessor` beans to determine the ports used for redirecting to HTTP and HTTPS. -NOTE: This property is invalid for <> +NOTE: This property is invalid for <> [[nsa-intercept-url-servlet-path]] -* **servlet-path** -The servlet path which will be used in combination with the pattern and HTTP method to match an incoming request. -This attribute is only applicable when <> is 'mvc'. -In addition, the value is only required in the following 2 use cases: 1) There are 2 or more `HttpServlet` 's registered in the `ServletContext` that have mappings starting with `'/'` and are different; 2) The pattern starts with the same value of a registered `HttpServlet` path, excluding the default (root) `HttpServlet` `'/'`. +`servlet-path`:: +The servlet path to be used, in combination with the pattern and HTTP method, to match an incoming request. +This attribute is only applicable when <> is `mvc`. +In addition, the value is only required in the following two use cases: +* Two or more `HttpServlet` instances that have mappings starting with `/` and are different are registered in the `ServletContext`. +* The pattern starts with the same value of a registered `HttpServlet` path, excluding the default (root) `HttpServlet` `/`. -NOTE: This property is invalid for <> +NOTE: This property is invalid for <> [[nsa-jee]] ==== -Adds a J2eePreAuthenticatedProcessingFilter to the filter chain to provide integration with container authentication. -[[nsa-jee-parents]] -===== Parent Elements of +The `` element a dds a `J2eePreAuthenticatedProcessingFilter` to the filter chain to provide integration with container authentication. -* <> +[[nsa-jee-parents]] +===== Parent Elements of +The parent element of the `` element is the <`>> element. [[nsa-jee-attributes]] ===== Attributes +The `` element has the following attributes: [[nsa-jee-mappable-roles]] -* **mappable-roles** -A comma-separate list of roles to look for in the incoming HttpServletRequest. +`mappable-roles`:: +A comma-separated list of roles to look for in the incoming `HttpServletRequest`. [[nsa-jee-user-service-ref]] -* **user-service-ref** -A reference to a user-service (or UserDetailsService bean) Id +`user-service-ref`:: +A reference to a user-service (or `UserDetailsService` bean) ID. [[nsa-logout]] ==== -Adds a `LogoutFilter` to the filter stack. -This is configured with a `SecurityContextLogoutHandler`. +The `` element adds a `LogoutFilter` to the filter stack. +It is configured by a `SecurityContextLogoutHandler`. [[nsa-logout-parents]] ===== Parent Elements of - -* <> - +The parent element of the `` element is the <`>> element. [[nsa-logout-attributes]] ===== Attributes +The `` element has the following attributes: [[nsa-logout-delete-cookies]] -* **delete-cookies** -A comma-separated list of the names of cookies which should be deleted when the user logs out. +`delete-cookies`:: +A comma-separated list of the names of cookies that should be deleted when the user logs out. [[nsa-logout-invalidate-session]] -* **invalidate-session** +`invalidate-session`:: Maps to the `invalidateHttpSession` of the `SecurityContextLogoutHandler`. -Defaults to "true", so the session will be invalidated on logout. +Default: `true` (the session is invalidated on logout) [[nsa-logout-logout-success-url]] -* **logout-success-url** -The destination URL which the user will be taken to after logging out. -Defaults to /?logout (i.e. /login?logout) - +`logout-success-url`:: +The destination URL to which the user is taken after logging out. +Default: `/?logout` (usually `/login?logout`) + - -Setting this attribute will inject the `SessionManagementFilter` with a `SimpleRedirectInvalidSessionStrategy` configured with the attribute value. -When an invalid session ID is submitted, the strategy will be invoked, redirecting to the configured URL. +Setting this attribute injects the `SessionManagementFilter` with a `SimpleRedirectInvalidSessionStrategy` configured with the attribute value. +When an invalid session ID is submitted, the strategy is invoked, redirecting to the configured URL. [[nsa-logout-logout-url]] -* **logout-url** -The URL which will cause a logout (i.e. which will be processed by the filter). -Defaults to "/logout". +`logout-url`:: +The URL that causes a logout (which is processed by the filter). +Default: `/logout` [[nsa-logout-success-handler-ref]] -* **success-handler-ref** -May be used to supply an instance of `LogoutSuccessHandler` which will be invoked to control the navigation after logging out. +`success-handler-ref`:: +Can be used to supply an instance of `LogoutSuccessHandler` that is invoked to control the navigation after logging out. [[nsa-openid-login]] ==== -Similar to `` and has the same attributes. -The default value for `login-processing-url` is "/login/openid". -An `OpenIDAuthenticationFilter` and `OpenIDAuthenticationProvider` will be registered. +The `` element is similar to the `` element and has the same attributes. +The default value for `login-processing-url` is `/login/openid`. +An `OpenIDAuthenticationFilter` and a `OpenIDAuthenticationProvider` are registered. The latter requires a reference to a `UserDetailsService`. -Again, this can be specified by `id`, using the `user-service-ref` attribute, or will be located automatically in the application context. +You can specify this reference by `id`, by using the `user-service-ref` attribute, or you can let it be automatically located in the application context. [[nsa-openid-login-parents]] ===== Parent Elements of - -* <> - +The parent element of the `` element is the <`>> element. [[nsa-openid-login-attributes]] ===== Attributes +The `` element has the following attributes: [[nsa-openid-login-always-use-default-target]] -* **always-use-default-target** -Whether the user should always be redirected to the default-target-url after login. +`always-use-default-target`:: +Whether the user should always be redirected to the `default-target-url` after login. [[nsa-openid-login-authentication-details-source-ref]] -* **authentication-details-source-ref** -Reference to an AuthenticationDetailsSource which will be used by the authentication filter +`authentication-details-source-ref`:: +Reference to an `AuthenticationDetailsSource` that is used by the authentication filter. [[nsa-openid-login-authentication-failure-handler-ref]] -* **authentication-failure-handler-ref** -Reference to an AuthenticationFailureHandler bean which should be used to handle a failed authentication request. -Should not be used in combination with authentication-failure-url as the implementation should always deal with navigation to the subsequent destination +`authentication-failure-handler-ref`:: +Reference to an `AuthenticationFailureHandler` bean that should be used to handle a failed authentication request. +It should not be used in combination with `authentication-failure-url`, as the implementation should always deal with navigation to the subsequent destination. [[nsa-openid-login-authentication-failure-url]] -* **authentication-failure-url** +authentication-failure-url:: The URL for the login failure page. -If no login failure URL is specified, Spring Security will automatically create a failure login URL at /login?login_error and a corresponding filter to render that login failure URL when requested. +If no login failure URL is specified, Spring Security automatically creates a failure login URL at `/login?login_error` and a corresponding filter to render that login failure URL when requested. [[nsa-openid-login-authentication-success-forward-url]] -* **authentication-success-forward-url** +authentication-success-forward-url:: Maps a `ForwardAuthenticationSuccessHandler` to `authenticationSuccessHandler` property of `UsernamePasswordAuthenticationFilter`. [[nsa-openid-login-authentication-failure-forward-url]] -* **authentication-failure-forward-url** +`authentication-failure-forward-url`:: Maps a `ForwardAuthenticationFailureHandler` to `authenticationFailureHandler` property of `UsernamePasswordAuthenticationFilter`. [[nsa-openid-login-authentication-success-handler-ref]] -* **authentication-success-handler-ref** -Reference to an AuthenticationSuccessHandler bean which should be used to handle a successful authentication request. -Should not be used in combination with <> (or <>) as the implementation should always deal with navigation to the subsequent destination +`authentication-success-handler-ref`:: +Reference to an `AuthenticationSuccessHandler` bean that should be used to handle a successful authentication request. +Should not be used in combination with <> (or <>) as the implementation should always deal with navigation to the subsequent destination [[nsa-openid-login-default-target-url]] -* **default-target-url** -The URL that will be redirected to after successful authentication, if the user's previous action could not be resumed. +`default-target-url`:: +The URL to which to redirect after successful authentication, if the user's previous action could not be resumed. This generally happens if the user visits a login page without having first requested a secured operation that triggers authentication. -If unspecified, defaults to the root of the application. +If unspecified, it defaults to the root of the application. [[nsa-openid-login-login-page]] -* **login-page** +`login-page`:: The URL for the login page. -If no login URL is specified, Spring Security will automatically create a login URL at /login and a corresponding filter to render that login URL when requested. +If no login URL is specified, Spring Security automatically creates a login URL at `/login` and a corresponding filter to render that login URL when requested. [[nsa-openid-login-login-processing-url]] -* **login-processing-url** -The URL that the login form is posted to. -If unspecified, it defaults to /login. +`login-processing-url`:: +The URL to which the login form is posted. +If unspecified, it defaults to `/login`. [[nsa-openid-login-password-parameter]] -* **password-parameter** -The name of the request parameter which contains the password. -Defaults to "password". +`password-parameter`:: +The name of the request parameter that contains the password. +Default: `password` [[nsa-openid-login-user-service-ref]] -* **user-service-ref** -A reference to a user-service (or UserDetailsService bean) Id +`user-service-ref`:: +A reference to a user-service (or `UserDetailsService` bean) ID [[nsa-openid-login-username-parameter]] -* **username-parameter** -The name of the request parameter which contains the username. -Defaults to "username". +`username-parameter`:: +The name of the request parameter that contains the username. +Default: `username` [[nsa-openid-login-children]] ===== Child Elements of -* <> +The `` element has only one child attribute: <`>>. [[nsa-attribute-exchange]] -==== -The `attribute-exchange` element defines the list of attributes which should be requested from the identity provider. -An example can be found in the <> section of the namespace configuration chapter. -More than one can be used, in which case each must have an `identifier-match` attribute, containing a regular expression which is matched against the supplied OpenID identifier. -This allows different attribute lists to be fetched from different providers (Google, Yahoo etc). +==== Element +The `` element defines the list of attributes to request from the identity provider. +You can find an example in the <> section of the namespace configuration chapter. +You can use more than one. In that case, each must have an `identifier-match` attribute that contains a regular expression, which is matched against the supplied OpenID identifier. +This lets different attribute lists be fetched from different providers (Google, Yahoo, and others). [[nsa-attribute-exchange-parents]] ===== Parent Elements of - -* <> - +The parent element of the `` element is the <`>> element. [[nsa-attribute-exchange-attributes]] ===== Attributes +The `` element has a single attribute: + [[nsa-attribute-exchange-identifier-match]] -* **identifier-match** -A regular expression which will be compared against the claimed identity, when deciding which attribute-exchange configuration to use during authentication. +`identifier-match`:: +A regular expression that is compared against the claimed identity when deciding which `attribute-exchange` configuration to use during authentication. [[nsa-attribute-exchange-children]] ===== Child Elements of - -* <> - +The `` element has a single child attribute: <`>>. [[nsa-openid-attribute]] ==== -Attributes used when making an OpenID AX https://openid.net/specs/openid-attribute-exchange-1_0.html#fetch_request[ Fetch Request] +The `` element defines the attributes to use when making an OpenID AX https://openid.net/specs/openid-attribute-exchange-1_0.html#fetch_request[ Fetch Request]. [[nsa-openid-attribute-parents]] ===== Parent Elements of - -* <> - +The parent element of the `` element is the <> element. [[nsa-openid-attribute-attributes]] ===== Attributes +The `` element has the following attributes: [[nsa-openid-attribute-count]] -* **count** -Specifies the number of attributes that you wish to get back. -For example, return 3 emails. -The default value is 1. +`count`:: +Specifies the number of attributes that you wish to get back -- for example, return three emails. +Default: 1 [[nsa-openid-attribute-name]] -* **name** -Specifies the name of the attribute that you wish to get back. -For example, email. +`name`:: +Specifies the name of the attribute that you wish to get back -- for example, `email`. [[nsa-openid-attribute-required]] -* **required** -Specifies if this attribute is required to the OP, but does not error out if the OP does not return the attribute. -Default is false. +`required`:: +Specifies whether this attribute is required to the OP but does not error out if the OP does not return the attribute. +Default: `false` [[nsa-openid-attribute-type]] -* **type** -Specifies the attribute type. -For example, https://axschema.org/contact/email. +`type`:: +Specifies the attribute type -- for example, `https://axschema.org/contact/email`. See your OP's documentation for valid attribute types. [[nsa-port-mappings]] -==== -By default, an instance of `PortMapperImpl` will be added to the configuration for use in redirecting to secure and insecure URLs. -This element can optionally be used to override the default mappings which that class defines. +==== Element +By default, an instance of `PortMapperImpl` is added to the configuration for use in redirecting to secure and insecure URLs. +You can optionally use the `` element to override the default mappings that `PortMapperImpl` defines. Each child `` element defines a pair of HTTP:HTTPS ports. -The default mappings are 80:443 and 8080:8443. -An example of overriding these can be found in <>. +The default mappings are `80:443` and `8080:8443`. +You can find an example of overriding these values in <>. [[nsa-port-mappings-parents]] -===== Parent Elements of - - -* <> +===== Parent Element of +The parent element of the `` element is the <`>> element. [[nsa-port-mappings-children]] ===== Child Elements of - -* <> - +The `` element has a single child element: <>. [[nsa-port-mapping]] ==== -Provides a method to map http ports to https ports when forcing a redirect. +The `` element provides a method to map HTTP ports to HTTPS ports when forcing a redirect. [[nsa-port-mapping-parents]] ===== Parent Elements of - -* <> +The parent element of the `` element is the <`>> element. [[nsa-port-mapping-attributes]] ===== Attributes +The `` element has the following attributes: [[nsa-port-mapping-http]] -* **http** -The http port to use. +`http`:: +The HTTP port to use. [[nsa-port-mapping-https]] -* **https** -The https port to use. +`https`:: +The HTTPS port to use. [[nsa-remember-me]] ==== -Adds the `RememberMeAuthenticationFilter` to the stack. -This in turn will be configured with either a `TokenBasedRememberMeServices`, a `PersistentTokenBasedRememberMeServices` or a user-specified bean implementing `RememberMeServices` depending on the attribute settings. +The `` element adds the `RememberMeAuthenticationFilter` to the stack. +This filter is, in turn, configured with either a `TokenBasedRememberMeServices`, a `PersistentTokenBasedRememberMeServices`, or a user-specified bean that implements `RememberMeServices`, depending on the attribute settings. [[nsa-remember-me-parents]] ===== Parent Elements of - -* <> - +The parent element of the `` element is the <`>> element. [[nsa-remember-me-attributes]] ===== Attributes +The `` element has the following attributes: [[nsa-remember-me-authentication-success-handler-ref]] -* **authentication-success-handler-ref** -Sets the `authenticationSuccessHandler` property on the `RememberMeAuthenticationFilter` if custom navigation is required. +`authentication-success-handler-ref`:: +Sets the `authenticationSuccessHandler` property on the `RememberMeAuthenticationFilter` when custom navigation is required. The value should be the name of a `AuthenticationSuccessHandler` bean in the application context. [[nsa-remember-me-data-source-ref]] -* **data-source-ref** +`data-source-ref`:: A reference to a `DataSource` bean. -If this is set, `PersistentTokenBasedRememberMeServices` will be used and configured with a `JdbcTokenRepositoryImpl` instance. +If this attribute is set, `PersistentTokenBasedRememberMeServices` is used and configured with a `JdbcTokenRepositoryImpl` instance. [[nsa-remember-me-remember-me-parameter]] -* **remember-me-parameter** -The name of the request parameter which toggles remember-me authentication. -Defaults to "remember-me". -Maps to the "parameter" property of `AbstractRememberMeServices`. +`remember-me-parameter`:: +The name of the request parameter that toggles remember-me authentication. +Defaults: `remember-me` +Maps to the `parameter` property of `AbstractRememberMeServices`. [[nsa-remember-me-remember-me-cookie]] -* **remember-me-cookie** -The name of cookie which store the token for remember-me authentication. -Defaults to "remember-me". -Maps to the "cookieName" property of `AbstractRememberMeServices`. +`remember-me-cookie`:: +The name of the cookie that stores the token for remember-me authentication. +Defaults: `remember-me` +This attribute maps to the `cookieName` property of `AbstractRememberMeServices`. [[nsa-remember-me-key]] -* **key** -Maps to the "key" property of `AbstractRememberMeServices`. -Should be set to a unique value to ensure that remember-me cookies are only valid within the one application footnote:[ -This doesn't affect the use of `PersistentTokenBasedRememberMeServices`, where the tokens are stored on the server side. -]. -If this is not set a secure random value will be generated. -Since generating secure random values can take a while, setting this value explicitly can help improve startup times when using the remember-me functionality. +`key`:: +Maps to the `key` property of `AbstractRememberMeServices`. +Should be set to a unique value to ensure that remember-me cookies are valid only within one application +This key does not affect the use of `PersistentTokenBasedRememberMeServices`, where the tokens are stored on the server side. +If this key is not set, a secure random value is generated. +Since generating secure random values can take a while, explicitly setting this value can help improve startup times when you use the remember-me functionality. [[nsa-remember-me-services-alias]] -* **services-alias** -Exports the internally defined `RememberMeServices` as a bean alias, allowing it to be used by other beans in the application context. +`services-alias`:: +Exports the internally defined `RememberMeServices` as a bean alias, letting it be used by other beans in the application context. [[nsa-remember-me-services-ref]] -* **services-ref** -Allows complete control of the `RememberMeServices` implementation that will be used by the filter. -The value should be the `id` of a bean in the application context which implements this interface. -Should also implement `LogoutHandler` if a logout filter is in use. +`services-ref`:: +Allows complete control of the `RememberMeServices` implementation that is used by the filter. +The value should be the `id` of a bean in the application context that implements this interface. +It should also implement `LogoutHandler` if a logout filter is in use. [[nsa-remember-me-token-repository-ref]] -* **token-repository-ref** +`token-repository-ref`:: Configures a `PersistentTokenBasedRememberMeServices` but allows the use of a custom `PersistentTokenRepository` bean. [[nsa-remember-me-token-validity-seconds]] -* **token-validity-seconds** +`token-validity-seconds`:: Maps to the `tokenValiditySeconds` property of `AbstractRememberMeServices`. Specifies the period in seconds for which the remember-me cookie should be valid. -By default it will be valid for 14 days. +By default, it is valid for 14 days. [[nsa-remember-me-use-secure-cookie]] -* **use-secure-cookie** -It is recommended that remember-me cookies are only submitted over HTTPS and thus should be flagged as "secure". -By default, a secure cookie will be used if the connection over which the login request is made is secure (as it should be). -If you set this property to `false`, secure cookies will not be used. -Setting it to `true` will always set the secure flag on the cookie. +`use-secure-cookie`:: +We recommend that you submit remember-me cookies over HTTPS and that you flag as "`secure`". +By default, a secure cookie is used if the connection for the login request is secure (as it should be). +If you set this property to `false`, secure cookies are not used. +Setting it to `true` always sets the secure flag on the cookie. This attribute maps to the `useSecureCookie` property of `AbstractRememberMeServices`. [[nsa-remember-me-user-service-ref]] -* **user-service-ref** +`user-service-ref`:: The remember-me services implementations require access to a `UserDetailsService`, so there has to be one defined in the application context. -If there is only one, it will be selected and used automatically by the namespace configuration. -If there are multiple instances, you can specify a bean `id` explicitly using this attribute. +If there is only one, it is selected and automatically used by the namespace configuration. +If there are multiple instances, you can specify a bean `id` explicitly by setting this attribute. [[nsa-request-cache]] ==== Element -Sets the `RequestCache` instance which will be used by the `ExceptionTranslationFilter` to store request information before invoking an `AuthenticationEntryPoint`. +Sets the `RequestCache` instance, which is used by the `ExceptionTranslationFilter` to store request information before invoking an `AuthenticationEntryPoint`. [[nsa-request-cache-parents]] ===== Parent Elements of -* <> +The parent element of the `` element is the <`>> element. [[nsa-request-cache-attributes]] ===== Attributes +The `` element has only one attribute: [[nsa-request-cache-ref]] -* **ref** +`ref`:: Defines a reference to a Spring bean that is a `RequestCache`. [[nsa-session-management]] ==== -Session-management related functionality is implemented by the addition of a `SessionManagementFilter` to the filter stack. +Session-management functionality is implemented by the addition of a `SessionManagementFilter` to the filter stack. This element adds that filter. [[nsa-session-management-parents]] ===== Parent Elements of -* <> - +The parent element of the `` element is the <`>> element. [[nsa-session-management-attributes]] ===== Attributes +The `` has the following attributes: [[nsa-session-management-invalid-session-url]] -* **invalid-session-url** -Setting this attribute will inject the `SessionManagementFilter` with a `SimpleRedirectInvalidSessionStrategy` configured with the attribute value. -When an invalid session ID is submitted, the strategy will be invoked, redirecting to the configured URL. +`invalid-session-url`:: +Setting this attribute injects a `SessionManagementFilter` with a `SimpleRedirectInvalidSessionStrategy` that is configured with the attribute value. +When an invalid session ID is submitted, the strategy is invoked, redirecting to the configured URL. [[nsa-session-management-invalid-session-strategy-ref]] -* **invalid-session-url** -Allows injection of the InvalidSessionStrategy instance used by the SessionManagementFilter. -Use either this or the `invalid-session-url` attribute but not both. +`invalid-session-url`:: +Allows injection of the `InvalidSessionStrategy` instance, which is used by the `SessionManagementFilter`. +Use either this attribute or the `invalid-session-url` attribute but not both. [[nsa-session-management-session-authentication-error-url]] -* **session-authentication-error-url** -Defines the URL of the error page which should be shown when the SessionAuthenticationStrategy raises an exception. -If not set, an unauthorized (401) error code will be returned to the client. -Note that this attribute doesn't apply if the error occurs during a form-based login, where the URL for authentication failure will take precedence. +`session-authentication-error-url` +Defines the URL of the error page, which should be shown when the `SessionAuthenticationStrategy` raises an exception. +If not set, an unauthorized (401) error code is returned to the client. +Note that this attribute does not apply if the error occurs during a form-based login, where the URL for authentication failure takes precedence. [[nsa-session-management-session-authentication-strategy-ref]] -* **session-authentication-strategy-ref** -Allows injection of the SessionAuthenticationStrategy instance used by the SessionManagementFilter +`session-authentication-strategy-ref`:: +Allows injection of a `SessionAuthenticationStrategy` instance, which is used by the `SessionManagementFilter`. [[nsa-session-management-session-fixation-protection]] -* **session-fixation-protection** -Indicates how session fixation protection will be applied when a user authenticates. -If set to "none", no protection will be applied. -"newSession" will create a new empty session, with only Spring Security-related attributes migrated. -"migrateSession" will create a new session and copy all session attributes to the new session. -In Servlet 3.1 (Java EE 7) and newer containers, specifying "changeSessionId" will keep the existing session and use the container-supplied session fixation protection (HttpServletRequest#changeSessionId()). -Defaults to "changeSessionId" in Servlet 3.1 and newer containers, "migrateSession" in older containers. -Throws an exception if "changeSessionId" is used in older containers. - -+ - +session-fixation-protection:: +Indicates how session fixation protection is applied when a user authenticates. +If set to `none`, no protection is applied. +`newSession` creates a new empty session, with only Spring Security-related attributes migrated. +`migrateSession` creates a new session and copies all session attributes to the new session. +In Servlet 3.1 (Java EE 7) and newer containers, specifying `changeSessionId` keeps the existing session and uses the container-supplied session fixation protection (`HttpServletRequest#changeSessionId()`). +It defaults to `changeSessionId` in Servlet 3.1 and newer containers, `migrateSession` in older containers. +It throws an exception if `changeSessionId` is used in older containers. If session fixation protection is enabled, the `SessionManagementFilter` is injected with an appropriately configured `DefaultSessionAuthenticationStrategy`. -See the Javadoc for this class for more details. +See the {security-api-url}org/springframework/security/web/session/SessionManagementFilter.html[Javadoc for `SessionManagementFilter`] for more details. [[nsa-session-management-children]] ===== Child Elements of - -* <> - +The `` element has only one child element: <`>> [[nsa-concurrency-control]] ==== -Adds support for concurrent session control, allowing limits to be placed on the number of active sessions a user can have. -A `ConcurrentSessionFilter` will be created, and a `ConcurrentSessionControlAuthenticationStrategy` will be used with the `SessionManagementFilter`. -If a `form-login` element has been declared, the strategy object will also be injected into the created authentication filter. -An instance of `SessionRegistry` (a `SessionRegistryImpl` instance unless the user wishes to use a custom bean) will be created for use by the strategy. +The `` adds support for concurrent session control, letting limits be placed on the number of active sessions a user can have. +A `ConcurrentSessionFilter` is created, and a `ConcurrentSessionControlAuthenticationStrategy` is used with the `SessionManagementFilter`. +If a `form-login` element has been declared, the strategy object is also injected into the created authentication filter. +An instance of `SessionRegistry` (a `SessionRegistryImpl` instance unless the user wishes to use a custom bean) is created for use by the strategy. [[nsa-concurrency-control-parents]] ===== Parent Elements of - -* <> - +The parent element of the `` element is the <`>> element. [[nsa-concurrency-control-attributes]] ===== Attributes +The `` element has the following attributes: + [[nsa-concurrency-control-error-if-maximum-exceeded]] -* **error-if-maximum-exceeded** -If set to "true" a `SessionAuthenticationException` will be raised when a user attempts to exceed the maximum allowed number of sessions. -The default behaviour is to expire the original session. +`error-if-maximum-exceeded`:: +If set to `true`, a `SessionAuthenticationException` is raised when a user attempts to exceed the maximum allowed number of sessions. +The default behavior is to expire the original session. [[nsa-concurrency-control-expired-url]] -* **expired-url** -The URL a user will be redirected to if they attempt to use a session which has been "expired" by the concurrent session controller because the user has exceeded the number of allowed sessions and has logged in again elsewhere. -Should be set unless `exception-if-maximum-exceeded` is set. -If no value is supplied, an expiry message will just be written directly back to the response. +`expired-url`:: +The URL to which a user is redirected if they attempt to use a session which has been "`expired`" by the concurrent session controller because the user has exceeded the number of allowed sessions and has logged in again elsewhere. +This attribute should be set unless `exception-if-maximum-exceeded` is set. +If no value is supplied, an expiry message is written directly back to the response. [[nsa-concurrency-control-expired-session-strategy-ref]] -* **expired-url** -Allows injection of the ExpiredSessionStrategy instance used by the ConcurrentSessionFilter +`expired-url`:: +Allows injection of an `ExpiredSessionStrategy` instance, which is used by the `ConcurrentSessionFilter`. [[nsa-concurrency-control-max-sessions]] -* **max-sessions** +`max-sessions`:: Maps to the `maximumSessions` property of `ConcurrentSessionControlAuthenticationStrategy`. Specify `-1` as the value to support unlimited sessions. [[nsa-concurrency-control-session-registry-alias]] -* **session-registry-alias** +`session-registry-alias`:: +Exposes an internal bean and gives it a name that you use elsewhere in your configuration It can also be useful to have a reference to the internal session registry for use in your own beans or an admin interface. -You can expose the internal bean using the `session-registry-alias` attribute, giving it a name that you can use elsewhere in your configuration. [[nsa-concurrency-control-session-registry-ref]] -* **session-registry-ref** -The user can supply their own `SessionRegistry` implementation using the `session-registry-ref` attribute. -The other concurrent session control beans will be wired up to use it. +`session-registry-ref`:: +Specifies a `SessionRegistry` implementation to use. +The other concurrent session control beans are wired up to use it. [[nsa-x509]] ==== -Adds support for X.509 authentication. -An `X509AuthenticationFilter` will be added to the stack and an `Http403ForbiddenEntryPoint` bean will be created. -The latter will only be used if no other authentication mechanisms are in use (its only functionality is to return an HTTP 403 error code). -A `PreAuthenticatedAuthenticationProvider` will also be created which delegates the loading of user authorities to a `UserDetailsService`. +The `` element adds support for X.509 authentication. +An `X509AuthenticationFilter` is added to the stack, and an `Http403ForbiddenEntryPoint` bean is created. +The latter is used only if no other authentication mechanisms are in use. (Its only functionality is to return an HTTP 403 error code.) +A `PreAuthenticatedAuthenticationProvider` is also created. It delegates the loading of user authorities to a `UserDetailsService`. [[nsa-x509-parents]] ===== Parent Elements of - -* <> - +The parent element of the `` element is the <`>> element. [[nsa-x509-attributes]] ===== Attributes +The `` element has the following attributes: [[nsa-x509-authentication-details-source-ref]] -* **authentication-details-source-ref** -A reference to an `AuthenticationDetailsSource` +`authentication-details-source-ref`:: +A reference to an `AuthenticationDetailsSource`. [[nsa-x509-subject-principal-regex]] -* **subject-principal-regex** -Defines a regular expression which will be used to extract the username from the certificate (for use with the `UserDetailsService`). +`subject-principal-regex`:: +Defines a regular expression, which is used to extract the username from the certificate (for use with the `UserDetailsService`). [[nsa-x509-user-service-ref]] -* **user-service-ref** -Allows a specific `UserDetailsService` to be used with X.509 in the case where multiple instances are configured. -If not set, an attempt will be made to locate a suitable instance automatically and use that. +`user-service-ref`:: +Lets a specific `UserDetailsService` be used with X.509 when where multiple instances are configured. +If not set, an attempt is made to locate a suitable instance automatically and use that. [[nsa-filter-chain-map]] ==== -Used to explicitly configure a FilterChainProxy instance with a FilterChainMap +The `` explicitly configures a `FilterChainProxy` instance with a `FilterChainMap`. [[nsa-filter-chain-map-attributes]] ===== Attributes +The `` element has one attribute: + [[nsa-filter-chain-map-request-matcher]] -* **request-matcher** +`request-matcher`:: Defines the strategy to use for matching incoming requests. -Currently the options are 'ant' (for ant path patterns), 'regex' for regular expressions and 'ciRegex' for case-insensitive regular expressions. +Currently, the options are `ant` (for Ant path patterns), `regex` (for regular expressions), and `ciRegex` (for case-insensitive regular expressions). [[nsa-filter-chain-map-children]] ===== Child Elements of - -* <> - +The `` element has one child element: <`>>. [[nsa-filter-chain]] ==== -Used within to define a specific URL pattern and the list of filters which apply to the URLs matching that pattern. -When multiple filter-chain elements are assembled in a list in order to configure a FilterChainProxy, the most specific patterns must be placed at the top of the list, with most general ones at the bottom. + +The `` element is used within a `` to define a specific URL pattern and the list of filters that apply to the URLs that match that pattern. +When multiple `` elements are assembled in a list, to configure a `FilterChainProxy`, the most specific patterns must be placed at the top of the list, with the most general ones at the bottom. [[nsa-filter-chain-parents]] ===== Parent Elements of - -* <> - +The parent element of the `` element is the <`>> element. [[nsa-filter-chain-attributes]] ===== Attributes +The `` element has the following attributes: [[nsa-filter-chain-filters]] -* **filters** -A comma separated list of references to Spring beans that implement `Filter`. -The value "none" means that no `Filter` should be used for this `FilterChain`. +`filters`:: +A comma-separated list of references to Spring beans that implement `Filter`. +A value of `none` means that no `Filter` should be used for this `FilterChain`. [[nsa-filter-chain-pattern]] -* **pattern** -A pattern that creates RequestMatcher in combination with the <> +`pattern`:: +A pattern that creates `RequestMatcher` in combination with the <`>> element. [[nsa-filter-chain-request-matcher-ref]] -* **request-matcher-ref** -A reference to a `RequestMatcher` that will be used to determine if any `Filter` from the `filters` attribute should be invoked. +`request-matcher-ref`:: +A reference to a `RequestMatcher` that is used to determine if any `Filter` from the `filters` attribute should be invoked. [[nsa-filter-security-metadata-source]] -==== -Used to explicitly configure a FilterSecurityMetadataSource bean for use with a FilterSecurityInterceptor. -Usually only needed if you are configuring a FilterChainProxy explicitly, rather than using the element. -The intercept-url elements used should only contain pattern, method and access attributes. -Any others will result in a configuration error. +==== Element +The `` is used to explicitly configure a `FilterSecurityMetadataSource` bean for use with a `FilterSecurityInterceptor`. +The `` is usually only needed if you explicitly configure a `FilterChainProxy` rather than use the `` element. +The `` elements should contain only pattern, method, and access attributes. +Any others result in a configuration error. [[nsa-filter-security-metadata-source-attributes]] ===== Attributes +The `` element has the following attributes: [[nsa-filter-security-metadata-source-id]] -* **id** -A bean identifier, used for referring to the bean elsewhere in the context. +`id`:: +A bean identifier, which is used for referring to the bean elsewhere in the context. [[nsa-filter-security-metadata-source-request-matcher]] -* **request-matcher** +`request-matcher`:: Defines the strategy use for matching incoming requests. -Currently the options are 'ant' (for ant path patterns), 'regex' for regular expressions and 'ciRegex' for case-insensitive regular expressions. +Currently the options are `ant` (for Ant path patterns), `regex` (for regular expressions), and `ciRegex` (for case-insensitive regular expressions). [[nsa-filter-security-metadata-source-use-expressions]] -* **use-expressions** -Enables the use of expressions in the 'access' attributes in elements rather than the traditional list of configuration attributes. -Defaults to 'true'. +use-expressions:: +Enables the use of expressions in the `access` attributes in `` elements rather than the traditional list of configuration attributes. +Default: `true` If enabled, each attribute should contain a single Boolean expression. -If the expression evaluates to 'true', access will be granted. +If the expression evaluates to `true`, access is granted. [[nsa-filter-security-metadata-source-children]] ===== Child Elements of - -* <> +The `` has a single child element: <`>>. [[nsa-websocket-security]] === WebSocket Security @@ -2013,145 +2037,160 @@ Spring Security 4.0+ provides support for authorizing messages. One concrete example of where this is useful is to provide authorization in WebSocket based applications. [[nsa-websocket-message-broker]] -==== +==== Element -The websocket-message-broker element has two different modes. -If the <> is not specified, then it will do the following things: +The `` element has two different modes. +If the <> is not specified, it does the following things: -* Ensure that any SimpAnnotationMethodMessageHandler has the AuthenticationPrincipalArgumentResolver registered as a custom argument resolver. -This allows the use of `@AuthenticationPrincipal` to resolve the principal of the current `Authentication` -* Ensures that the SecurityContextChannelInterceptor is automatically registered for the clientInboundChannel. -This populates the SecurityContextHolder with the user that is found in the Message -* Ensures that a ChannelSecurityInterceptor is registered with the clientInboundChannel. +* Ensure that any `SimpAnnotationMethodMessageHandler` has the `AuthenticationPrincipalArgumentResolver` registered as a custom argument resolver. +This allows the use of `@AuthenticationPrincipal` to resolve the principal of the current `Authentication`. +* Ensures that the `SecurityContextChannelInterceptor` is automatically registered for the `clientInboundChannel`. +This populates the `SecurityContextHolder` with the user that is found in the message. +* Ensures that a `ChannelSecurityInterceptor` is registered with the `clientInboundChannel`. This allows authorization rules to be specified for a message. -* Ensures that a CsrfChannelInterceptor is registered with the clientInboundChannel. +* Ensures that a `CsrfChannelInterceptor` is registered with the `clientInboundChannel`. This ensures that only requests from the original domain are enabled. -* Ensures that a CsrfTokenHandshakeInterceptor is registered with WebSocketHttpRequestHandler, TransportHandlingSockJsService, or DefaultSockJsService. -This ensures that the expected CsrfToken from the HttpServletRequest is copied into the WebSocket Session attributes. +* Ensures that a `CsrfTokenHandshakeInterceptor` is registered with a `WebSocketHttpRequestHandler`, a `TransportHandlingSockJsService`, or a `DefaultSockJsService`. +This ensures that the expected `CsrfToken` from the `HttpServletRequest` is copied into the WebSocket Session attributes. -If additional control is necessary, the id can be specified and a ChannelSecurityInterceptor will be assigned to the specified id. -All the wiring with Spring's messaging infrastructure can then be done manually. -This is more cumbersome, but provides greater control over the configuration. +If additional control is necessary, you can specify the ID, and a `ChannelSecurityInterceptor` is assigned to the specified ID. +You can then manually wire Spring's messaging infrastructure. +This is more cumbersome, but doing so provides greater control over the configuration. [[nsa-websocket-message-broker-attributes]] ===== Attributes +The `` element has the following attributes: + [[nsa-websocket-message-broker-id]] -* **id** A bean identifier, used for referring to the ChannelSecurityInterceptor bean elsewhere in the context. +`id`:: +A bean identifier, used to refer to the `ChannelSecurityInterceptor` bean elsewhere in the context. If specified, Spring Security requires explicit configuration within Spring Messaging. -If not specified, Spring Security will automatically integrate with the messaging infrastructure as described in <> +If not specified, Spring Security automatically integrates with the messaging infrastructure, as described in <> [[nsa-websocket-message-broker-same-origin-disabled]] -* **same-origin-disabled** Disables the requirement for CSRF token to be present in the Stomp headers (default false). -Changing the default is useful if it is necessary to allow other origins to make SockJS connections. +`same-origin-disabled`:: +Disables the requirement for a CSRF token to be present in the Stomp headers. +Default: `false` +Changing the default lets other origins make SockJS connections. [[nsa-websocket-message-broker-children]] ===== Child Elements of +The `` element has the following child elements: -* <> -* <> +* <`>> +* <`>> [[nsa-intercept-message]] -==== +==== Element -Defines an authorization rule for a message. +The `` defines an authorization rule for a message. [[nsa-intercept-message-parents]] ===== Parent Elements of - -* <> +The parent element of the `` element is the <> element. [[nsa-intercept-message-attributes]] ===== Attributes +The `` element has the following attributes: + [[nsa-intercept-message-pattern]] -* **pattern** An ant based pattern that matches on the Message destination. -For example, "/**" matches any Message with a destination; "/admin/**" matches any Message that has a destination that starts with "/admin/**". +`pattern`:: +An Ant-based pattern that matches on the message destination. +For example, `/**` matches any message with a destination, while `/admin/**` matches any message that has a destination that starts with `/admin/`. [[nsa-intercept-message-type]] -* **type** The type of message to match on. -Valid values are defined in SimpMessageType (i.e. CONNECT, CONNECT_ACK, HEARTBEAT, MESSAGE, SUBSCRIBE, UNSUBSCRIBE, DISCONNECT, DISCONNECT_ACK, OTHER). +`type`:: +The type of message to match on. +SimpMessageType defines the valid values: `CONNECT`, `CONNECT_ACK`, `HEARTBEAT`, `MESSAGE`, `SUBSCRIBE`, `UNSUBSCRIBE`, `DISCONNECT`, `DISCONNECT_ACK`, and `OTHER`). [[nsa-intercept-message-access]] -* **access** The expression used to secure the Message. -For example, "denyAll" will deny access to all of the matching Messages; "permitAll" will grant access to all of the matching Messages; "hasRole('ADMIN') requires the current user to have the role 'ROLE_ADMIN' for the matching Messages. +`access`:: +The expression used to secure the message. +Here are some examples: ++ +* `denyAll`: Denies access to all of the matching messages. +* `permitAll`: Grants access to all of the matching Messages. +* `hasRole('ADMIN')`: Requires the current user to have a role of `ROLE_ADMIN` for the matching messages. [[nsa-authentication]] === Authentication Services Before Spring Security 3.0, an `AuthenticationManager` was automatically registered internally. -Now you must register one explicitly using the `` element. -This creates an instance of Spring Security's `ProviderManager` class, which needs to be configured with a list of one or more `AuthenticationProvider` instances. -These can either be created using syntax elements provided by the namespace, or they can be standard bean definitions, marked for addition to the list using the `authentication-provider` element. +Now you must register one explicitly by using the `` element. +Doing so creates an instance of Spring Security's `ProviderManager` class, which needs to be configured with a list of one or more `AuthenticationProvider` instances. +You can create these instances either by using syntax elements provided by the namespace or by using standard bean definitions, marked for addition to the list by using the `authentication-provider` element. [[nsa-authentication-manager]] -==== -Every Spring Security application which uses the namespace must have include this element somewhere. -It is responsible for registering the `AuthenticationManager` which provides authentication services to the application. -All elements which create `AuthenticationProvider` instances should be children of this element. +==== Element +Every Spring Security application that uses the namespace must include the `` element somewhere. +It is responsible for registering the `AuthenticationManager`, which provides authentication services to the application. +All elements that create `AuthenticationProvider` instances should be children of this element. [[nsa-authentication-manager-attributes]] ===== Attributes +The `` element has the following attributes: [[nsa-authentication-manager-alias]] -* **alias** -This attribute allows you to define an alias name for the internal instance for use in your own configuration. +`alias`:: +This attribute lets you define an alias name for the internal instance to use in your own configuration. [[nsa-authentication-manager-erase-credentials]] -* **erase-credentials** -If set to true, the AuthenticationManager will attempt to clear any credentials data in the returned Authentication object, once the user has been authenticated. -Literally it maps to the `eraseCredentialsAfterAuthentication` property of the <>. +`erase-credentials`:: +If set to `true`, the `AuthenticationManager` tries to clear any credentials data in the returned `Authentication` object, once the user has been authenticated. +Literally, it maps to the `eraseCredentialsAfterAuthentication` property of the <>. [[nsa-authentication-manager-id]] -* **id** -This attribute allows you to define an id for the internal instance for use in your own configuration. -It is the same as the alias element, but provides a more consistent experience with elements that use the id attribute. +`id`:: +This attribute lets you define an ID for the internal instance to use in your own configuration. +It is the same as the `alias` element but provides a more consistent experience with elements that use the `id` attribute. [[nsa-authentication-manager-children]] ===== Child Elements of +The `` element has the following child elements: -* <> -* <> +* <`>> +* <`>> [[nsa-authentication-provider]] -==== -Unless used with a `ref` attribute, this element is shorthand for configuring a `DaoAuthenticationProvider`. -`DaoAuthenticationProvider` loads user information from a `UserDetailsService` and compares the username/password combination with the values supplied at login. -The `UserDetailsService` instance can be defined either by using an available namespace element (`jdbc-user-service` or by using the `user-service-ref` attribute to point to a bean defined elsewhere in the application context). - +==== Element +Unless used with a `ref` attribute, the `` element is shorthand for configuring a `DaoAuthenticationProvider`. +A `DaoAuthenticationProvider` loads user information from a `UserDetailsService` and compares the username and password combination with the values supplied at login. +You can define the `UserDetailsService` instance either by using an available namespace element (`jdbc-user-service`) or by using the `user-service-ref` attribute to point to a bean defined elsewhere in the application context. [[nsa-authentication-provider-parents]] ===== Parent Elements of - -* <> - +The parent element of the `` element is the <`>> element. [[nsa-authentication-provider-attributes]] ===== Attributes +The `` element has the following attributes: [[nsa-authentication-provider-ref]] -* **ref** +ref:: Defines a reference to a Spring bean that implements `AuthenticationProvider`. - -If you have written your own `AuthenticationProvider` implementation (or want to configure one of Spring Security's own implementations as a traditional bean for some reason, then you can use the following syntax to add it to the internal list of `ProviderManager`: - ++ +If you have written your own `AuthenticationProvider` implementation (or want to configure one of Spring Security's implementations as a traditional bean for some reason), you can use the following syntax to add it to the internal list of `ProviderManager`: ++ +==== [source,xml] ---- @@ -2161,66 +2200,63 @@ If you have written your own `AuthenticationProvider` implementation (or want to ---- - - +==== [[nsa-authentication-provider-user-service-ref]] -* **user-service-ref** -A reference to a bean that implements UserDetailsService that may be created using the standard bean element or the custom user-service element. +`user-service-ref`:: +A reference to a bean that implements `UserDetailsService`, which may be created by using the standard bean element or the custom user-service element. [[nsa-authentication-provider-children]] ===== Child Elements of +The `` element has the following child elements: -* <> -* <> -* <> -* <> - +* <`>> +* <`>> +* <`>> +* <`>> [[nsa-jdbc-user-service]] ==== -Causes creation of a JDBC-based UserDetailsService. +The `` element causes the creation of a JDBC-based `UserDetailsService`. [[nsa-jdbc-user-service-attributes]] ===== Attributes +The `` element has the following attributes: [[nsa-jdbc-user-service-authorities-by-username-query]] -* **authorities-by-username-query** +`authorities-by-username-query`:: An SQL statement to query for a user's granted authorities given a username. - -The default is - ++ +The default is as follows: +==== [source] ---- select username, authority from authorities where username = ? ---- - - - +==== [[nsa-jdbc-user-service-cache-ref]] -* **cache-ref** -Defines a reference to a cache for use with a UserDetailsService. +`cache-ref`:: +Defines a reference to a cache for use with a `UserDetailsService`. [[nsa-jdbc-user-service-data-source-ref]] -* **data-source-ref** -The bean ID of the DataSource which provides the required tables. +`data-source-ref`:: +The bean ID of the DataSource that provides the required tables. [[nsa-jdbc-user-service-group-authorities-by-username-query]] -* **group-authorities-by-username-query** -An SQL statement to query user's group authorities given a username. -The default is - +`group-authorities-by-username-query`:: +An SQL statement to query user's group authorities, given a username. +The default is as follows: + - +==== [source] ---- select @@ -2230,149 +2266,139 @@ groups g, group_members gm, group_authorities ga where gm.username = ? and g.id = ga.group_id and g.id = gm.group_id ---- - - - +==== [[nsa-jdbc-user-service-id]] -* **id** -A bean identifier, used for referring to the bean elsewhere in the context. - +`id`:: +A bean identifier, which is used for referring to the bean elsewhere in the context. [[nsa-jdbc-user-service-role-prefix]] -* **role-prefix** -A non-empty string prefix that will be added to role strings loaded from persistent storage (default is "ROLE_"). -Use the value "none" for no prefix in cases where the default is non-empty. - +`role-prefix`:: +A non-empty string prefix that is added to role strings loaded from persistent storage. +Default: `ROLE_` +Use a value of `none` for no prefix in cases where the default should be non-empty. [[nsa-jdbc-user-service-users-by-username-query]] -* **users-by-username-query** -An SQL statement to query a username, password, and enabled status given a username. -The default is - +`users-by-username-query`:: +An SQL statement to query a username, password, and enabled status, given a username. +The default is as follows: + - +==== [source] ---- select username, password, enabled from users where username = ? ---- - +==== [[nsa-password-encoder]] -==== -Authentication providers can optionally be configured to use a password encoder as described in the <>. -This will result in the bean being injected with the appropriate `PasswordEncoder` instance. +==== Element +Injects a bean with the appropriate `PasswordEncoder` instance. +Authentication providers can optionally be configured to use a password encoder, as described in the <>. [[nsa-password-encoder-parents]] ===== Parent Elements of +The `` element has the following parent elements: -* <> -* <> +* <`>> +* <`>> [[nsa-password-encoder-attributes]] ===== Attributes +The `` element has the following attributes: [[nsa-password-encoder-hash]] -* **hash** -Defines the hashing algorithm used on user passwords. -We recommend strongly against using MD4, as it is a very weak hashing algorithm. +`hash`:: +Defines the hashing algorithm for user passwords. +IMPORTANT: We recommend strongly against using MD4, as it is a very weak hashing algorithm. [[nsa-password-encoder-ref]] -* **ref** +`ref`:: Defines a reference to a Spring bean that implements `PasswordEncoder`. [[nsa-user-service]] -==== -Creates an in-memory UserDetailsService from a properties file or a list of "user" child elements. -Usernames are converted to lower-case internally to allow for case-insensitive lookups, so this should not be used if case-sensitivity is required. +==== Element +The `` element creates an in-memory `UserDetailsService` from a properties file or a list of `` child elements. +Usernames are converted to lower case internally, to allow for case-insensitive lookups, so do not use this element if you need case-sensitivity. [[nsa-user-service-attributes]] ===== Attributes +The `` element has the following attributes: [[nsa-user-service-id]] -* **id** -A bean identifier, used for referring to the bean elsewhere in the context. +`id`:: +A bean identifier, used to refer to the bean elsewhere in the context. [[nsa-user-service-properties]] -* **properties** -The location of a Properties file where each line is in the format of - +`properties`:: +The location of a properties file, in which each line is in the format of + - +==== [source] ---- username=password,grantedAuthority[,grantedAuthority][,enabled|disabled] ---- - - +==== [[nsa-user-service-children]] -===== Child Elements of - - -* <> +===== Child Element of +The `` element has a single child element: <`>>. +Multiple `` elements can be present. [[nsa-user]] -==== -Represents a user in the application. +==== Element +The `` represents a user in the application. [[nsa-user-parents]] -===== Parent Elements of - - -* <> +===== Parent Element of +The parent element of the `` element is the <`>> element. [[nsa-user-attributes]] ===== Attributes +The `` element has the following elements: [[nsa-user-authorities]] -* **authorities** -One of more authorities granted to the user. -Separate authorities with a comma (but no space). -For example, "ROLE_USER,ROLE_ADMINISTRATOR" - +`authorities`:: +One of more authorities to be granted to the user. +Separate authorities with a comma (but no space) -- for example, `ROLE_USER,ROLE_ADMINISTRATOR`. [[nsa-user-disabled]] -* **disabled** -Can be set to "true" to mark an account as disabled and unusable. - +`disabled`:: +Set to `true` to mark an account as disabled and unusable. [[nsa-user-locked]] -* **locked** -Can be set to "true" to mark an account as locked and unusable. - +`locked`:: +Set to `true` to mark an account as locked and unusable. [[nsa-user-name]] -* **name** +`name`:: The username assigned to the user. - [[nsa-user-password]] -* **password** +`password`:: The password assigned to the user. -This may be hashed if the corresponding authentication provider supports hashing (remember to set the "hash" attribute of the "user-service" element). -This attribute be omitted in the case where the data will not be used for authentication, but only for accessing authorities. -If omitted, the namespace will generate a random value, preventing its accidental use for authentication. -Cannot be empty. +This value may be hashed if the corresponding authentication provider supports hashing (remember to set the `hash` attribute of the `user-service` element). +You can omit this attribute when the data is not used for authentication but only for accessing authorities. +If omitted, the namespace generates a random value, preventing its accidental use for authentication. +This attribute cannot be empty. @@ -2412,600 +2438,576 @@ Defaults to "false". * <> [[nsa-global-method-security]] -==== -This element is the primary means of adding support for securing methods on Spring Security beans. -Methods can be secured by the use of annotations (defined at the interface or class level) or by defining a set of pointcuts as child elements, using AspectJ syntax. +==== element +The `` element is the primary means of adding support for securing methods on Spring Security beans. +You can secure methods by using annotations (defined at the interface or class level) or by defining a set of pointcuts as child elements with AspectJ syntax. [[nsa-global-method-security-attributes]] ===== Attributes +The `` element has the following attributes: [[nsa-global-method-security-access-decision-manager-ref]] -* **access-decision-manager-ref** -Method security uses the same `AccessDecisionManager` configuration as web security, but this can be overridden using this attribute. -By default an AffirmativeBased implementation is used for with a RoleVoter and an AuthenticatedVoter. - +`access-decision-manager-ref`:: +Method security uses the same `AccessDecisionManager` configuration as web security, but using this attribute can override this arrangement. +By default, an `AffirmativeBased` implementation is used with a `RoleVoter` and an `AuthenticatedVoter`. [[nsa-global-method-security-authentication-manager-ref]] -* **authentication-manager-ref** -A reference to an `AuthenticationManager` that should be used for method security. - +`authentication-manager-ref`:: +A reference to the `AuthenticationManager` that should be used for method security. [[nsa-global-method-security-jsr250-annotations]] -* **jsr250-annotations** -Specifies whether JSR-250 style attributes are to be used (for example "RolesAllowed"). -This will require the javax.annotation.security classes on the classpath. -Setting this to true also adds a `Jsr250Voter` to the `AccessDecisionManager`, so you need to make sure you do this if you are using a custom implementation and want to use these annotations. +`jsr250-annotations`:: +Specifies whether JSR-250 style attributes are to be used (for example, `RolesAllowed`). +Doing so requires the `javax.annotation.security` classes to be on the classpath. +Setting this to `true` also adds a `Jsr250Voter` to the `AccessDecisionManager`, so you need to make sure that you do so if you use a custom implementation and want to use these annotations. [[nsa-global-method-security-metadata-source-ref]] -* **metadata-source-ref** -An external `MethodSecurityMetadataSource` instance can be supplied which will take priority over other sources (such as the default annotations). - +metadata-source-ref:: +You can supply an external `MethodSecurityMetadataSource` instance, which will take priority over other sources (such as the default annotations). [[nsa-global-method-security-mode]] -* **mode** -This attribute can be set to "aspectj" to specify that AspectJ should be used instead of the default Spring AOP. -Secured methods must be woven with the `AnnotationSecurityAspect` from the `spring-security-aspects` module. - -It is important to note that AspectJ follows Java's rule that annotations on interfaces are not inherited. -This means that methods that define the Security annotations on the interface will not be secured. -Instead, you must place the Security annotation on the class when using AspectJ. - +mode:: +You can set this attribute to `aspectj` to specify that AspectJ should be used instead of the default Spring AOP. +You must weave secured methods with the `AnnotationSecurityAspect` from the `spring-security-aspects` module. ++ +NOTE: AspectJ follows Java's rule that annotations on interfaces are not inherited. +This means that methods that define the Security annotations on the interface are not secured. +Instead, you must place the Security annotation on the class when you use AspectJ. [[nsa-global-method-security-order]] -* **order** -Allows the advice "order" to be set for the method security interceptor. - +`order`:: +Lets the `order` advice be set for the method security interceptor. [[nsa-global-method-security-pre-post-annotations]] -* **pre-post-annotations** -Specifies whether the use of Spring Security's pre and post invocation annotations (@PreFilter, @PreAuthorize, @PostFilter, @PostAuthorize) should be enabled for this application context. -Defaults to "disabled". - +`pre-post-annotations`:: +Specifies whether the use of Spring Security's pre- and post-invocation annotations (`@PreFilter`, `@PreAuthorize`, `@PostFilter`, and `@PostAuthorize`) should be enabled for this application context. +Default: `disabled` [[nsa-global-method-security-proxy-target-class]] -* **proxy-target-class** -If true, class based proxying will be used instead of interface based proxying. - +`proxy-target-class`:: +If `true`, class-based proxying is used instead of interface-based proxying. [[nsa-global-method-security-run-as-manager-ref]] -* **run-as-manager-ref** -A reference to an optional `RunAsManager` implementation which will be used by the configured `MethodSecurityInterceptor` - +`run-as-manager-ref`:: +A reference to an optional `RunAsManager` implementation, which is used by the configured `MethodSecurityInterceptor`. [[nsa-global-method-security-secured-annotations]] -* **secured-annotations** -Specifies whether the use of Spring Security's @Secured annotations should be enabled for this application context. -Defaults to "disabled". +`secured-annotations`:: +Specifies whether the use of Spring Security's `@Secured` annotations should be enabled for this application context. +Default: `disabled` [[nsa-global-method-security-children]] ===== Child Elements of +The `` has the following child elements: -* <> -* <> -* <> -* <> - +* <`>> +* <`>> +* <`>> +* <`>> [[nsa-after-invocation-provider]] -==== -This element can be used to decorate an `AfterInvocationProvider` for use by the security interceptor maintained by the `` namespace. -You can define zero or more of these within the `global-method-security` element, each with a `ref` attribute pointing to an `AfterInvocationProvider` bean instance within your application context. +==== Element +You can use the `` element to decorate an `AfterInvocationProvider` for use by the security interceptor that is maintained by the `` namespace. +You can define zero or more of these elements within the `global-method-security` element, each with a `ref` attribute that points to an `AfterInvocationProvider` bean instance within your application context. [[nsa-after-invocation-provider-parents]] ===== Parent Elements of - -* <> - +The parent element of the `` is the <`>> element. [[nsa-after-invocation-provider-attributes]] ===== Attributes +The `` element has a single attribute: [[nsa-after-invocation-provider-ref]] -* **ref** +`ref`:: Defines a reference to a Spring bean that implements `AfterInvocationProvider`. [[nsa-pre-post-annotation-handling]] ==== -Allows the default expression-based mechanism for handling Spring Security's pre and post invocation annotations (@PreFilter, @PreAuthorize, @PostFilter, @PostAuthorize) to be replaced entirely. -Only applies if these annotations are enabled. +The `` lets us entirely replace the default expression-based mechanism for handling Spring Security's pre- and post-invocation annotations (`@PreFilter`, `@PreAuthorize`, `@PostFilter`, `@PostAuthorize`). +It applies only if these annotations are enabled. [[nsa-pre-post-annotation-handling-parents]] ===== Parent Elements of - -* <> - +The parent element of the `` element is the <`>> element. [[nsa-pre-post-annotation-handling-children]] ===== Child Elements of +The `` element has the following children: -* <> -* <> -* <> +* <`>> +* <`>> +* <`>> [[nsa-invocation-attribute-factory]] ==== -Defines the PrePostInvocationAttributeFactory instance which is used to generate pre and post invocation metadata from the annotated methods. +The `` element defines the `PrePostInvocationAttributeFactory` instance to use to generate pre- and post-invocation metadata from the annotated methods. [[nsa-invocation-attribute-factory-parents]] ===== Parent Elements of - -* <> - +The parent element of the `` element is the <> element. [[nsa-invocation-attribute-factory-attributes]] ===== Attributes +The `` has a single attribute: [[nsa-invocation-attribute-factory-ref]] -* **ref** -Defines a reference to a Spring bean Id. +`ref`:: +Defines a reference to a Spring bean ID. [[nsa-post-invocation-advice]] ==== -Customizes the `PostInvocationAdviceProvider` with the ref as the `PostInvocationAuthorizationAdvice` for the element. +The `` element customizes the `PostInvocationAdviceProvider` with the value of the `ref` attribute as the `PostInvocationAuthorizationAdvice` for the `` element. [[nsa-post-invocation-advice-parents]] ===== Parent Elements of - -* <> - +The parent element of the `` element is the <`>> element. [[nsa-post-invocation-advice-attributes]] ===== Attributes +The `` has a single attribute: [[nsa-post-invocation-advice-ref]] -* **ref** -Defines a reference to a Spring bean Id. +`ref`:: +Defines a reference to a Spring bean ID. [[nsa-pre-invocation-advice]] ==== -Customizes the `PreInvocationAuthorizationAdviceVoter` with the ref as the `PreInvocationAuthorizationAdviceVoter` for the element. +The `` element customizes the `PreInvocationAuthorizationAdviceVoter` with the value of the `ref` attribute as the `PreInvocationAuthorizationAdviceVoter` for the `` element. [[nsa-pre-invocation-advice-parents]] ===== Parent Elements of - -* <> - +The parent element of the `` is the <`>> element. [[nsa-pre-invocation-advice-attributes]] ===== Attributes +The `` element has a single attribute: [[nsa-pre-invocation-advice-ref]] -* **ref** -Defines a reference to a Spring bean Id. +ref:: +Defines a reference to a Spring bean ID. [[nsa-protect-pointcut]] -==== Securing Methods using -`` -Rather than defining security attributes on an individual method or class basis using the `@Secured` annotation, you can define cross-cutting security constraints across whole sets of methods and interfaces in your service layer using the `` element. +==== Securing Methods by Using +Rather than defining security attributes on an individual method or class basis by using the `@Secured` annotation, you can define cross-cutting security constraints across whole sets of methods and interfaces in your service layer by using the `` element. You can find an example in the <>. [[nsa-protect-pointcut-parents]] ===== Parent Elements of - -* <> +The parent element of the `` element is the <`>> element. [[nsa-protect-pointcut-attributes]] ===== Attributes +The `` has the following attributes: [[nsa-protect-pointcut-access]] -* **access** -Access configuration attributes list that applies to all methods matching the pointcut, e.g. -"ROLE_A,ROLE_B" +`access`:: +Access configuration attributes list that applies to all methods that match the pointcut -- for example, +`ROLE_A,ROLE_B`. [[nsa-protect-pointcut-expression]] -* **expression** -An AspectJ expression, including the `execution` keyword. -For example, `execution(int com.foo.TargetObject.countLength(String))`. +`expression`:: +An AspectJ expression, including the `execution` keyword -- for example, `execution(int com.foo.TargetObject.countLength(String))`. [[nsa-intercept-methods]] ==== -Can be used inside a bean definition to add a security interceptor to the bean and set up access configuration attributes for the bean's methods +You can use the `` element inside a bean definition to add a security interceptor to the bean and set up access configuration attributes for the bean's methods [[nsa-intercept-methods-attributes]] ===== Attributes +The `` element has a single attribute: [[nsa-intercept-methods-access-decision-manager-ref]] -* **access-decision-manager-ref** -Optional AccessDecisionManager bean ID to be used by the created method security interceptor. +`access-decision-manager-ref`:: +Optional `AccessDecisionManager` bean ID to be used by the created method security interceptor. [[nsa-intercept-methods-children]] ===== Child Elements of - -* <> - +The parent element of the `` is the <`>> element. [[nsa-method-security-metadata-source]] ==== -Creates a MethodSecurityMetadataSource instance +The `` element creates a `MethodSecurityMetadataSource` instance. [[nsa-method-security-metadata-source-attributes]] ===== Attributes +The `` element has the following attributes: [[nsa-method-security-metadata-source-id]] -* **id** +`id`:: A bean identifier, used for referring to the bean elsewhere in the context. [[nsa-method-security-metadata-source-use-expressions]] -* **use-expressions** -Enables the use of expressions in the 'access' attributes in elements rather than the traditional list of configuration attributes. -Defaults to 'false'. +`use-expressions`:: +Enables the use of expressions in the `access` attributes of `` elements rather than the traditional list of configuration attributes. +Default: `false` If enabled, each attribute should contain a single Boolean expression. -If the expression evaluates to 'true', access will be granted. +If the expression evaluates to `true`, access is granted. [[nsa-method-security-metadata-source-children]] ===== Child Elements of - -* <> - +The `` has a single child element: <`>>. [[nsa-protect]] ==== -Defines a protected method and the access control configuration attributes that apply to it. -We strongly advise you NOT to mix "protect" declarations with any services provided "global-method-security". +The `` element defines a protected method and the access control configuration attributes that apply to it. +We strongly advise you NOT to mix "`protect`" declarations with any services provided by `` element. [[nsa-protect-parents]] ===== Parent Elements of +The `` element has two parent elements: -* <> -* <> - +* <`>> +* <`>> [[nsa-protect-attributes]] ===== Attributes +The `` element has the following attributes: [[nsa-protect-access]] -* **access** -Access configuration attributes list that applies to the method, e.g. -"ROLE_A,ROLE_B". +`access`:: +Access configuration attributes list that applies to the method -- for example, +`ROLE_A,ROLE_B`. [[nsa-protect-method]] -* **method** -A method name +`method`:: +A method name. [[nsa-ldap]] === LDAP Namespace Options -LDAP is covered in some details in <>. -We will expand on that here with some explanation of how the namespace options map to Spring beans. +LDAP is covered in some detail in <>. +We expand on that here with some explanation of how the namespace options map to Spring beans. The LDAP implementation uses Spring LDAP extensively, so some familiarity with that project's API may be useful. [[nsa-ldap-server]] -==== Defining the LDAP Server using the -`` Element -This element sets up a Spring LDAP `ContextSource` for use by the other LDAP beans, defining the location of the LDAP server and other information (such as a username and password, if it doesn't allow anonymous access) for connecting to it. -It can also be used to create an embedded server for testing. +==== Defining the LDAP Server by Using the Element +The `` element sets up a Spring LDAP `ContextSource` for use by the other LDAP beans, defining the location of the LDAP server and other information (such as a username and password, if it does not allow anonymous access) for connecting to it. +You can also use it to create an embedded server for testing. Details of the syntax for both options are covered in the <>. -The actual `ContextSource` implementation is `DefaultSpringSecurityContextSource` which extends Spring LDAP's `LdapContextSource` class. +The actual `ContextSource` implementation is `DefaultSpringSecurityContextSource`, which extends Spring LDAP's `LdapContextSource` class. The `manager-dn` and `manager-password` attributes map to the latter's `userDn` and `password` properties respectively. -If you only have one server defined in your application context, the other LDAP namespace-defined beans will use it automatically. -Otherwise, you can give the element an "id" attribute and refer to it from other namespace beans using the `server-ref` attribute. +If you have only one server defined in your application context, the other LDAP namespace-defined beans use it automatically. +Otherwise, you can give the element an `id` attribute and refer to it from other namespace beans by using the `server-ref` attribute. This is actually the bean `id` of the `ContextSource` instance, if you want to use it in other traditional Spring beans. [[nsa-ldap-server-attributes]] ===== Attributes +The `` element has the following attributes: + [[nsa-ldap-server-mode]] -* **mode** -Explicitly specifies which embedded ldap server should use. Values are `apacheds` and `unboundid`. By default, it will depends if the library is available in the classpath. +`mode`:: +Explicitly specifies which embedded LDAP server to use. Valid values are `apacheds` and `unboundid`. By default, it depends on whether the library is available in the classpath. [[nsa-ldap-server-id]] -* **id** +`id`:: A bean identifier, used for referring to the bean elsewhere in the context. [[nsa-ldap-server-ldif]] -* **ldif** +`ldif`:: Explicitly specifies an ldif file resource to load into an embedded LDAP server. -The ldif should be a Spring resource pattern (i.e. classpath:init.ldif). -The default is classpath*:*.ldif +The ldif file should be a Spring resource pattern (such as `classpath:init.ldif`). +Default: `classpath*:*.ldif` [[nsa-ldap-server-manager-dn]] -* **manager-dn** -Username (DN) of the "manager" user identity which will be used to authenticate to a (non-embedded) LDAP server. -If omitted, anonymous access will be used. +`manager-dn`:: +Username (DN) of the "`manager`" user identity, which is used to authenticate to a (non-embedded) LDAP server. +If omitted, anonymous access is used. [[nsa-ldap-server-manager-password]] -* **manager-password** +`manager-password`:: The password for the manager DN. -This is required if the manager-dn is specified. +This is required if the `manager-dn` is specified. [[nsa-ldap-server-port]] -* **port** +`port`:: Specifies an IP port number. -Used to configure an embedded LDAP server, for example. -The default value is 33389. +You can use use it to configure an embedded LDAP server, for example. +The default value is `33389`. [[nsa-ldap-server-root]] -* **root** +`root`:: Optional root suffix for the embedded LDAP server. -Default is "dc=springframework,dc=org" +Default: `dc=springframework,dc=org` [[nsa-ldap-server-url]] -* **url** -Specifies the ldap server URL when not using the embedded LDAP server. +url:: +Specifies the LDAP server URL when not using the embedded LDAP server. [[nsa-ldap-authentication-provider]] ==== This element is shorthand for the creation of an `LdapAuthenticationProvider` instance. -By default this will be configured with a `BindAuthenticator` instance and a `DefaultAuthoritiesPopulator`. +By default, this is configured with a `BindAuthenticator` instance and a `DefaultAuthoritiesPopulator`. As with all namespace authentication providers, it must be included as a child of the `authentication-provider` element. [[nsa-ldap-authentication-provider-parents]] ===== Parent Elements of - -* <> - +The parent element of the `` is the <`>> element. [[nsa-ldap-authentication-provider-attributes]] ===== Attributes +The `` element has the following attributes: [[nsa-ldap-authentication-provider-group-role-attribute]] -* **group-role-attribute** -The LDAP attribute name which contains the role name which will be used within Spring Security. -Maps to the ``DefaultLdapAuthoritiesPopulator``'s `groupRoleAttribute` property. -Defaults to "cn". +`group-role-attribute`:: +The LDAP attribute name, which contains the role name that is used within Spring Security. +Maps to the `groupRoleAttribute` property of the `DefaultLdapAuthoritiesPopulator`. +Default: `cn` [[nsa-ldap-authentication-provider-group-search-base]] -* **group-search-base** +`group-search-base`:: Search base for group membership searches. -Maps to the ``DefaultLdapAuthoritiesPopulator``'s `groupSearchBase` constructor argument. -Defaults to "" (searching from the root). +Maps to the `groupSearchBase` constructor argument of `DefaultLdapAuthoritiesPopulator`. +Default: `""` (searching from the root) [[nsa-ldap-authentication-provider-group-search-filter]] -* **group-search-filter** +`group-search-filter`:: Group search filter. -Maps to the ``DefaultLdapAuthoritiesPopulator``'s `groupSearchFilter` property. -Defaults to `+(uniqueMember={0})+`. +Maps to the `groupSearchFilter` property of `DefaultLdapAuthoritiesPopulator`. The substituted parameter is the DN of the user. +Default: `+(uniqueMember={0})+` [[nsa-ldap-authentication-provider-role-prefix]] -* **role-prefix** -A non-empty string prefix that will be added to role strings loaded from persistent. -Maps to the ``DefaultLdapAuthoritiesPopulator``'s `rolePrefix` property. -Defaults to "ROLE_". -Use the value "none" for no prefix in cases where the default is non-empty. +`role-prefix`:: +A non-empty string prefix that is added to role strings loaded from persistent storage. +Maps to the `rolePrefix` property of `DefaultLdapAuthoritiesPopulator`. +Use a value of `none` for no prefix in cases where the default is non-empty. +Default: `ROLE_` [[nsa-ldap-authentication-provider-server-ref]] -* **server-ref** +`server-ref`:: The optional server to use. -If omitted, and a default LDAP server is registered (using with no Id), that server will be used. +If omitted, and a default LDAP server is registered (by using `` with no ID), that server is used. [[nsa-ldap-authentication-provider-user-context-mapper-ref]] -* **user-context-mapper-ref** -Allows explicit customization of the loaded user object by specifying a UserDetailsContextMapper bean which will be called with the context information from the user's directory entry +`user-context-mapper-ref`:: +Allows explicit customization of the loaded user object by specifying a `UserDetailsContextMapper` bean, which is called with the context information from the user's directory entry. [[nsa-ldap-authentication-provider-user-details-class]] -* **user-details-class** -Allows the objectClass of the user entry to be specified. -If set, the framework will attempt to load standard attributes for the defined class into the returned UserDetails object +`user-details-class`:: +Lets the `objectClass` of the user entry be specified. +If set, the framework tries to load standard attributes for the defined class into the returned `UserDetails` object [[nsa-ldap-authentication-provider-user-dn-pattern]] -* **user-dn-pattern** -If your users are at a fixed location in the directory (i.e. you can work out the DN directly from the username without doing a directory search), you can use this attribute to map directly to the DN. +user-dn-pattern:: +If your users are at a fixed location in the directory (that is, you can work out the DN directly from the username without doing a directory search), you can use this attribute to map directly to the DN. It maps directly to the `userDnPatterns` property of `AbstractLdapAuthenticator`. -The value is a specific pattern used to build the user's DN, for example `+uid={0},ou=people+`. -The key `+{0}+` must be present and will be substituted with the username. +The value is a specific pattern used to build the user's DN -- for example, `+uid={0},ou=people+`. +The `+{0}+` key must be present and is substituted with the username. [[nsa-ldap-authentication-provider-user-search-base]] -* **user-search-base** +`user-search-base`:: Search base for user searches. -Defaults to "". -Only used with a 'user-search-filter'. - +Only used with a `user-search-filter`. +Default `""` + - -If you need to perform a search to locate the user in the directory, then you can set these attributes to control the search. -The `BindAuthenticator` will be configured with a `FilterBasedLdapUserSearch` and the attribute values map directly to the first two arguments of that bean's constructor. -If these attributes aren't set and no `user-dn-pattern` has been supplied as an alternative, then the default search values of `+user-search-filter="(uid={0})"+` and `user-search-base=""` will be used. +If you need to perform a search to locate the user in the directory, you can set these attributes to control the search. +The `BindAuthenticator` is configured with a `FilterBasedLdapUserSearch`, and the attribute values map directly to the first two arguments of that bean's constructor. +If these attributes are not set and no `user-dn-pattern` has been supplied as an alternative, the default search values of `+user-search-filter="(uid={0})"+` and `user-search-base=""` are used. [[nsa-ldap-authentication-provider-user-search-filter]] -* **user-search-filter** -The LDAP filter used to search for users (optional). -For example `+(uid={0})+`. +`user-search-filter`:: +The LDAP filter used to search for users (optional) -- for example, `+(uid={0})+`. The substituted parameter is the user's login name. - + - -If you need to perform a search to locate the user in the directory, then you can set these attributes to control the search. -The `BindAuthenticator` will be configured with a `FilterBasedLdapUserSearch` and the attribute values map directly to the first two arguments of that bean's constructor. -If these attributes aren't set and no `user-dn-pattern` has been supplied as an alternative, then the default search values of `+user-search-filter="(uid={0})"+` and `user-search-base=""` will be used. +If you need to perform a search to locate the user in the directory, you can set these attributes to control the search. +The `BindAuthenticator` is configured with a `FilterBasedLdapUserSearch`, and the attribute values map directly to the first two arguments of that bean's constructor. +If these attributes are not set and no `user-dn-pattern` has been supplied as an alternative, the default search values of `+user-search-filter="(uid={0})"+` and `user-search-base=""` is used. [[nsa-ldap-authentication-provider-children]] ===== Child Elements of - -* <> - +The `` has a single child element: <`>>. [[nsa-password-compare]] ==== -This is used as child element to `` and switches the authentication strategy from `BindAuthenticator` to `PasswordComparisonAuthenticator`. +The `` element is used as a child element to `` and switches the authentication strategy from `BindAuthenticator` to `PasswordComparisonAuthenticator`. [[nsa-password-compare-parents]] ===== Parent Elements of - -* <> - +The parent element of the `` element is the <`>> element. [[nsa-password-compare-attributes]] ===== Attributes +The `` has the following attributes: [[nsa-password-compare-hash]] -* **hash** +`hash`:: Defines the hashing algorithm used on user passwords. We recommend strongly against using MD4, as it is a very weak hashing algorithm. [[nsa-password-compare-password-attribute]] -* **password-attribute** -The attribute in the directory which contains the user password. -Defaults to "userPassword". +`password-attribute`:: +The attribute in the directory that contains the user password. +Default: `userPassword` [[nsa-password-compare-children]] ===== Child Elements of - -* <> - +The `` element has a single child element: <`>>. [[nsa-ldap-user-service]] ==== -This element configures an LDAP `UserDetailsService`. -The class used is `LdapUserDetailsService` which is a combination of a `FilterBasedLdapUserSearch` and a `DefaultLdapAuthoritiesPopulator`. -The attributes it supports have the same usage as in ``. +The `` element configures an LDAP `UserDetailsService`. +It uses `LdapUserDetailsService`, which is a combination of a `FilterBasedLdapUserSearch` and a `DefaultLdapAuthoritiesPopulator`. +The attributes it supports have the same usage as ``. [[nsa-ldap-user-service-attributes]] ===== Attributes +The `` element has the following attributes: + [[nsa-ldap-user-service-cache-ref]] -* **cache-ref** -Defines a reference to a cache for use with a UserDetailsService. +`cache-ref`:: +Defines a reference to a cache for use with a `UserDetailsService`. [[nsa-ldap-user-service-group-role-attribute]] -* **group-role-attribute** -The LDAP attribute name which contains the role name which will be used within Spring Security. -Defaults to "cn". +`group-role-attribute`:: +The LDAP attribute name that contains the role name to be used within Spring Security. +Default: `cn` [[nsa-ldap-user-service-group-search-base]] -* **group-search-base** +`group-search-base`:: Search base for group membership searches. -Defaults to "" (searching from the root). +Default: `""` (searching from the root) [[nsa-ldap-user-service-group-search-filter]] -* **group-search-filter** +`group-search-filter`:: Group search filter. -Defaults to `+(uniqueMember={0})+`. The substituted parameter is the DN of the user. +Default: `+(uniqueMember={0})+` [[nsa-ldap-user-service-id]] -* **id** +`id`:: A bean identifier, used for referring to the bean elsewhere in the context. [[nsa-ldap-user-service-role-prefix]] -* **role-prefix** -A non-empty string prefix that will be added to role strings loaded from persistent storage (e.g. -"ROLE_"). -Use the value "none" for no prefix in cases where the default is non-empty. +role-prefix:: +A non-empty string prefix that is added to role strings loaded from persistent storage (for example, +`ROLE_`). +Use a value of `none` for no prefix in cases where the default is non-empty. [[nsa-ldap-user-service-server-ref]] -* **server-ref** +`server-ref`:: The optional server to use. -If omitted, and a default LDAP server is registered (using with no Id), that server will be used. +If omitted and a default LDAP server is registered (by using `` with no ID), that server is used. [[nsa-ldap-user-service-user-context-mapper-ref]] -* **user-context-mapper-ref** -Allows explicit customization of the loaded user object by specifying a UserDetailsContextMapper bean which will be called with the context information from the user's directory entry +`user-context-mapper-ref`:: +Allows explicit customization of the loaded user object by specifying a `UserDetailsContextMapper` bean, which is called with the context information from the user's directory entry. [[nsa-ldap-user-service-user-details-class]] -* **user-details-class** -Allows the objectClass of the user entry to be specified. -If set, the framework will attempt to load standard attributes for the defined class into the returned UserDetails object +`user-details-class`:: +Lets the `objectClass` of the user entry be specified. +If set, the framework tries to load standard attributes for the defined class into the returned `UserDetails` object. [[nsa-ldap-user-service-user-search-base]] -* **user-search-base** +`user-search-base`:: Search base for user searches. -Defaults to "". -Only used with a 'user-search-filter'. +It is used only with a <`>> element. +Default: `""` [[nsa-ldap-user-service-user-search-filter]] -* **user-search-filter** -The LDAP filter used to search for users (optional). -For example `+(uid={0})+`. +`user-search-filter`:: +The LDAP filter used to search for users (optional) -- for example, `+(uid={0})+`. The substituted parameter is the user's login name. diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/architecture/delegating-filter-proxy.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/architecture/delegating-filter-proxy.adoc index d7c3d45ed3b..5743b938689 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/architecture/delegating-filter-proxy.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/architecture/delegating-filter-proxy.adoc @@ -2,17 +2,19 @@ = DelegatingFilterProxy Spring provides a `Filter` implementation named {security-api-url}org/springframework/web/filter/DelegatingFilterProxy.html/[`DelegatingFilterProxy`] that allows bridging between the Servlet container's lifecycle and Spring's `ApplicationContext`. -The Servlet container allows registering ``Filter``s using its own standards, but it is not aware of Spring defined Beans. -`DelegatingFilterProxy` can be registered via standard Servlet container mechanisms, but delegate all the work to a Spring Bean that implements `Filter`. +The Servlet container allows registering `Filter` instances by using its own standards, but it is not aware of Spring-defined Beans. +You can register `DelegatingFilterProxy` through the standard Servlet container mechanisms but delegate all the work to a Spring Bean that implements `Filter`. -Here is a picture of how `DelegatingFilterProxy` fits into the <>. +Here is a picture of how `DelegatingFilterProxy` fits into the <>. .DelegatingFilterProxy [[servlet-delegatingfilterproxy-figure]] image::{figures}/delegatingfilterproxy.png[] `DelegatingFilterProxy` looks up __Bean Filter~0~__ from the `ApplicationContext` and then invokes __Bean Filter~0~__. -The pseudo code of `DelegatingFilterProxy` can be seen below. +The following listing shows pseudo code of `DelegatingFilterProxy`: + +// FIXME: Use real code from a real repository rather than pseudo code. .`DelegatingFilterProxy` Pseudo Code ==== @@ -41,6 +43,6 @@ fun doFilter(request: ServletRequest, response: ServletResponse, chain: FilterCh ---- ==== -Another benefit of `DelegatingFilterProxy` is that it allows delaying looking `Filter` bean instances. -This is important because the container needs to register the `Filter` instances before the container can startup. -However, Spring typically uses a `ContextLoaderListener` to load the Spring Beans which will not be done until after the `Filter` instances need to be registered. +Another benefit of `DelegatingFilterProxy` is that it allows delaying looking up `Filter` bean instances. +This is important because the container needs to register the `Filter` instances before the container can start up. +However, Spring typically uses a `ContextLoaderListener` to load the Spring Beans, which is not done until after the `Filter` instances need to be registered. diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/architecture/exception-translation-filter.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/architecture/exception-translation-filter.adoc index 67cad58ddf1..f3c97ed7de0 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/architecture/exception-translation-filter.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/architecture/exception-translation-filter.adoc @@ -8,29 +8,29 @@ The {security-api-url}org/springframework/security/web/access/ExceptionTranslati `ExceptionTranslationFilter` is inserted into the <> as one of the <>. -image::{figures}/exceptiontranslationfilter.png[] +The following image shows the relationship of `ExceptionTranslationFilter` to other components: +image::{figures}/exceptiontranslationfilter.png[] * image:{icondir}/number_1.png[] First, the `ExceptionTranslationFilter` invokes `FilterChain.doFilter(request, response)` to invoke the rest of the application. -* image:{icondir}/number_2.png[] If the user is not authenticated or it is an `AuthenticationException`, then __Start Authentication__. -** The <> is cleared out +* image:{icondir}/number_2.png[] If the user is not authenticated or it is an `AuthenticationException`, __Start Authentication__. +** The <> is cleared out. ** The `HttpServletRequest` is saved in the {security-api-url}org/springframework/security/web/savedrequest/RequestCache.html[`RequestCache`]. When the user successfully authenticates, the `RequestCache` is used to replay the original request. // FIXME: add link to authentication success ** The `AuthenticationEntryPoint` is used to request credentials from the client. For example, it might redirect to a log in page or send a `WWW-Authenticate` header. // FIXME: link to AuthenticationEntryPoint -* image:{icondir}/number_3.png[] Otherwise if it is an `AccessDeniedException`, then __Access Denied__. +* image:{icondir}/number_3.png[] Otherwise, if it is an `AccessDeniedException`, then __Access Denied__. The `AccessDeniedHandler` is invoked to handle access denied. // FIXME: link to AccessDeniedHandler -[NOTE] -==== -If the application does not throw an `AccessDeniedException` or an `AuthenticationException`, then `ExceptionTranslationFilter` does not do anything. -==== +NOTE: If the application does not throw an `AccessDeniedException` or an `AuthenticationException`, `ExceptionTranslationFilter` does not do anything. The pseudocode for `ExceptionTranslationFilter` looks something like this: +// FIXME: Use real code from a real repository rather than pseudo code + .ExceptionTranslationFilter pseudocode [source,java] ---- @@ -44,7 +44,7 @@ try { } } ---- -<1> You will recall from <> that invoking `FilterChain.doFilter(request, response)` is the equivalent of invoking the rest of the application. -This means that if another part of the application, (i.e. <> or method security) throws an `AuthenticationException` or `AccessDeniedException` it will be caught and handled here. -<2> If the user is not authenticated or it is an `AuthenticationException`, then __Start Authentication__. +<1> As described in <>, invoking `FilterChain.doFilter(request, response)` is the equivalent of invoking the rest of the application. +This means that if another part of the application, (<> or method security) throws an `AuthenticationException` or `AccessDeniedException` it is caught and handled here. +<2> If the user is not authenticated or it is an `AuthenticationException`, __Start Authentication__. <3> Otherwise, __Access Denied__ diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/architecture/filter-chain-proxy.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/architecture/filter-chain-proxy.adoc index 0b15efeec9f..d69cbdb423c 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/architecture/filter-chain-proxy.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/architecture/filter-chain-proxy.adoc @@ -5,6 +5,8 @@ Spring Security's Servlet support is contained within `FilterChainProxy`. `FilterChainProxy` is a special `Filter` provided by Spring Security that allows delegating to many `Filter` instances through <>. Since `FilterChainProxy` is a Bean, it is typically wrapped in a <>. +The following image shows the role of `FilterChainProxy`. + .FilterChainProxy [[servlet-filterchainproxy-figure]] image::{figures}/filterchainproxy.png[] diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/architecture/filters.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/architecture/filters.adoc index 4b63aa4deb9..54aaee9b4ad 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/architecture/filters.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/architecture/filters.adoc @@ -1,21 +1,21 @@ [[servlet-filters-review]] -= A Review of ``Filter``s += A Review of Filters -Spring Security's Servlet support is based on Servlet ``Filter``s, so it is helpful to look at the role of ``Filter``s generally first. -The picture below shows the typical layering of the handlers for a single HTTP request. +Spring Security's Servlet support is based on Servlet Filters, so it is helpful to look at the role of Filters generally first. +The following image shows the typical layering of the handlers for a single HTTP request. .FilterChain [[servlet-filterchain-figure]] image::{figures}/filterchain.png[] -The client sends a request to the application, and the container creates a `FilterChain` which contains the ``Filter``s and `Servlet` that should process the `HttpServletRequest` based on the path of the request URI. -In a Spring MVC application the `Servlet` is an instance of https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#mvc-servlet[`DispatcherServlet`]. -At most one `Servlet` can handle a single `HttpServletRequest` and `HttpServletResponse`. +The client sends a request to the application, and the container creates a `FilterChain`, which contains the `Filter` instances and `Servlet` that should process the `HttpServletRequest`, based on the path of the request URI. +In a Spring MVC application, the `Servlet` is an instance of https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#mvc-servlet[`DispatcherServlet`]. +At most, one `Servlet` can handle a single `HttpServletRequest` and `HttpServletResponse`. However, more than one `Filter` can be used to: -* Prevent downstream ``Filter``s or the `Servlet` from being invoked. -In this instance the `Filter` will typically write the `HttpServletResponse`. -* Modify the `HttpServletRequest` or `HttpServletResponse` used by the downstream ``Filter``s and `Servlet` +* Prevent downstream `Filter` instances or the `Servlet` from being invoked. +In this case, the `Filter` typically writes the `HttpServletResponse`. +* Modify the `HttpServletRequest` or `HttpServletResponse` used by the downstream `Filter` instances and the `Servlet`. The power of the `Filter` comes from the `FilterChain` that is passed into it. @@ -42,4 +42,4 @@ fun doFilter(request: ServletRequest, response: ServletResponse, chain: FilterCh ---- ==== -Since a `Filter` only impacts downstream ``Filter``s and the `Servlet`, the order each `Filter` is invoked is extremely important. +Since a `Filter` impacts only downstream `Filter` instances and the `Servlet`, the order in which each `Filter` is invoked is extremely important. diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/architecture/index.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/architecture/index.adoc index 38b639f9b29..610c4953760 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/architecture/index.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/architecture/index.adoc @@ -2,8 +2,8 @@ = Servlet Security: The Big Picture :figures: images/servlet/architecture -This section discusses Spring Security's high level architecture within Servlet based applications. -We build on this high level understanding within <>, <>, <> sections of the reference. +This section discusses Spring Security's high-level architecture within Servlet based applications. +We build on this high-level understanding within the <>, <>, and <> sections of the reference. // FIXME: Add links to other sections of architecture include::filters.adoc[leveloffset=+1] diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/architecture/security-filter-chain.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/architecture/security-filter-chain.adoc index 508e9e3d218..a970902c1a9 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/architecture/security-filter-chain.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/architecture/security-filter-chain.adoc @@ -1,7 +1,9 @@ [[servlet-securityfilterchain]] = SecurityFilterChain -{security-api-url}org/springframework/security/web/SecurityFilterChain.html[`SecurityFilterChain`] is used by <> to determine which Spring Security ``Filter``s should be invoked for this request. +{security-api-url}org/springframework/security/web/SecurityFilterChain.html[`SecurityFilterChain`] is used by <> to determine which Spring Security `Filter` instances should be invoked for the current request. + +The following image shows the role of `SecurityFilterChain`. .SecurityFilterChain [[servlet-securityfilterchain-figure]] @@ -10,34 +12,36 @@ image::{figures}/securityfilterchain.png[] The <> in `SecurityFilterChain` are typically Beans, but they are registered with `FilterChainProxy` instead of <>. `FilterChainProxy` provides a number of advantages to registering directly with the Servlet container or <>. First, it provides a starting point for all of Spring Security's Servlet support. -For that reason, if you are attempting to troubleshoot Spring Security's Servlet support, adding a debug point in `FilterChainProxy` is a great place to start. +For that reason, if you try to troubleshoot Spring Security's Servlet support, adding a debug point in `FilterChainProxy` is a great place to start. -Second, since `FilterChainProxy` is central to Spring Security usage it can perform tasks that are not viewed as optional. +Second, since `FilterChainProxy` is central to Spring Security usage, it can perform tasks that are not viewed as optional. // FIXME: Add a link to SecurityContext For example, it clears out the `SecurityContext` to avoid memory leaks. It also applies Spring Security's <> to protect applications against certain types of attacks. In addition, it provides more flexibility in determining when a `SecurityFilterChain` should be invoked. -In a Servlet container, ``Filter``s are invoked based upon the URL alone. +In a Servlet container, `Filter` instances are invoked based upon the URL alone. // FIXME: Link to RequestMatcher -However, `FilterChainProxy` can determine invocation based upon anything in the `HttpServletRequest` by leveraging the `RequestMatcher` interface. +However, `FilterChainProxy` can determine invocation based upon anything in the `HttpServletRequest` by using the `RequestMatcher` interface. + +In fact, you can use `FilterChainProxy` to determine which `SecurityFilterChain` should be used. +This lets you provide a totally separate configuration for different _slices_ of your application. -In fact, `FilterChainProxy` can be used to determine which `SecurityFilterChain` should be used. -This allows providing a totally separate configuration for different _slices_ of your application. +The following image shows multiple `SecurityFilterChain` instances: .Multiple SecurityFilterChain [[servlet-multi-securityfilterchain-figure]] image::{figures}/multi-securityfilterchain.png[] -In the <> Figure `FilterChainProxy` decides which `SecurityFilterChain` should be used. -Only the first `SecurityFilterChain` that matches will be invoked. -If a URL of `/api/messages/` is requested, it will first match on ``SecurityFilterChain~0~``'s pattern of `+/api/**+`, so only `SecurityFilterChain~0~` will be invoked even though it also matches on ``SecurityFilterChain~n~``. -If a URL of `/messages/` is requested, it will not match on ``SecurityFilterChain~0~``'s pattern of `+/api/**+`, so `FilterChainProxy` will continue trying each `SecurityFilterChain`. -Assuming that no other, `SecurityFilterChain` instances match `SecurityFilterChain~n~` will be invoked. -// FIXME add link to pattern matching - -Notice that `SecurityFilterChain~0~` has only three security ``Filter``s instances configured. -However, `SecurityFilterChain~n~` has four security ``Filter``s configured. -It is important to note that each `SecurityFilterChain` can be unique and configured in isolation. -In fact, a `SecurityFilterChain` might have zero security ``Filter``s if the application wants Spring Security to ignore certain requests. +In the <> figure, `FilterChainProxy` decides which `SecurityFilterChain` should be used. +Only the first `SecurityFilterChain` that matches is invoked. +If a URL of `/api/messages/` is requested, it first matches on the `SecurityFilterChain~0~` pattern of `+/api/**+`, so only `SecurityFilterChain~0~` is invoked, even though it also matches on ``SecurityFilterChain~n~``. +If a URL of `/messages/` is requested, it does not match on the `SecurityFilterChain~0~` pattern of `+/api/**+`, so `FilterChainProxy` continues trying each `SecurityFilterChain`. +Assuming that no other `SecurityFilterChain` instances match, `SecurityFilterChain~n~` is invoked. +// FIXME: add link to pattern matching + +Notice that `SecurityFilterChain~0~` has only three security `Filter` instances configured. +However, `SecurityFilterChain~n~` has four security `Filter` instanes configured. +It is important to note that each `SecurityFilterChain` can be unique and can be configured in isolation. +In fact, a `SecurityFilterChain` might have zero security `Filter` instances if the application wants Spring Security to ignore certain requests. // FIXME: add link to configuring multiple `SecurityFilterChain` instances diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/architecture/security-filters.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/architecture/security-filters.adoc index 408ec406371..9bc818d42f0 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/architecture/security-filters.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/architecture/security-filters.adoc @@ -2,41 +2,41 @@ = Security Filters The Security Filters are inserted into the <> with the <> API. -The <>s matters. -It is typically not necessary to know the ordering of Spring Security's ``Filter``s. -However, there are times that it is beneficial to know the ordering +The <> instances matters. +It is typically not necessary to know the ordering of Spring Security's `Filter` instances. +However, there are times that it is beneficial to know the ordering. -Below is a comprehensive list of Spring Security Filter ordering: +The following is a comprehensive list of Spring Security Filter ordering: -* ChannelProcessingFilter -* WebAsyncManagerIntegrationFilter -* SecurityContextPersistenceFilter -* HeaderWriterFilter -* CorsFilter -* CsrfFilter -* LogoutFilter -* OAuth2AuthorizationRequestRedirectFilter -* Saml2WebSsoAuthenticationRequestFilter -* X509AuthenticationFilter -* AbstractPreAuthenticatedProcessingFilter -* CasAuthenticationFilter -* OAuth2LoginAuthenticationFilter -* Saml2WebSsoAuthenticationFilter +* `ChannelProcessingFilter` +* `WebAsyncManagerIntegrationFilter` +* `SecurityContextPersistenceFilter` +* `HeaderWriterFilter` +* `CorsFilter` +* `CsrfFilter` +* `LogoutFilter` +* `OAuth2AuthorizationRequestRedirectFilter` +* `Saml2WebSsoAuthenticationRequestFilter` +* `X509AuthenticationFilter` +* `AbstractPreAuthenticatedProcessingFilter` +* `CasAuthenticationFilter` +* `OAuth2LoginAuthenticationFilter` +* `Saml2WebSsoAuthenticationFilter` * <> -* OpenIDAuthenticationFilter -* DefaultLoginPageGeneratingFilter -* DefaultLogoutPageGeneratingFilter -* ConcurrentSessionFilter +* `OpenIDAuthenticationFilter` +* `DefaultLoginPageGeneratingFilter` +* `DefaultLogoutPageGeneratingFilter` +* `ConcurrentSessionFilter` * <> -* BearerTokenAuthenticationFilter +* `BearerTokenAuthenticationFilter` * <> -* RequestCacheAwareFilter -* SecurityContextHolderAwareRequestFilter -* JaasApiIntegrationFilter -* RememberMeAuthenticationFilter -* AnonymousAuthenticationFilter -* OAuth2AuthorizationCodeGrantFilter -* SessionManagementFilter +* `RequestCacheAwareFilter` +* `SecurityContextHolderAwareRequestFilter` +* `JaasApiIntegrationFilter` +* `RememberMeAuthenticationFilter` +* `AnonymousAuthenticationFilter` +* `OAuth2AuthorizationCodeGrantFilter` +* `SessionManagementFilter` * <> * <> -* SwitchUserFilter +* `SwitchUserFilter` diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/anonymous.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/anonymous.adoc index 9f2508f7aa2..16306a34022 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/anonymous.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/anonymous.adoc @@ -1,38 +1,35 @@ [[anonymous]] == Anonymous Authentication - [[anonymous-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. +It is generally considered good security practice to adopt a "`deny-by-default`" stance, 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). -In this case it is easiest to define access configuration attributes for these specific URLs rather than have for every secured resource. -Put differently, sometimes it is nice to say `ROLE_SOMETHING` is required by default and only allow certain exceptions to this rule, such as for login, logout and home pages of an application. +In that case, it is easiest to define access configuration attributes for these specific URLs rather than for every secured resource. +Put differently, sometimes it is nice to say `ROLE_SOMETHING` is required by default and allow only certain exceptions to this rule, such as for login, logout, and home pages of an application. You could also omit these pages from the filter chain entirely, thus bypassing the access control checks, but this may be undesirable for other reasons, particularly if the pages behave differently for authenticated users. This is what we mean by anonymous authentication. -Note that there is no real conceptual difference between a user who is "anonymously authenticated" and an unauthenticated user. +Note that there is no real conceptual difference between a user who is "`anonymously authenticated`" and an unauthenticated user. Spring Security's anonymous authentication just gives you a more convenient way to configure your access-control attributes. -Calls to servlet API calls such as `getCallerPrincipal`, for example, will still return null even though there is actually an anonymous authentication object in the `SecurityContextHolder`. +Calls to servlet API calls, such as `getCallerPrincipal`, still return null, even though there is actually an anonymous authentication object in the `SecurityContextHolder`. There are other situations where anonymous authentication is useful, such as when an auditing interceptor queries the `SecurityContextHolder` to identify which principal was responsible for a given operation. -Classes can be authored more robustly if they know the `SecurityContextHolder` always contains an `Authentication` object, and never `null`. - +Classes can be authored more robustly if they know the `SecurityContextHolder` always contains an `Authentication` object and never contains `null`. [[anonymous-config]] === Configuration -Anonymous authentication support is provided automatically when using the HTTP configuration Spring Security 3.0 and can be customized (or disabled) using the `` element. -You don't need to configure the beans described here unless you are using traditional bean configuration. - -Three classes that together provide the anonymous authentication feature. -`AnonymousAuthenticationToken` is an implementation of `Authentication`, and stores the `GrantedAuthority` s which apply to the anonymous principal. -There is a corresponding `AnonymousAuthenticationProvider`, which is chained into the `ProviderManager` so that `AnonymousAuthenticationToken` s are accepted. -Finally, there is an `AnonymousAuthenticationFilter`, which is chained after the normal authentication mechanisms and automatically adds an `AnonymousAuthenticationToken` to the `SecurityContextHolder` if there is no existing `Authentication` held there. -The definition of the filter and authentication provider appears as follows: - +Anonymous authentication support is provided automatically when you use the HTTP configuration (introduced inSpring Security 3.0). +You can customize (or disable) it by using the `` element. +You need not configure the beans described here unless you are using traditional bean configuration. +Three classes work together to provide the anonymous authentication feature. +`AnonymousAuthenticationToken` is an implementation of `Authentication` and stores the `GrantedAuthority` instancesthat apply to the anonymous principal. +There is a corresponding `AnonymousAuthenticationProvider`, which is chained into the `ProviderManager` so that `AnonymousAuthenticationToken` instances are accepted. +Finally, an `AnonymousAuthenticationFilter` is chained after the normal authentication mechanisms and automatically adds an `AnonymousAuthenticationToken` to the `SecurityContextHolder` if there is no existing `Authentication` held there. +The filter and authentication provider is defined as follows: +==== [source,xml] ---- @@ -47,27 +44,24 @@ The definition of the filter and authentication provider appears as follows: ---- +==== +The `key` is shared between the filter and authentication provider so that tokens created by the former are accepted by the latter - -The `key` is shared between the filter and authentication provider, so that tokens created by the former are accepted by the latter footnote:[ -The use of the `key` property should not be regarded as providing any real security here. +NOTE: The use of the `key` property should not be regarded as providing any real security here. It is merely a book-keeping exercise. -If you are sharing a `ProviderManager` which contains an `AnonymousAuthenticationProvider` in a scenario where it is possible for an authenticating client to construct the `Authentication` object (such as with RMI invocations), then a malicious client could submit an `AnonymousAuthenticationToken` which it had created itself (with chosen username and authority list). -If the `key` is guessable or can be found out, then the token would be accepted by the anonymous provider. -This isn't a problem with normal usage but if you are using RMI you would be best to use a customized `ProviderManager` which omits the anonymous provider rather than sharing the one you use for your HTTP authentication mechanisms. -]. -The `userAttribute` is expressed in the form of `usernameInTheAuthenticationToken,grantedAuthority[,grantedAuthority]`. -This is the same syntax as used after the equals sign for the `userMap` property of `InMemoryDaoImpl`. - -As explained earlier, the benefit of anonymous authentication is that all URI patterns can have security applied to them. -For example: +If you share a `ProviderManager` that contains an `AnonymousAuthenticationProvider` in a scenario where it is possible for an authenticating client to construct the `Authentication` object (such as with RMI invocations), then a malicious client could submit an `AnonymousAuthenticationToken` that it had created itself (with the chosen username and authority list). +If the `key` is guessable or can be found out, the token would be accepted by the anonymous provider. +This is not a problem with normal usage. However, if you use RMI, you should use a customized `ProviderManager` that omits the anonymous provider rather than sharing the one you use for your HTTP authentication mechanisms. +The `userAttribute` is expressed in the form of `usernameInTheAuthenticationToken,grantedAuthority[,grantedAuthority]`. +The same syntax is used after the equals sign for the `userMap` property of `InMemoryDaoImpl`. +As explained earlier, the benefit of anonymous authentication is that all URI patterns can have security applied to them, as the following example shows: +==== [source,xml] ---- - @@ -83,20 +77,18 @@ For example: ---- - - - +==== [[anonymous-auth-trust-resolver]] === 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. -If an `AccessDeniedException` is thrown, and the authentication is of an anonymous type, instead of throwing a 403 (forbidden) response, the filter will instead commence the `AuthenticationEntryPoint` so the principal can authenticate properly. -This is a necessary distinction, otherwise principals would always be deemed "authenticated" and never be given an opportunity to login via form, basic, digest or some other normal authentication mechanism. +The `ExceptionTranslationFilter` uses this interface in processing `AccessDeniedException` instances. +If an `AccessDeniedException` is thrown and the authentication is of an anonymous type, instead of throwing a 403 (forbidden) response, the filter, instead, commences the `AuthenticationEntryPoint` so that the principal can authenticate properly. +This is a necessary distinction. Otherwise, principals would always be deemed "`authenticated`" and never be given an opportunity to login through form, basic, digest, or some other normal authentication mechanism. -You will often see the `ROLE_ANONYMOUS` attribute in the above interceptor configuration replaced with `IS_AUTHENTICATED_ANONYMOUSLY`, which is effectively the same thing when defining access controls. -This is an example of the use of the `AuthenticatedVoter` which we will see in the <>. +We often see the `ROLE_ANONYMOUS` attribute in the earlier interceptor configuration replaced with `IS_AUTHENTICATED_ANONYMOUSLY`, which is effectively the same thing when defining access controls. +This is an example of the use of the `AuthenticatedVoter`, which we cover in the <>. It uses an `AuthenticationTrustResolver` to process this particular configuration attribute and grant access to anonymous users. -The `AuthenticatedVoter` approach is more powerful, since it allows you to differentiate between anonymous, remember-me and fully-authenticated users. -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`. +The `AuthenticatedVoter` approach is more powerful, since it lets you differentiate between anonymous, remember-me, and fully authenticated users. +If you do not need this functionality, though, you can stick with `ROLE_ANONYMOUS`, which is processed by Spring Security's standard `RoleVoter`. diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/architecture/abstract-authentication-processing-filter.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/architecture/abstract-authentication-processing-filter.adoc index a3a8a48d183..c0801ee192e 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/architecture/abstract-authentication-processing-filter.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/architecture/abstract-authentication-processing-filter.adoc @@ -4,7 +4,7 @@ :icondir: images/icons {security-api-url}org/springframework/security/web/authentication/AbstractAuthenticationProcessingFilter.html[`AbstractAuthenticationProcessingFilter`] is used as a base `Filter` for authenticating a user's credentials. -Before the credentials can be authenticated, Spring Security typically requests the credentials using <>. +Before the credentials can be authenticated, Spring Security typically requests the credentials by using <>. Next, the `AbstractAuthenticationProcessingFilter` can authenticate any authentication requests that are submitted to it. @@ -16,26 +16,26 @@ For example, <> is passed into the <> to be authenticated. -image:{icondir}/number_3.png[] If authentication fails, then __Failure__ +image:{icondir}/number_3.png[] If authentication fails, then __Failure__. * The <> is cleared out. * `RememberMeServices.loginFail` is invoked. If remember me is not configured, this is a no-op. -// FIXME: link to rememberme +See the {security-api-url}org/springframework/security/web/authentication/rememberme/package-frame.html[`rememberme`] package. * `AuthenticationFailureHandler` is invoked. -// FIXME: link to AuthenticationFailureHandler +See the {security-api-url}org/springframework/security/web/authentication/AuthenticationFailureHandler.html[`AuthenticationFailureHandler`] interface. image:{icondir}/number_4.png[] If authentication is successful, then __Success__. -* `SessionAuthenticationStrategy` is notified of a new log in. -// FIXME: Add link to SessionAuthenticationStrategy +* `SessionAuthenticationStrategy` is notified of a new login. +See the {security-api-url}org/springframework/security/web/authentication/session/SessionAuthenticationStrategy.html[`SessionAuthenticationStrategy`] interface. * The <> is set on the <>. -Later the `SecurityContextPersistenceFilter` saves the `SecurityContext` to the `HttpSession`. -// FIXME: link securitycontextpersistencefilter +Later, the `SecurityContextPersistenceFilter` saves the `SecurityContext` to the `HttpSession`. +See the {security-api-url}org/springframework/security/web/context/SecurityContextPersistenceFilter.html[`SecurityContextPersistenceFilter`] class. * `RememberMeServices.loginSuccess` is invoked. If remember me is not configured, this is a no-op. -// FIXME: link to rememberme +See the {security-api-url}org/springframework/security/web/authentication/rememberme/package-frame.html[`rememberme`] package. * `ApplicationEventPublisher` publishes an `InteractiveAuthenticationSuccessEvent`. * `AuthenticationSuccessHandler` is invoked. // FIXME: link to AuthenticationSuccessHandler - +See the {security-api-url}org/springframework/security/web/authentication/AuthenticationSuccessHandler.html[`AuthenticationSuccessHandler`] interface. diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/architecture/authentication-entry-point.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/architecture/authentication-entry-point.adoc index cdc00dddbc9..0218b752bca 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/architecture/authentication-entry-point.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/architecture/authentication-entry-point.adoc @@ -4,11 +4,9 @@ {security-api-url}org/springframework/security/web/AuthenticationEntryPoint.html[`AuthenticationEntryPoint`] is used to send an HTTP response that requests credentials from a client. -Sometimes a client will proactively include credentials such as a username/password to request a resource. -In these cases, Spring Security does not need to provide an HTTP response that requests credentials from the client since they are already included. +Sometimes, a client proactively includes credentials (such as a username and password) to request a resource. +In these cases, Spring Security does not need to provide an HTTP response that requests credentials from the client, since they are already included. -In other cases, a client will make an unauthenticated request to a resource that they are not authorized to access. +In other cases, a client makes an unauthenticated request to a resource that they are not authorized to access. In this case, an implementation of `AuthenticationEntryPoint` is used to request credentials from the client. -The `AuthenticationEntryPoint` implementation might perform a <>, respond with an <> header, etc. - - +The `AuthenticationEntryPoint` implementation might perform a <>, respond with an <> header, or take other action. diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/architecture/authentication-manager.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/architecture/authentication-manager.adoc index 5c85382b716..59933643781 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/architecture/authentication-manager.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/architecture/authentication-manager.adoc @@ -2,8 +2,8 @@ = AuthenticationManager {security-api-url}org/springframework/security/authentication/AuthenticationManager.html[`AuthenticationManager`] is the API that defines how Spring Security's Filters perform <>. -The <> that is returned is then set on the <> by the controller (i.e. <>) that invoked the `AuthenticationManager`. -If you are not integrating with __Spring Security's ``Filters``s__ you can set the `SecurityContextHolder` directly and are not required to use an `AuthenticationManager`. +The <> that is returned is then set on the <> by the controller (that is, by <>) that invoked the `AuthenticationManager`. +If you are not integrating with Spring Security's `Filters` instances, you can set the `SecurityContextHolder` directly and are not required to use an `AuthenticationManager`. While the implementation of `AuthenticationManager` could be anything, the most common implementation is <>. // FIXME: add configuration diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/architecture/authentication-provider.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/architecture/authentication-provider.adoc index c7cb0b7b6c3..3932504e34f 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/architecture/authentication-provider.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/architecture/authentication-provider.adoc @@ -1,6 +1,6 @@ [[servlet-authentication-authenticationprovider]] = AuthenticationProvider -Multiple {security-api-url}org/springframework/security/authentication/AuthenticationProvider.html[``AuthenticationProvider``s] can be injected into <>. +You can inject multiple {security-api-url}org/springframework/security/authentication/AuthenticationProvider.html[`AuthenticationProvider`] instances into <>. Each `AuthenticationProvider` performs a specific type of authentication. -For example, <> supports username/password based authentication while `JwtAuthenticationProvider` supports authenticating a JWT token. +For example, <> supports username/password-based authentication, while `JwtAuthenticationProvider` supports authenticating a JWT token. diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/architecture/authentication.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/architecture/authentication.adoc index 2e7319c4aec..170d180f06a 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/architecture/authentication.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/architecture/authentication.adoc @@ -1,18 +1,18 @@ [[servlet-authentication-authentication]] = Authentication -The {security-api-url}org/springframework/security/core/Authentication.html[`Authentication`] serves two main purposes within Spring Security: +The {security-api-url}org/springframework/security/core/Authentication.html[`Authentication`] interface serves two main purposes within Spring Security: * An input to <> to provide the credentials a user has provided to authenticate. When used in this scenario, `isAuthenticated()` returns `false`. -* Represents the currently authenticated user. -The current `Authentication` can be obtained from the <>. +* Represent the currently authenticated user. +You can obtain the current `Authentication` from the <>. The `Authentication` contains: -* `principal` - identifies the user. +* `principal`: Identifies the user. When authenticating with a username/password this is often an instance of <>. -* `credentials` - Often a password. -In many cases this will be cleared after the user is authenticated to ensure it is not leaked. -* `authorities` - the <> are high level permissions the user is granted. -A few examples are roles or scopes. +* `credentials`: Often a password. +In many cases, this is cleared after the user is authenticated, to ensure that it is not leaked. +* `authorities`: The <> instances are high-level permissions the user is granted. +Two examples are roles and scopes. diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/architecture/granted-authority.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/architecture/granted-authority.adoc index 19b45cd0498..98afa85f118 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/architecture/granted-authority.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/architecture/granted-authority.adoc @@ -1,16 +1,16 @@ [[servlet-authentication-granted-authority]] = GrantedAuthority -{security-api-url}org/springframework/security/core/GrantedAuthority.html[``GrantedAuthority``s] are high level permissions the user is granted. A few examples are roles or scopes. +{security-api-url}org/springframework/security/core/GrantedAuthority.html[`GrantedAuthority`] instances are high-level permissions that the user is granted. Two examples are roles and scopes. -``GrantedAuthority``s can be obtained from the <> method. +You can obtain `GrantedAuthority` instances from the <> method. This method provides a `Collection` of `GrantedAuthority` objects. A `GrantedAuthority` is, not surprisingly, an authority that is granted to the principal. -Such authorities are usually "roles", such as `ROLE_ADMINISTRATOR` or `ROLE_HR_SUPERVISOR`. -These roles are later on configured for web authorization, method authorization and domain object authorization. -Other parts of Spring Security are capable of interpreting these authorities, and expect them to be present. -When using username/password based authentication ``GrantedAuthority``s are usually loaded by the <>. +Such authorities are usually "`roles`", such as `ROLE_ADMINISTRATOR` or `ROLE_HR_SUPERVISOR`. +These roles are later configured for web authorization, method authorization, and domain object authorization. +Other parts of Spring Security interpret these authorities and expect them to be present. +When using username/password based authentication `GrantedAuthority` instances are usually loaded by the <>. -Usually the `GrantedAuthority` objects are application-wide permissions. +Usually, the `GrantedAuthority` objects are application-wide permissions. They are not specific to a given domain object. -Thus, you wouldn't likely have a `GrantedAuthority` to represent a permission to `Employee` object number 54, because if there are thousands of such authorities you would quickly run out of memory (or, at the very least, cause the application to take a long time to authenticate a user). -Of course, Spring Security is expressly designed to handle this common requirement, but you'd instead use the project's domain object security capabilities for this purpose. +Thus, you would not likely have a `GrantedAuthority` to represent a permission to `Employee` object number 54, because if there are thousands of such authorities you would quickly run out of memory (or, at the very least, cause the application to take a long time to authenticate a user). +Of course, Spring Security is expressly designed to handle this common requirement, but you should instead use the project's domain object security capabilities for this purpose. diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/architecture/provider-manager.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/architecture/provider-manager.adoc index 4ed8cb4615a..5dc80d7f601 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/architecture/provider-manager.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/architecture/provider-manager.adoc @@ -3,18 +3,18 @@ :figures: images/servlet/authentication/architecture {security-api-url}org/springframework/security/authentication/ProviderManager.html[`ProviderManager`] is the most commonly used implementation of <>. -`ProviderManager` delegates to a `List` of <>. -// FIXME: link to AuthenticationProvider +`ProviderManager` delegates to a `List` of <> instances. +(See the Javadoc for the {security-api-url}org/springframework/security/authentication/AuthenticationProvider.html[`AuthenticationProvider`]. Each `AuthenticationProvider` has an opportunity to indicate that authentication should be successful, fail, or indicate it cannot make a decision and allow a downstream `AuthenticationProvider` to decide. -If none of the configured ``AuthenticationProvider``s can authenticate, then authentication will fail with a `ProviderNotFoundException` which is a special `AuthenticationException` that indicates the `ProviderManager` was not configured to support the type of `Authentication` that was passed into it. +If none of the configured `AuthenticationProvider` instances can authenticate, authentication fails with a `ProviderNotFoundException`, which is a special `AuthenticationException` that indicates that the `ProviderManager` was not configured to support the type of `Authentication` that was passed into it. image::{figures}/providermanager.png[] In practice each `AuthenticationProvider` knows how to perform a specific type of authentication. - For example, one `AuthenticationProvider` might be able to validate a username/password, while another might be able to authenticate a SAML assertion. -This allows each `AuthenticationProvider` to do a very specific type of authentication, while supporting multiple types of authentication and only exposing a single `AuthenticationManager` bean. +For example, one `AuthenticationProvider` might be able to validate a username/password, while another might be able to authenticate a SAML assertion. +This lets each `AuthenticationProvider` do a very specific type of authentication while supporting multiple types of authentication and expose only a single `AuthenticationManager` bean. -`ProviderManager` also allows configuring an optional parent `AuthenticationManager` which is consulted in the event that no `AuthenticationProvider` can perform authentication. +`ProviderManager` also allows configuring an optional parent `AuthenticationManager`, which is consulted in the event that no `AuthenticationProvider` can perform authentication. The parent can be any type of `AuthenticationManager`, but it is often an instance of `ProviderManager`. image::{figures}/providermanager-parent.png[] @@ -25,12 +25,12 @@ This is somewhat common in scenarios where there are multiple <>. Spring Security does not care how the `SecurityContextHolder` is populated. -If it contains a value, then it is used as the currently authenticated user. +If it contains a value, it is used as the currently authenticated user. -The simplest way to indicate a user is authenticated is to set the `SecurityContextHolder` directly. +The simplest way to indicate a user is authenticated is to set the `SecurityContextHolder` directly: .Setting `SecurityContextHolder` ==== @@ -36,18 +36,18 @@ context.authentication = authentication SecurityContextHolder.setContext(context) // <3> ---- -==== <1> We start by creating an empty `SecurityContext`. -It is important to create a new `SecurityContext` instance instead of using `SecurityContextHolder.getContext().setAuthentication(authentication)` to avoid race conditions across multiple threads. -<2> Next we create a new <> object. +You should create a new `SecurityContext` instance instead of using `SecurityContextHolder.getContext().setAuthentication(authentication)` to avoid race conditions across multiple threads. +<2> Next, we create a new <> object. Spring Security does not care what type of `Authentication` implementation is set on the `SecurityContext`. -Here we use `TestingAuthenticationToken` because it is very simple. +Here, we use `TestingAuthenticationToken`, because it is very simple. A more common production scenario is `UsernamePasswordAuthenticationToken(userDetails, password, authorities)`. <3> Finally, we set the `SecurityContext` on the `SecurityContextHolder`. -Spring Security will use this information for <>. +Spring Security uses this information for <>. +==== -If you wish to obtain information about the authenticated principal, you can do so by accessing the `SecurityContextHolder`. +To obtain information about the authenticated principal, access the `SecurityContextHolder`. .Access Currently Authenticated User ==== @@ -72,18 +72,18 @@ val authorities = authentication.authorities ---- ==== -// FIXME: add links to HttpServletRequest.getRemoteUser() and @CurrentSecurityContext @AuthenticationPrincipal +// FIXME: Add links to and relevant description of HttpServletRequest.getRemoteUser() and @CurrentSecurityContext @AuthenticationPrincipal -By default the `SecurityContextHolder` uses a `ThreadLocal` to store these details, which means that the `SecurityContext` is always available to methods in the same thread, even if the `SecurityContext` is not explicitly passed around as an argument to those methods. -Using a `ThreadLocal` in this way is quite safe if care is taken to clear the thread after the present principal's request is processed. +By default, `SecurityContextHolder` uses a `ThreadLocal` to store these details, which means that the `SecurityContext` is always available to methods in the same thread, even if the `SecurityContext` is not explicitly passed around as an argument to those methods. +Using a `ThreadLocal` in this way is quite safe if you take care to clear the thread after the present principal's request is processed. Spring Security's <> ensures that the `SecurityContext` is always cleared. -Some applications aren't entirely suitable for using a `ThreadLocal`, because of the specific way they work with threads. +Some applications are not entirely suitable for using a `ThreadLocal`, because of the specific way they work with threads. For example, a Swing client might want all threads in a Java Virtual Machine to use the same security context. -`SecurityContextHolder` can be configured with a strategy on startup to specify how you would like the context to be stored. -For a standalone application you would use the `SecurityContextHolder.MODE_GLOBAL` strategy. +You can configure `SecurityContextHolder` with a strategy on startup to specify how you would like the context to be stored. +For a standalone application, you would use the `SecurityContextHolder.MODE_GLOBAL` strategy. Other applications might want to have threads spawned by the secure thread also assume the same security identity. -This is achieved by using `SecurityContextHolder.MODE_INHERITABLETHREADLOCAL`. +You can achieve this by using `SecurityContextHolder.MODE_INHERITABLETHREADLOCAL`. You can change the mode from the default `SecurityContextHolder.MODE_THREADLOCAL` in two ways. -The first is to set a system property, the second is to call a static method on `SecurityContextHolder`. -Most applications won't need to change from the default, but if you do, take a look at the JavaDoc for `SecurityContextHolder` to learn more. +The first is to set a system property. The second is to call a static method on `SecurityContextHolder`. +Most applications need not change from the default. However, if you do, take a look at the JavaDoc for `SecurityContextHolder` to learn more. diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/cas.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/cas.adoc index 31436ad1f28..310044eca6a 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/cas.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/cas.adoc @@ -2,106 +2,108 @@ == CAS Authentication [[cas-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. +Unlike other initiatives, JA-SIG's Central Authentication Service is open source, widely used, simple to understand, and platform-independent. It also supports proxy capabilities. +Spring Security fully supports CAS and provides an easy migration path from single-application deployments of Spring Security to multiple-application deployments secured by an enterprise-wide CAS server. 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. +You also need to visit this site to download the CAS Server files. [[cas-how-it-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. +While 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 (and later) supports CAS 3 (and later). +At the time of writing, the CAS server is at version 6.3.3. -Somewhere in your enterprise you will need to setup a CAS server. -The CAS server is simply a standard WAR file, so there isn't anything difficult about setting up your server. -Inside the WAR file you will customise the login and other single sign on pages displayed to users. +NOTE: This section was written about CAS version 3.4, but the material is still current. -When deploying a CAS 3.4 server, you will also need to specify an `AuthenticationHandler` in the `deployerConfigContext.xml` included with CAS. -The `AuthenticationHandler` has a simple method that returns a boolean as to whether a given set of Credentials is valid. -Your `AuthenticationHandler` implementation will need to link into some type of backend authentication repository, such as an LDAP server or database. -CAS itself includes numerous `AuthenticationHandler` s out of the box to assist with this. -When you download and deploy the server war file, it is set up to successfully authenticate users who enter a password matching their username, which is useful for testing. +Somewhere in your enterprise, you need to setup a CAS server. +The CAS server runs from a standard WAR file. +Inside the WAR file, you need to customize the login and other single-sign-on pages displayed to users. -Apart from the CAS server itself, the other key players are of course the secure web applications deployed throughout your enterprise. -These web applications are known as "services". -There are three types of services. -Those that authenticate service tickets, those that can obtain proxy tickets, and those that authenticate proxy tickets. -Authenticating a proxy ticket differs because the list of proxies must be validated and often times a proxy ticket can be reused. +When deploying a CAS 3.4 server, you also need to specify an `AuthenticationHandler` in the `deployerConfigContext.xml` included with CAS. +The `AuthenticationHandler` has a simple method that returns a boolean as to whether a given set of credentials is valid. +Your `AuthenticationHandler` implementation needs to link into some type of backend authentication repository, such as an LDAP server or database. +CAS itself includes numerous `AuthenticationHandler` implementations to assist with this. +When you download and deploy the server war file, it is set up to successfully authenticate users who enter a password that matches their username, which is useful for testing. +Apart from the CAS server itself, the other key players are the secure web applications deployed throughout your enterprise. +These web applications are known as "`services`". +There are three types of services: + +* Services that authenticate service tickets +* Services that can obtain proxy tickets +* Services that authenticate proxy tickets. + +Authenticating a proxy ticket differs because the list of proxies must be validated and because, oftentimes, a proxy ticket can be reused. [[cas-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 basic interaction between a web browser, a CAS server, and a Spring Security-secured service is as follows: -* The web user is browsing the service's public pages. +. The web user browses the service's public pages. CAS or Spring Security is not involved. -* The user eventually requests a page that is either secure or one of the beans it uses is secure. -Spring Security's `ExceptionTranslationFilter` will detect the `AccessDeniedException` or `AuthenticationException`. -* Because the user's `Authentication` object (or lack thereof) caused an `AuthenticationException`, the `ExceptionTranslationFilter` will call the configured `AuthenticationEntryPoint`. -If using CAS, this will be the `CasAuthenticationEntryPoint` class. -* The `CasAuthenticationEntryPoint` will redirect the user's browser to the CAS server. -It will also indicate a `service` parameter, which is the callback URL for the Spring Security service (your application). +. The user eventually requests a page that is either secure or that uses a secure bean. +Spring Security's `ExceptionTranslationFilter` detects the `AccessDeniedException` or `AuthenticationException`. +. Because the user's `Authentication` object (or lack thereof) caused an `AuthenticationException`, the `ExceptionTranslationFilter` calls the configured `AuthenticationEntryPoint`. +If using CAS, this is the `CasAuthenticationEntryPoint` class. +. The `CasAuthenticationEntryPoint` redirects the user's browser to the CAS server. +It also indicates a `service` parameter, which is the callback URL for the Spring Security service (your application). For example, the URL to which the browser is redirected might be https://my.company.com/cas/login?service=https%3A%2F%2Fserver3.company.com%2Fwebapp%2Flogin/cas. -* After the user's browser redirects to CAS, they will be prompted for their username and password. -If the user presents a session cookie which indicates they've previously logged on, they will not be prompted to login again (there is an exception to this procedure, which we'll cover later). -CAS will use the `PasswordHandler` (or `AuthenticationHandler` if using CAS 3.0) discussed above to decide whether the username and password is valid. -* Upon successful login, CAS will redirect the user's browser back to the original service. -It will also include a `ticket` parameter, which is an opaque string representing the "service ticket". -Continuing our earlier example, the URL the browser is redirected to might be https://server3.company.com/webapp/login/cas?ticket=ST-0-ER94xMJmn6pha35CQRoZ. -* Back in the service web application, the `CasAuthenticationFilter` is always listening for requests to `/login/cas` (this is configurable, but we'll use the defaults in this introduction). -The processing filter will construct a `UsernamePasswordAuthenticationToken` representing the service ticket. -The principal will be equal to `CasAuthenticationFilter.CAS_STATEFUL_IDENTIFIER`, whilst the credentials will be the service ticket opaque value. -This authentication request will then be handed to the configured `AuthenticationManager`. -* The `AuthenticationManager` implementation will be the `ProviderManager`, which is in turn configured with the `CasAuthenticationProvider`. -The `CasAuthenticationProvider` only responds to `UsernamePasswordAuthenticationToken` s containing the CAS-specific principal (such as `CasAuthenticationFilter.CAS_STATEFUL_IDENTIFIER`) and `CasAuthenticationToken` s (discussed later). -* `CasAuthenticationProvider` will validate the service ticket using a `TicketValidator` implementation. -This will typically be a `Cas20ServiceTicketValidator` which is one of the classes included in the CAS client library. -In the event the application needs to validate proxy tickets, the `Cas20ProxyTicketValidator` is used. -The `TicketValidator` makes an HTTPS request to the CAS server in order to validate the service ticket. -It may also include a proxy callback URL, which is included in this example: https://my.company.com/cas/proxyValidate?service=https%3A%2F%2Fserver3.company.com%2Fwebapp%2Flogin/cas&ticket=ST-0-ER94xMJmn6pha35CQRoZ&pgtUrl=https://server3.company.com/webapp/login/cas/proxyreceptor. -* Back on the CAS server, the validation request will be received. -If the presented service ticket matches the service URL the ticket was issued to, CAS will provide an affirmative response in XML indicating the username. -If any proxy was involved in the authentication (discussed below), the list of proxies is also included in the XML response. -* [OPTIONAL] If the request to the CAS validation service included the proxy callback URL (in the `pgtUrl` parameter), CAS will include a `pgtIou` string in the XML response. +. After the user's browser redirects to CAS, they are prompted for their username and password. +If the user presents a session cookie that indicates that they have previously logged on, they are not prompted to login again (there is an exception to this procedure, which we cover later). +CAS uses the `PasswordHandler` (or `AuthenticationHandler` if using CAS 3.0) discussed earler to decide whether the username and password are valid. +. Upon successful login, CAS redirects the user's browser back to the original service. +It also includes a `ticket` parameter, which is an opaque string that represents the "`service ticket`". +Continuing our earlier example, the URL to which the browser is redirected might be https://server3.company.com/webapp/login/cas?ticket=ST-0-ER94xMJmn6pha35CQRoZ. +. Back in the service web application, the `CasAuthenticationFilter` is always listening for requests to `/login/cas` (this is configurable, but we use the defaults in this introduction). +The processing filter constructs a `UsernamePasswordAuthenticationToken` that represents the service ticket. +The principal is equal to `CasAuthenticationFilter.CAS_STATEFUL_IDENTIFIER`, while the credentials are the service ticket opaque value. +This authentication request is then handed to the configured `AuthenticationManager`. +. The `AuthenticationManager` implementation is the `ProviderManager`, which is in turn configured with the `CasAuthenticationProvider`. +The `CasAuthenticationProvider` only responds to `UsernamePasswordAuthenticationToken` instances that contain the CAS-specific principal (such as `CasAuthenticationFilter.CAS_STATEFUL_IDENTIFIER`) and `CasAuthenticationToken` instances (discussed later). +. `CasAuthenticationProvider` will validate the service ticket using a `TicketValidator` implementation. +This is typically a `Cas20ServiceTicketValidator`, which is one of the classes included in the CAS client library. +If the application needs to validate proxy tickets, the `Cas20ProxyTicketValidator` is used. +The `TicketValidator` makes an HTTPS request to the CAS server to validate the service ticket. +It can also include a proxy callback URL, which is included in this example: https://my.company.com/cas/proxyValidate?service=https%3A%2F%2Fserver3.company.com%2Fwebapp%2Flogin/cas&ticket=ST-0-ER94xMJmn6pha35CQRoZ&pgtUrl=https://server3.company.com/webapp/login/cas/proxyreceptor. +. Back on the CAS server, the validation request is received. +If the presented service ticket matches the service URL to which the ticket was issued, CAS provides an affirmative response in XML that indicates the username. +If any proxy was involved in the authentication (discussed later), the list of proxies is also included in the XML response. +. [OPTIONAL] If the request to the CAS validation service included the proxy callback URL (in the `pgtUrl` parameter), CAS includes a `pgtIou` string in the XML response. This `pgtIou` represents a proxy-granting ticket IOU. -The CAS server will then create its own HTTPS connection back to the `pgtUrl`. +The CAS server thens create its own HTTPS connection back to the `pgtUrl`. This is to mutually authenticate the CAS server and the claimed service URL. -The HTTPS connection will be used to send a proxy granting ticket to the original web application. -For example, https://server3.company.com/webapp/login/cas/proxyreceptor?pgtIou=PGTIOU-0-R0zlgrl4pdAQwBvJWO3vnNpevwqStbSGcq3vKB2SqSFFRnjPHt&pgtId=PGT-1-si9YkkHLrtACBo64rmsi3v2nf7cpCResXg5MpESZFArbaZiOKH. -* The `Cas20TicketValidator` will parse the XML received from the CAS server. -It will return to the `CasAuthenticationProvider` a `TicketResponse`, which includes the username (mandatory), proxy list (if any were involved), and proxy-granting ticket IOU (if the proxy callback was requested). -* Next `CasAuthenticationProvider` will call a configured `CasProxyDecider`. +The HTTPS connection is used to send a proxy granting ticket to the original web application -- +for example, https://server3.company.com/webapp/login/cas/proxyreceptor?pgtIou=PGTIOU-0-R0zlgrl4pdAQwBvJWO3vnNpevwqStbSGcq3vKB2SqSFFRnjPHt&pgtId=PGT-1-si9YkkHLrtACBo64rmsi3v2nf7cpCResXg5MpESZFArbaZiOKH. +. The `Cas20TicketValidator` parses the XML received from the CAS server. +It returns to the `CasAuthenticationProvider` a `TicketResponse`, which includes the username (mandatory), proxy list (if any were involved), and proxy-granting ticket IOU (if the proxy callback was requested). +. Next `CasAuthenticationProvider` calls a configured `CasProxyDecider`. The `CasProxyDecider` indicates whether the proxy list in the `TicketResponse` is acceptable to the service. -Several implementations are provided with Spring Security: `RejectProxyTickets`, `AcceptAnyCasProxy` and `NamedCasProxyDecider`. -These names are largely self-explanatory, except `NamedCasProxyDecider` which allows a `List` of trusted proxies to be provided. -* `CasAuthenticationProvider` will next request a `AuthenticationUserDetailsService` to load the `GrantedAuthority` objects that apply to the user contained in the `Assertion`. -* If there were no problems, `CasAuthenticationProvider` constructs a `CasAuthenticationToken` including the details contained in the `TicketResponse` and the ``GrantedAuthority``s. -* Control then returns to `CasAuthenticationFilter`, which places the created `CasAuthenticationToken` in the security context. -* The user's browser is redirected to the original page that caused the `AuthenticationException` (or a custom destination depending on the configuration). +Spring Security provides three implementations: `RejectProxyTickets`, `AcceptAnyCasProxy`, and `NamedCasProxyDecider`. +These names are largely self-explanatory, except `NamedCasProxyDecider`, which allows a `List` of trusted proxies to be provided. +. `CasAuthenticationProvider` next requests a `AuthenticationUserDetailsService` to load the `GrantedAuthority` objects that apply to the user contained in the `Assertion`. +. If there were no problems, `CasAuthenticationProvider` constructs a `CasAuthenticationToken`, including the details contained in the `TicketResponse` and the `GrantedAuthority` instances. +. Control then returns to `CasAuthenticationFilter`, which places the created `CasAuthenticationToken` in the security context. +. The user's browser is redirected to the original page that caused the `AuthenticationException` (or a custom destination depending on the configuration). -It's good that you're still here! -Let's now look at how this is configured +Next, we discuss how to configure the components that are involved in that long interaction. [[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. +Spring Security makes the web application side of CAS easy. +We assume you already know the basics of using Spring Security, so these are not covered again later. +We also assume a namespace-based configuration is being used and add in the CAS beans as required. Each section builds upon the previous section. -A full CAS sample application can be found in the Spring Security <>. - +You can find a full CAS sample application in the Spring Security <>. [[cas-st]] ==== 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. -This represents your CAS service: +This section describes how to set up Spring Security to authenticate Service Tickets. +Oftentimes, this is all a web application requires. +You need to add a `ServiceProperties` bean to your application context to represent your CAS service: +==== [source,xml] ---- ---- +==== -The `service` must equal a URL that will be monitored by the `CasAuthenticationFilter`. -The `sendRenew` defaults to false, but should be set to true if your application is particularly sensitive. -What this parameter does is tell the CAS login service that a single sign on login is unacceptable. -Instead, the user will need to re-enter their username and password in order to gain access to the service. +The `service` must equal a URL that is monitored by the `CasAuthenticationFilter`. +`sendRenew` defaults to `false` but should be set to `true` if your application is particularly sensitive. +This parameter tells the CAS login service that a single-sign-on login is unacceptable. +Instead, the user needs to re-enter their username and password to gain access to the service. -The following beans should be configured to commence the CAS authentication process (assuming you're using a namespace configuration): +The following beans should be configured to commence the CAS authentication process (assuming you use a namespace configuration): +==== [source,xml] ---- @@ -137,17 +141,19 @@ The following beans should be configured to commence the CAS authentication proc ---- +==== For CAS to operate, the `ExceptionTranslationFilter` must have its `authenticationEntryPoint` property set to the `CasAuthenticationEntryPoint` bean. -This can easily be done using <> as is done in the example above. -The `CasAuthenticationEntryPoint` must refer to the `ServiceProperties` bean (discussed above), which provides the URL to the enterprise's CAS login server. -This is where the user's browser will be redirected. +You can do so by using <>, as in the preceding example. +The `CasAuthenticationEntryPoint` must refer to the `ServiceProperties` bean (discussed earlier), which provides the URL to the enterprise's CAS login server. +This is where the user's browser is redirected. The `CasAuthenticationFilter` has very similar properties to the `UsernamePasswordAuthenticationFilter` (used for form-based logins). You can use these properties to customize things like behavior for authentication success and failure. -Next you need to add a `CasAuthenticationProvider` and its collaborators: +Next, you need to add a `CasAuthenticationProvider` and its collaborators: +==== [source,xml,attrs="-attributes"] ---- @@ -180,24 +186,25 @@ Normally passwords should be hashed using BCrypt --> ... ---- +==== The `CasAuthenticationProvider` uses a `UserDetailsService` instance to load the authorities for a user, once they have been authenticated by CAS. -We've shown a simple in-memory setup here. +We have shown a simple in-memory setup here. Note that the `CasAuthenticationProvider` does not actually use the password for authentication, but it does use the authorities. The beans are all reasonably self-explanatory if you refer back to the <> section. This completes the most basic configuration for CAS. -If you haven't made any mistakes, your web application should happily work within the framework of CAS single sign on. -No other parts of Spring Security need to be concerned about the fact CAS handled authentication. -In the following sections we will discuss some (optional) more advanced configurations. - +If you have not made any mistakes, your web application should happily work within the framework of CAS single sign on. +No other parts of Spring Security need to be concerned about the fact that CAS handled authentication. +In the following sections, we discuss some (optional) more advanced configurations. [[cas-singlelogout]] ==== 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 +The following updates to the Spring Security configuration handle Single Logout: +==== [source,xml] ---- @@ -221,26 +228,26 @@ Below are updates to the Spring Security configuration that handle Single Logout ---- +==== -The `logout` element logs the user out of the local application, but does not end the session with the CAS server or any other applications that have been logged into. -The `requestSingleLogoutFilter` filter will allow the URL of `/spring_security_cas_logout` to be requested to redirect the application to the configured CAS Server logout URL. -Then the CAS Server will send a Single Logout request to all the services that were signed into. +The `logout` element logs the user out of the local application but does not end the session with the CAS server or any other applications that have been logged into. +The `requestSingleLogoutFilter` filter lets the URL of `/spring_security_cas_logout` be requested to redirect the application to the configured CAS Server logout URL. +Then the CAS Server sends a Single Logout request to all the services that were signed into. The `singleLogoutFilter` handles the Single Logout request by looking up the `HttpSession` in a static `Map` and then invalidating it. It might be confusing why both the `logout` element and the `singleLogoutFilter` are needed. -It is considered best practice to logout locally first since the `SingleSignOutFilter` just stores the `HttpSession` in a static `Map` in order to call invalidate on it. +It is considered best practice to logout locally first, since the `SingleSignOutFilter` just stores the `HttpSession` in a static `Map` in order to invalidate it. With the configuration above, the flow of logout would be: -* The user requests `/logout` which would log the user out of the local application and send the user to the logout success page. -* The logout success page, `/cas-logout.jsp`, should instruct the user to click a link pointing to `/logout/cas` in order to logout out of all applications. +* The user requests `/logout`, which would log the user out of the local application and send the user to the logout success page. +* The logout success page, `/cas-logout.jsp`, should instruct the user to click a link that points to `/logout/cas`, to logout out of all applications. * When the user clicks the link, the user is redirected to the CAS single logout URL (https://localhost:9443/cas/logout). * On the CAS Server side, the CAS single logout URL then submits single logout requests to all the CAS Services. On the CAS Service side, JASIG's `SingleSignOutFilter` processes the logout request by invalidating the original session. +The next step is to add the following to your `web.xml` file: - -The next step is to add the following to your web.xml - +==== [source,xml] ---- @@ -263,45 +270,49 @@ The next step is to add the following to your web.xml ---- +==== -When using the SingleSignOutFilter you might encounter some encoding issues. -Therefore it is recommended to add the `CharacterEncodingFilter` to ensure that the character encoding is correct when using the `SingleSignOutFilter`. -Again, refer to JASIG's documentation for details. +When using the `SingleSignOutFilter`, you might encounter some encoding issues. +Therefore, we recommend adding the `CharacterEncodingFilter` to ensure that the character encoding is correct when using the `SingleSignOutFilter`. +Again, see JASIG's documentation for details. The `SingleSignOutHttpSessionListener` ensures that when an `HttpSession` expires, the mapping used for single logout is removed. [[cas-pt-client]] ==== 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. +This section describes how to authenticate to a service by using CAS. +In other words, this section discusses how to set up 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 -In order to authenticate to a stateless service, the application needs to obtain a proxy granting ticket (PGT). +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. The first step is to include a `ProxyGrantingTicketStorage` in your Spring Security configuration. -This is used to store PGT's that are obtained by the `CasAuthenticationFilter` so that they can be used to obtain proxy tickets. -An example configuration is shown below +This is used to store PGTs that are obtained by the `CasAuthenticationFilter` so that they can be used to obtain proxy tickets. +The following example shows a typical configuration: +==== [source,xml] ---- ---- +==== The next step is to update the `CasAuthenticationProvider` to be able to obtain proxy tickets. -To do this replace the `Cas20ServiceTicketValidator` with a `Cas20ProxyTicketValidator`. -The `proxyCallbackUrl` should be set to a URL that the application will receive PGT's at. -Last, the configuration should also reference the `ProxyGrantingTicketStorage` so it can use a PGT to obtain proxy tickets. -You can find an example of the configuration changes that should be made below. +To do so, replace the `Cas20ServiceTicketValidator` with a `Cas20ProxyTicketValidator`. +The `proxyCallbackUrl` should be set to a URL that at which the application receives PGTs. +Finally, the configuration should also reference the `ProxyGrantingTicketStorage` so that it can use a PGT to obtain proxy tickets. +The following example shows the configuration changes that should be made: +==== [source,xml] ---- ---- +==== -The last step is to update the `CasAuthenticationFilter` to accept PGT and to store them in the `ProxyGrantingTicketStorage`. -It is important the `proxyReceptorUrl` matches the `proxyCallbackUrl` of the `Cas20ProxyTicketValidator`. -An example configuration is shown below. +The last step is to update the `CasAuthenticationFilter` to accept PGTs and to store them in the `ProxyGrantingTicketStorage`. +The `proxyReceptorUrl` should match the `proxyCallbackUrl` of the `Cas20ProxyTicketValidator`. +The following example shows a typical configuration: +==== [source,xml] ---- - ... - ---- +==== [[cas-pt-client-sample]] -===== 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. +===== Calling a Stateless Service by 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 <> contains a working example in the `ProxyTicketSampleServlet`. -Example code can be found below: +The following listing shows an example: +==== [source,java] ---- protected void doGet(HttpServletRequest request, HttpServletResponse response) @@ -357,27 +370,29 @@ String proxyResponse = CommonUtils.getResponseFromServer(serviceUrl, "UTF-8"); ... } ---- +==== [[cas-pt]] ==== 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`. +A stateful client is considered to be any client that submits to the `filterProcessUrl` of the `CasAuthenticationFilter`. +A stateless client is any client that presents an authentication request to `CasAuthenticationFilter` on a URL other than the `filterProcessUrl`. -Because remoting protocols have no way of presenting themselves within the context of an `HttpSession`, it isn't possible to rely on the default practice of storing the security context in the session between requests. -Furthermore, because the CAS server invalidates a ticket after it has been validated by the `TicketValidator`, presenting the same proxy ticket on subsequent requests will not work. +Because remoting protocols have no way of presenting themselves within the context of an `HttpSession`, it is not possible to rely on the default practice of storing the security context in the session between requests. +Furthermore, because the CAS server invalidates a ticket after it has been validated by the `TicketValidator`, presenting the same proxy ticket on subsequent requests does not work. One obvious option is to not use CAS at all for remoting protocol clients. However, this would eliminate many of the desirable features of CAS. As a middle-ground, the `CasAuthenticationProvider` uses a `StatelessTicketCache`. -This is used solely for stateless clients which use a principal equal to `CasAuthenticationFilter.CAS_STATELESS_IDENTIFIER`. -What happens is the `CasAuthenticationProvider` will store the resulting `CasAuthenticationToken` in the `StatelessTicketCache`, keyed on the proxy ticket. -Accordingly, remoting protocol clients can present the same proxy ticket and the `CasAuthenticationProvider` will not need to contact the CAS server for validation (aside from the first request). -Once authenticated, the proxy ticket could be used for URLs other than the original target service. +This is used solely for stateless clients that use a principal equal to `CasAuthenticationFilter.CAS_STATELESS_IDENTIFIER`. +The `CasAuthenticationProvider` stores the resulting `CasAuthenticationToken` in the `StatelessTicketCache`, keyed on the proxy ticket. +Accordingly, remoting protocol clients can present the same proxy ticket, and the `CasAuthenticationProvider` does not need to contact the CAS server for validation (aside from the first request). +Once authenticated, the proxy ticket can be used for URLs other than the original target service. This section builds upon the previous sections to accommodate proxy ticket authentication. -The first step is to specify to authenticate all artifacts as shown below. +The first step is to specify to authenticate all artifacts: +==== [source,xml] ---- ---- +==== The next step is to specify `serviceProperties` and the `authenticationDetailsSource` for the `CasAuthenticationFilter`. -The `serviceProperties` property instructs the `CasAuthenticationFilter` to attempt to authenticate all artifacts instead of only ones present on the `filterProcessUrl`. +The `serviceProperties` property instructs the `CasAuthenticationFilter` to try to authenticate all artifacts instead of only ones present on the `filterProcessUrl`. The `ServiceAuthenticationDetailsSource` creates a `ServiceAuthenticationDetails` that ensures the current URL, based upon the `HttpServletRequest`, is used as the service URL when validating the ticket. -The method for generating the service URL can be customized by injecting a custom `AuthenticationDetailsSource` that returns a custom `ServiceAuthenticationDetails`. +You can customize the method for generating the service URL by injecting a custom `AuthenticationDetailsSource` that returns a custom `ServiceAuthenticationDetails`. +==== [source,xml] ---- ---- +==== -You will also need to update the `CasAuthenticationProvider` to handle proxy tickets. -To do this replace the `Cas20ServiceTicketValidator` with a `Cas20ProxyTicketValidator`. -You will need to configure the `statelessTicketCache` and which proxies you want to accept. -You can find an example of the updates required to accept all proxies below. +You also need to update the `CasAuthenticationProvider` to handle proxy tickets. +To do so, replace the `Cas20ServiceTicketValidator` with a `Cas20ProxyTicketValidator`. +You need to configure the `statelessTicketCache` and which proxies you want to accept. +The following example shows the updates required to accept all proxies: +==== [source,xml] ---- @@ -441,3 +460,4 @@ You can find an example of the updates required to accept all proxies below. ---- +==== diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/events.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/events.adoc index 254df9a6694..a97b2b17af8 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/events.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/events.adoc @@ -1,10 +1,10 @@ [[servlet-events]] == Authentication Events -For each authentication that succeeds or fails, a `AuthenticationSuccessEvent` or `AuthenticationFailureEvent` is fired, respectively. +For each authentication that succeeds or fails, a `AuthenticationSuccessEvent` or `AuthenticationFailureEvent`, respectively, is fired. To listen for these events, you must first publish an `AuthenticationEventPublisher`. -Spring Security's `DefaultAuthenticationEventPublisher` will probably do fine: +Spring Security's `DefaultAuthenticationEventPublisher` works fine for this purpose: ==== .Java @@ -28,7 +28,7 @@ fun authenticationEventPublisher ---- ==== -Then, you can use Spring's `@EventListener` support: +Then you can use Spring's `@EventListener` support: ==== .Java @@ -70,7 +70,7 @@ While similar to `AuthenticationSuccessHandler` and `AuthenticationFailureHandle === Adding Exception Mappings -`DefaultAuthenticationEventPublisher` by default will publish an `AuthenticationFailureEvent` for the following events: +By default, `DefaultAuthenticationEventPublisher` publishes an `AuthenticationFailureEvent` for the following events: |============ | Exception | Event @@ -85,9 +85,9 @@ While similar to `AuthenticationSuccessHandler` and `AuthenticationFailureHandle | `InvalidBearerTokenException` | `AuthenticationFailureBadCredentialsEvent` |============ -The publisher does an exact `Exception` match, which means that sub-classes of these exceptions won't also produce events. +The publisher does an exact `Exception` match, which means that sub-classes of these exceptions do not also produce events. -To that end, you may want to supply additional mappings to the publisher via the `setAdditionalExceptionMappings` method: +To that end, you may want to supply additional mappings to the publisher through the `setAdditionalExceptionMappings` method: ==== .Java @@ -123,7 +123,7 @@ fun authenticationEventPublisher === Default Event -And, you can supply a catch-all event to fire in the case of any `AuthenticationException`: +You can also supply a catch-all event to fire in the case of any `AuthenticationException`: ==== .Java diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/index.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/index.adoc index 9536e950e68..0d0507f8cb3 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/index.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/index.adoc @@ -7,34 +7,34 @@ This section discusses: [[servlet-authentication-architecture]] *Architecture Components* -This section describes the main architectural components of Spring Security's used in Servlet authentication. -If you need concrete flows that explain how these pieces fit together, look at the <> specific sections. - -* <> - The `SecurityContextHolder` is where Spring Security stores the details of who is <>. -* <> - is obtained from the `SecurityContextHolder` and contains the `Authentication` of the currently authenticated user. -* <> - Can be the input to `AuthenticationManager` to provide the credentials a user has provided to authenticate or the current user from the `SecurityContext`. -* <> - An authority that is granted to the principal on the `Authentication` (i.e. roles, scopes, etc.) -* <> - the API that defines how Spring Security's Filters perform <>. -* <> - the most common implementation of `AuthenticationManager`. -* <> - used by `ProviderManager` to perform a specific type of authentication. -* <> - used for requesting credentials from a client (i.e. redirecting to a log in page, sending a `WWW-Authenticate` response, etc.) -* <> - a base `Filter` used for authentication. -This also gives a good idea of the high level flow of authentication and how pieces work together. +This section describes the main architectural components of Spring Security that are used in Servlet authentication. +If you need concrete flows that explain how these pieces fit together, see the <> specific sections. + +* <>: The `SecurityContextHolder` is where Spring Security stores the details of who is <>. +* <>: Is obtained from the `SecurityContextHolder` and contains the `Authentication` of the currently authenticated user. +* <>: Can be the input to `AuthenticationManager` to provide the credentials a user has provided to authenticate or the current user from the `SecurityContext`. +* <>: An authority that is granted to the principal on the `Authentication` (roles, scopes, and so on) +* <>: The API that defines how Spring Security's Filters perform <>. +* <>: The most common implementation of `AuthenticationManager`. +* <>: Used by `ProviderManager` to perform a specific type of authentication. +* <>: Used for requesting credentials from a client (redirecting to a log in page, sending a `WWW-Authenticate` response, and so on) +* <>: A base `Filter` used for authentication. +This also gives a good idea of the high-level flow of authentication and how the pieces work together. [[servlet-authentication-mechanisms]] *Authentication Mechanisms* // FIXME: brief description -* <> - how to authenticate with a username/password -* <> - OAuth 2.0 Log In with OpenID Connect and non-standard OAuth 2.0 Login (i.e. GitHub) -* <> - SAML 2.0 Log In -* <> - Central Authentication Server (CAS) Support -* <> - How to remember a user past session expiration -* <> - Authenticate with JAAS -* <> - OpenID Authentication (not to be confused with OpenID Connect) -* <> - Authenticate with an external mechanism such as https://www.siteminder.com/[SiteMinder] or Java EE security but still use Spring Security for authorization and protection against common exploits. -* <> - X509 Authentication +* <>: How to authenticate with a username and password. +* <>: OAuth 2.0 Log In with OpenID Connect and non-standard OAuth 2.0 Login (i.e. GitHub). +* <>: SAML 2.0 Log In. +* <>: Central Authentication Server (CAS) support. +* <>: How to remember the past session expiration of a user. +* <>: Authenticate with JAAS. +* <>: OpenID Authentication (not to be confused with OpenID Connect). +* <>: Authenticate with an external mechanism such as https://www.siteminder.com/[SiteMinder] or Java EE security but still use Spring Security for authorization and protection against common exploits. +* <>: X509 Authentication. // FIXME: Add other mechanisms diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/jaas.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/jaas.adoc index 3a1864ca896..98020d94061 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/jaas.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/jaas.adoc @@ -1,80 +1,71 @@ [[servlet-jaas]] == Java Authentication and Authorization Service (JAAS) Provider - -=== 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. - +Spring Security provides a package to delegate authentication requests to the Java Authentication and Authorization Service (JAAS). +This section discusses that package. [[jaas-abstractjaasauthenticationprovider]] === AbstractJaasAuthenticationProvider -The `AbstractJaasAuthenticationProvider` is the basis for the provided JAAS `AuthenticationProvider` implementations. +The `AbstractJaasAuthenticationProvider` class 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. - +The `AbstractJaasAuthenticationProvider` has a number of dependencies that can be injected into it, as discussed in the remainder of this section. [[jaas-callbackhandler]] ==== JAAS CallbackHandler -Most JAAS `LoginModule` s require a callback of some sort. +Most JAAS `LoginModule` instances require a callback of some sort. These callbacks are usually used to obtain the username and password from the user. -In a Spring Security deployment, Spring Security is responsible for this user interaction (via the authentication mechanism). -Thus, by the time the authentication request is delegated through to JAAS, Spring Security's authentication mechanism will already have fully-populated an `Authentication` object containing all the information required by the JAAS `LoginModule`. - -Therefore, the JAAS package for Spring Security provides two default callback handlers, `JaasNameCallbackHandler` and `JaasPasswordCallbackHandler`. -Each of these callback handlers implement `JaasAuthenticationCallbackHandler`. -In most cases these callback handlers can simply be used without understanding the internal mechanics. +In a Spring Security deployment, Spring Security is responsible for this user interaction (through the authentication mechanism). +Thus, by the time the authentication request is delegated through to JAAS, Spring Security's authentication mechanism has already fully populated an `Authentication` object that contains all the information required by the JAAS `LoginModule`. -For those needing full control over the callback behavior, internally `AbstractJaasAuthenticationProvider` wraps these `JaasAuthenticationCallbackHandler` s with an `InternalCallbackHandler`. -The `InternalCallbackHandler` is the class that actually implements JAAS normal `CallbackHandler` interface. -Any time that the JAAS `LoginModule` is used, it is passed a list of application context configured `InternalCallbackHandler` s. -If the `LoginModule` requests a callback against the `InternalCallbackHandler` s, the callback is in-turn passed to the `JaasAuthenticationCallbackHandler` s being wrapped. +Therefore, the JAAS package for Spring Security provides two default callback handlers: `JaasNameCallbackHandler` and `JaasPasswordCallbackHandler`. +Each of these callback handlers implements `JaasAuthenticationCallbackHandler`. +In most cases, these callback handlers can be used without understanding the internal mechanics. +For those needing full control over the callback behavior, `AbstractJaasAuthenticationProvider` internally wraps these `JaasAuthenticationCallbackHandler` instances with an `InternalCallbackHandler`. +The `InternalCallbackHandler` is the class that actually implements the JAAS normal `CallbackHandler` interface. +Any time that the JAAS `LoginModule` is used, it is passed a list of application contexts configured `InternalCallbackHandler` instances. +If the `LoginModule` requests a callback against the `InternalCallbackHandler` instances, the callback is, in turn, passed to the `JaasAuthenticationCallbackHandler` instances being wrapped. [[jaas-authoritygranter]] ==== JAAS AuthorityGranter JAAS works with principals. -Even "roles" are represented as principals in JAAS. +Even "`roles`" are represented as principals in JAAS. Spring Security, on the other hand, works with `Authentication` objects. -Each `Authentication` object contains a single principal, and multiple `GrantedAuthority` s. +Each `Authentication` object contains a single principal and multiple `GrantedAuthority` instances. To facilitate mapping between these different concepts, Spring Security's JAAS package includes an `AuthorityGranter` interface. -An `AuthorityGranter` is responsible for inspecting a JAAS principal and returning a set of `String` s, representing the authorities assigned to the principal. -For each returned authority string, the `AbstractJaasAuthenticationProvider` creates a `JaasGrantedAuthority` (which implements Spring Security's `GrantedAuthority` interface) containing the authority string and the JAAS principal that the `AuthorityGranter` was passed. -The `AbstractJaasAuthenticationProvider` obtains the JAAS principals by firstly successfully authenticating the user's credentials using the JAAS `LoginModule`, and then accessing the `LoginContext` it returns. +An `AuthorityGranter` is responsible for inspecting a JAAS principal and returning a set of `String` objects that represent the authorities assigned to the principal. +For each returned authority string, the `AbstractJaasAuthenticationProvider` creates a `JaasGrantedAuthority` (which implements Spring Security's `GrantedAuthority` interface) that contains the authority string and the JAAS principal that the `AuthorityGranter` was passed. +The `AbstractJaasAuthenticationProvider` obtains the JAAS principals by first successfully authenticating the user's credentials by using the JAAS `LoginModule` and then accessing the `LoginContext` it returns. A call to `LoginContext.getSubject().getPrincipals()` is made, with each resulting principal passed to each `AuthorityGranter` defined against the `AbstractJaasAuthenticationProvider.setAuthorityGranters(List)` property. -Spring Security does not include any production `AuthorityGranter` s given that every JAAS principal has an implementation-specific meaning. +Spring Security does not include any production `AuthorityGranter` instances, given that every JAAS principal has an implementation-specific meaning. However, there is a `TestAuthorityGranter` in the unit tests that demonstrates a simple `AuthorityGranter` implementation. - [[jaas-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. - +The `DefaultJaasAuthenticationProvider` lets a JAAS `Configuration` object be injected into it as a dependency. +It then creates a `LoginContext` by using the injected JAAS `Configuration`. +This means that `DefaultJaasAuthenticationProvider` is not bound to any particular implementation of `Configuration`, as `JaasAuthenticationProvider` is. [[jaas-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`. -For details, refer to the class level javadoc of `InMemoryConfiguration`. - +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` instances. +`InMemoryConfiguration` also supports a default `Array` of `AppConfigurationEntry` objects that is used if no mapping is found within the provided `Map`. +For details, see the {security-api-url}org/springframework/security/authentication/jaas/memory/InMemoryConfiguration.html[Javadoc of `InMemoryConfiguration`]. [[jaas-djap-config]] ==== 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. +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 dependent on the default `Configuration` implementation. -An example configuration of `DefaultJaasAuthenticationProvider` using `InMemoryConfiguration` is provided below. +The next example provides a configuration of `DefaultJaasAuthenticationProvider` that uses `InMemoryConfiguration`. Note that custom implementations of `Configuration` can easily be injected into `DefaultJaasAuthenticationProvider` as well. - +==== [source,xml] ---- - @@ -110,32 +101,32 @@ class="org.springframework.security.authentication.jaas.DefaultJaasAuthenticatio - ---- - - +==== [[jaas-jaasauthenticationprovider]] === JaasAuthenticationProvider -The `JaasAuthenticationProvider` assumes the default `Configuration` is an instance of https://download.oracle.com/javase/1.4.2/docs/guide/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` assumes that the default `Configuration` is an instance of https://download.oracle.com/javase/1.4.2/docs/guide/security/jaas/spec/com/sun/security/auth/login/ConfigFile.html[`ConfigFile`]. +This assumption is made in order to try to update the `Configuration`. The `JaasAuthenticationProvider` then uses the default `Configuration` to create the `LoginContext`. -Let's assume we have a JAAS login configuration file, `/WEB-INF/login.conf`, with the following contents: +Assume that we have a JAAS login configuration file, `/WEB-INF/login.conf`, with the following contents: +==== [source,txt] ---- JAASTest { sample.SampleLoginModule required; }; ---- +==== -Like all Spring Security beans, the `JaasAuthenticationProvider` is configured via the application context. +Like all Spring Security beans, the `JaasAuthenticationProvider` is configured through the application context. The following definitions would correspond to the above JAAS login configuration file: +==== [source,xml] ---- - @@ -155,16 +146,19 @@ class="org.springframework.security.authentication.jaas.JaasAuthenticationProvid ---- +==== [[jaas-apiprovision]] === Running as a Subject -If configured, the `JaasApiIntegrationFilter` will attempt to run as the `Subject` on the `JaasAuthenticationToken`. +If configured, the `JaasApiIntegrationFilter` tries to run as the `Subject` on the `JaasAuthenticationToken`. This means that the `Subject` can be accessed using: +==== [source,java] ---- Subject subject = Subject.getSubject(AccessController.getContext()); ---- +==== -This integration can easily be configured using the <> attribute. +You can configure this integration by using the <> attribute. This feature is useful when integrating with legacy or external API's that rely on the JAAS Subject being populated. diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/logout.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/logout.adoc index c824ffe0adb..1b5a3f1893b 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/logout.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/logout.adoc @@ -1,16 +1,18 @@ [[jc-logout]] == Handling Logouts +This section covers how to customize the handling of logouts. + [[logout-java-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: +The default is that accessing the URL `/logout` logs the user out by: - Invalidating the HTTP Session - Cleaning up any RememberMe authentication that was configured - Clearing the `SecurityContextHolder` -- Redirect to `/login?logout` +- Redirecting to `/login?logout` Similar to configuring login capabilities, however, you also have various options to further customize your logout requirements: @@ -53,33 +55,30 @@ override fun configure(http: HttpSecurity) { <1> Provides logout support. This is automatically applied when using `WebSecurityConfigurerAdapter`. -<2> The URL that triggers log out to occur (default is `/logout`). -If CSRF protection is enabled (default), then the request must also be a POST. -For more information, please consult the {security-api-url}org/springframework/security/config/annotation/web/configurers/LogoutConfigurer.html#logoutUrl-java.lang.String-[JavaDoc]. -<3> The URL to redirect to after logout has occurred. +<2> The URL that triggers log out to occur (the default is `/logout`). +If CSRF protection is enabled (the default), the request must also be a POST. +For more information, see {security-api-url}org/springframework/security/config/annotation/web/configurers/LogoutConfigurer.html#logoutUrl-java.lang.String-[`logoutUrl(java.lang.String logoutUrl)`]. +<3> The URL to which to redirect after logout has occurred. The default is `/login?logout`. -For more information, please consult the {security-api-url}org/springframework/security/config/annotation/web/configurers/LogoutConfigurer.html#logoutSuccessUrl-java.lang.String-[JavaDoc]. +For more information, see {security-api-url}org/springframework/security/config/annotation/web/configurers/LogoutConfigurer.html#logoutSuccessUrl-java.lang.String-[`logoutSuccessUrl(java.lang.String logoutSuccessUrl)`]. <4> Let's you specify a custom `LogoutSuccessHandler`. If this is specified, `logoutSuccessUrl()` is ignored. -For more information, please consult the {security-api-url}org/springframework/security/config/annotation/web/configurers/LogoutConfigurer.html#logoutSuccessHandler-org.springframework.security.web.authentication.logout.LogoutSuccessHandler-[JavaDoc]. +For more information, see {security-api-url}org/springframework/security/config/annotation/web/configurers/LogoutConfigurer.html#logoutSuccessHandler-org.springframework.security.web.authentication.logout.LogoutSuccessHandler-[`LogoutSuccessHandler`]. <5> Specify whether to invalidate the `HttpSession` at the time of logout. This is *true* by default. Configures the `SecurityContextLogoutHandler` under the covers. -For more information, please consult the {security-api-url}org/springframework/security/config/annotation/web/configurers/LogoutConfigurer.html#invalidateHttpSession-boolean-[JavaDoc]. +For more information, see {security-api-url}org/springframework/security/config/annotation/web/configurers/LogoutConfigurer.html#invalidateHttpSession-boolean-[`invalidateHttpSession(boolean invalidateHttpSession)`]. <6> Adds a `LogoutHandler`. -`SecurityContextLogoutHandler` is added as the last `LogoutHandler` by default. -<7> Allows specifying the names of cookies to be removed on logout success. +By default, `SecurityContextLogoutHandler` is added as the last `LogoutHandler`. +<7> Lets specifying the names of cookies be removed on logout success. This is a shortcut for adding a `CookieClearingLogoutHandler` explicitly. -[NOTE] -==== -Logouts can of course also be configured using the XML Namespace notation. -Please see the documentation for the <> in the Spring Security XML Namespace section for further details. -==== +NOTE: Logouts can also be configured by using the XML Namespace notation. +See the documentation for the <> in the Spring Security XML Namespace section for further details. -Generally, in order to customize logout functionality, you can add +Generally, to customize logout functionality, you can add `{security-api-url}org/springframework/security/web/authentication/logout/LogoutHandler.html[LogoutHandler]` -and/or +or `{security-api-url}org/springframework/security/web/authentication/logout/LogoutSuccessHandler.html[LogoutSuccessHandler]` implementations. For many common scenarios, these handlers are applied under the @@ -88,8 +87,8 @@ covers when using the fluent API. [[ns-logout]] === 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. +The default logout URL is `/logout`, but you can set it to something else by setting the `logout-url` attribute. +You can find more information on other available attributes in the namespace appendix. [[jc-logout-handler]] === LogoutHandler @@ -97,9 +96,9 @@ More information on other available attributes may be found in the namespace app Generally, `{security-api-url}org/springframework/security/web/authentication/logout/LogoutHandler.html[LogoutHandler]` implementations indicate classes that are able to participate in logout handling. They are expected to be invoked to perform necessary clean-up. -As such they should +As a result, they should not throw exceptions. -Various implementations are provided: +Spring Security provides various implementations: - {security-api-url}org/springframework/security/web/authentication/rememberme/PersistentTokenBasedRememberMeServices.html[PersistentTokenBasedRememberMeServices] - {security-api-url}org/springframework/security/web/authentication/rememberme/TokenBasedRememberMeServices.html[TokenBasedRememberMeServices] @@ -108,41 +107,41 @@ Various implementations are provided: - {security-api-url}org/springframework/security/web/authentication/logout/SecurityContextLogoutHandler.html[SecurityContextLogoutHandler] - {security-api-url}org/springframework/security/web/authentication/logout/HeaderWriterLogoutHandler.html[HeaderWriterLogoutHandler] -Please see <> for details. +See <> for details. Instead of providing `LogoutHandler` implementations directly, the fluent API also provides shortcuts that provide the respective `LogoutHandler` implementations under the covers. -E.g. `deleteCookies()` allows specifying the names of one or more cookies to be removed on logout success. +For example, `deleteCookies()` lets you specify the names of one or more cookies to be removed on logout success. This is a shortcut compared to adding a `CookieClearingLogoutHandler`. [[jc-logout-success-handler]] === LogoutSuccessHandler -The `LogoutSuccessHandler` is called after a successful logout by the `LogoutFilter`, to handle e.g. +The `LogoutSuccessHandler` is called after a successful logout by the `LogoutFilter`, to handle (for example) redirection or forwarding to the appropriate destination. Note that the interface is almost the same as the `LogoutHandler` but may raise an exception. -The following implementations are provided: +Spring Security provides the following implementations: - {security-api-url}org/springframework/security/web/authentication/logout/SimpleUrlLogoutSuccessHandler.html[SimpleUrlLogoutSuccessHandler] - HttpStatusReturningLogoutSuccessHandler -As mentioned above, you don't need to specify the `SimpleUrlLogoutSuccessHandler` directly. +As mentioned earlier, you need not specify the `SimpleUrlLogoutSuccessHandler` directly. Instead, the fluent API provides a shortcut by setting the `logoutSuccessUrl()`. -This will setup the `SimpleUrlLogoutSuccessHandler` under the covers. -The provided URL will be redirected to after a logout has occurred. +This sets up the `SimpleUrlLogoutSuccessHandler` under the covers. +The provided URL is redirected to after a logout has occurred. The default is `/login?logout`. The `HttpStatusReturningLogoutSuccessHandler` can be interesting in REST API type scenarios. -Instead of redirecting to a URL upon the successful logout, this `LogoutSuccessHandler` allows you to provide a plain HTTP status code to be returned. -If not configured a status code 200 will be returned by default. +Instead of redirecting to a URL upon the successful logout, this `LogoutSuccessHandler` lets you provide a plain HTTP status code to be returned. +If not configured, a status code 200 is returned by default. [[jc-logout-references]] === Further Logout-Related References - <> - <> -- <> +- <> - <> - <> in section CSRF Caveats -- Section <> (CAS protocol) +- <> (CAS protocol) - Documentation for the <> in the Spring Security XML Namespace section diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/openid.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/openid.adoc index 01362127ffa..c615550bcff 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/openid.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/openid.adoc @@ -1,11 +1,11 @@ [[servlet-openid]] == 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. +NOTE: The OpenID 1.0 and 2.0 protocols have been deprecated. You should migrate to OpenID Connect, which is supported by `spring-security-oauth2`. -The namespace supports https://openid.net/[OpenID] login either instead of, or in addition to normal form-based login, with a simple change: +The namespace supports https://openid.net/[OpenID] login either instead of or in addition to normal form-based login, with a simple change: +==== [source,xml] ---- @@ -13,24 +13,27 @@ The namespace supports https://openid.net/[OpenID] login either instead of, or i ---- +==== You should then register yourself with an OpenID provider (such as myopenid.com), and add the user information to your in-memory ``: +==== [source,xml] ---- ---- +==== -You should be able to login using the `myopenid.com` site to authenticate. -It is also possible to select a specific `UserDetailsService` bean for use OpenID by setting the `user-service-ref` attribute on the `openid-login` element. -Note that we have omitted the password attribute from the above user configuration, since this set of user data is only being used to load the authorities for the user. -A random password will be generated internally, preventing you from accidentally using this user data as an authentication source elsewhere in your configuration. - +You should be able to login by using the `myopenid.com` site to authenticate. +You can also select a specific `UserDetailsService` bean for use with OpenID by setting the `user-service-ref` attribute on the `openid-login` element. +Note that we have omitted the password attribute from the above user configuration, since this set of user data is being used only to load the authorities for the user. +A random password is generated internally, preventing you from accidentally using this user data as an authentication source elsewhere in your configuration. === 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: +Spring Security includes support for OpenID https://openid.net/specs/openid-attribute-exchange-1_0.html[attribute exchange]. +As an example, the following configuration tries to retrieve the email and full name from the OpenID provider for use by the application: +==== [source,xml] ---- @@ -40,21 +43,24 @@ As an example, the following configuration would attempt to retrieve the email a ---- +==== -The "type" of each OpenID attribute is a URI, determined by a particular schema, in this case https://axschema.org/[https://axschema.org/]. -If an attribute must be retrieved for successful authentication, the `required` attribute can be set. -The exact schema and attributes supported will depend on your OpenID provider. -The attribute values are returned as part of the authentication process and can be accessed afterwards using the following code: +The "`type`" of each OpenID attribute is a URI, determined by a particular schema -- in this case, https://axschema.org/[https://axschema.org/]. +If an attribute must be retrieved for successful authentication, you can set the `required` attribute. +The exact schema and attributes supported depend on your OpenID provider. +The attribute values are returned as part of the authentication process and can be accessed afterwards by using the following code: +==== [source,java] ---- OpenIDAuthenticationToken token = (OpenIDAuthenticationToken)SecurityContextHolder.getContext().getAuthentication(); List attributes = token.getAttributes(); ---- +==== We can obtain the `OpenIDAuthenticationToken` from the <>. The `OpenIDAttribute` contains the attribute type and the retrieved value (or values in the case of multi-valued attributes). -You can supply multiple `attribute-exchange` elements, using an `identifier-matcher` attribute on each. -This contains a regular expression which will be matched against the OpenID identifier supplied by the user. -See the OpenID sample application in the codebase for an example configuration, providing different attribute lists for the Google, Yahoo and MyOpenID providers. +You can supply multiple `attribute-exchange` elements by using an `identifier-matcher` attribute on each element. +This contains a regular expression that is matched against the OpenID identifier supplied by the user. +See the {gh-samples-url}/boot/oauth2login[OpenID sample application] in the codebase for an example configuration, providing different attribute lists for the Google, Yahoo and MyOpenID providers. diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/preauth.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/preauth.adoc index c50de6379fb..ae6a0799129 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/preauth.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/preauth.adoc @@ -1,33 +1,29 @@ [[servlet-preauth]] == 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. -When using pre-authentication, Spring Security has to +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 runs. +When using pre-authentication, Spring Security has to: * Identify the user making the request. - * Obtain the authorities for the user. - -The details will depend on the external authentication mechanism. +The details depend on the external authentication mechanism. A user might be identified by their certificate information in the case of X.509, or by an HTTP request header in the case of Siteminder. -If relying on container authentication, the user will be identified by calling the `getUserPrincipal()` method on the incoming HTTP request. -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`. - +If relying on container authentication, the user is identified by calling the `getUserPrincipal()` method on the incoming HTTP request. +In some cases, the external mechanism may supply role and authority information for the user. However, in other cases, you must obtain the authorities from a separate source, such as a `UserDetailsService`. === 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 <>, as it already has a namespace configuration option which is simpler to use and get started with. -If you need to use explicit bean configuration or are planning on writing your own implementation then an understanding of how the provided implementations work will be useful. -You will find classes under the `org.springframework.security.web.authentication.preauth`. -We just provide an outline here so you should consult the Javadoc and source where appropriate. - +Because most pre-authentication mechanisms follow the same pattern, Spring Security has a set of classes that provide an internal framework for implementing pre-authenticated authentication providers. +This removes duplication and lets new implementations be added in a structured fashion, without having to write everything from scratch. +You need not know about these classes if you want to use something like <>, as it already has a namespace configuration option which is simpler to use and get started with. +If you need to use explicit bean configuration or are planning on writing your own implementation, you need an understanding of how the provided implementations work. +You can find the classes under the `org.springframework.security.web.authentication.preauth`. +We provide only an outline here, so you should consult the Javadoc and source where appropriate. ==== 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: +This class checks the current contents of the security context and, if it is empty, tries to extract user information from the HTTP request and submit it to the `AuthenticationManager`. +Subclasses override the following methods to obtain this information. .Override AbstractPreAuthenticatedProcessingFilter ==== @@ -49,24 +45,24 @@ protected abstract fun getPreAuthenticatedCredentials(request: HttpServletReques ==== -After calling these, the filter will create a `PreAuthenticatedAuthenticationToken` containing the returned data and submit it for authentication. -By "authentication" here, we really just mean further processing to perhaps load the user's authorities, but the standard Spring Security authentication architecture is followed. +After calling these, the filter creates a `PreAuthenticatedAuthenticationToken` that contains the returned data and submits it for authentication. +By "`authentication`" here, we really just mean further processing to perhaps load the user's authorities, but the standard Spring Security authentication architecture is followed. -Like other Spring Security authentication filters, the pre-authentication filter has an `authenticationDetailsSource` property which by default will create a `WebAuthenticationDetails` object to store additional information such as the session-identifier and originating IP address in the `details` property of the `Authentication` object. +As other Spring Security authentication filters, the pre-authentication filter has an `authenticationDetailsSource` property, which, by default, creates a `WebAuthenticationDetails` object to store additional information, such as the session identifier and the originating IP address in the `details` property of the `Authentication` object. In cases where user role information can be obtained from the pre-authentication mechanism, the data is also stored in this property, with the details implementing the `GrantedAuthoritiesContainer` interface. This enables the authentication provider to read the authorities which were externally allocated to the user. -We'll look at a concrete example next. +We look at a concrete example next. [[j2ee-preauth-details]] ===== 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". +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 `` information in a `web.xml` file. The pre-authentication sample application uses the latter approach. -There is an additional stage where the roles (or attributes) are mapped to Spring Security `GrantedAuthority` objects using a configured `Attributes2GrantedAuthoritiesMapper`. -The default will just add the usual `ROLE_` prefix to the names, but it gives you full control over the behaviour. +There is an additional stage where the roles (or attributes) are mapped to Spring Security `GrantedAuthority` objects by using a configured `Attributes2GrantedAuthoritiesMapper`. +The default just adds the usual `ROLE_` prefix to the names, but it gives you full control over the behavior. ==== PreAuthenticatedAuthenticationProvider @@ -74,45 +70,43 @@ The pre-authenticated provider has little more to do than load the `UserDetails` 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: +==== [source,java] ---- public interface AuthenticationUserDetailsService { UserDetails loadUserDetails(Authentication token) throws UsernameNotFoundException; } ---- +==== -This interface may have also other uses but with pre-authentication it allows access to the authorities which were packaged in the `Authentication` object, as we saw in the previous section. +This interface may also have other uses, but, with pre-authentication, it allows access to the authorities that were packaged in the `Authentication` object, as we saw in the previous section. The `PreAuthenticatedGrantedAuthoritiesUserDetailsService` class does this. -Alternatively, it may delegate to a standard `UserDetailsService` via the `UserDetailsByNameServiceWrapper` implementation. +Alternatively, it may delegate to a standard `UserDetailsService` through the `UserDetailsByNameServiceWrapper` implementation. ==== Http403ForbiddenEntryPoint -The <> 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. +The <> is responsible for kick-starting the authentication process for an unauthenticated user (when they try to access a protected resource). However, in the pre-authenticated case, this does not apply. +You would only configure the `ExceptionTranslationFilter` with an instance of this class if you do not use pre-authentication in combination with other authentication mechanisms. +It is 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 X.509 authentication is covered in its <>. -Here we'll look at some classes which provide support for other pre-authenticated scenarios. - +Here, we look at some classes which provide support for other pre-authenticated scenarios. ==== 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. -It defaults to using the name `SM_USER` as the header name. +This mechanism is supported by the `RequestHeaderAuthenticationFilter` class, which only extracts the username from the header. +It defaults to using a name of `SM_USER` as the header name. See the Javadoc for more details. -[TIP] -==== -Note that when using a system like this, the framework performs no authentication checks at all and it is __extremely__ important that the external system is configured properly and protects all access to the application. -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. -==== +TIP: When using a system like this, the framework performs no authentication checks at all, and it is _extremely_ important that the external system is configured properly and protects all access to the application. +If an attacker is able to forge the headers in their original request without this being detected, they could potentially choose any username they wished. ===== Siteminder Example Configuration -A typical configuration using this filter would look like this: +The following example shows a typical configuration that uses this filter: +==== [source,xml] ---- @@ -138,14 +132,14 @@ A typical configuration using this filter would look like this: ---- +==== -We've assumed here that the <> is being used for configuration. -It's also assumed that you have added a `UserDetailsService` (called "userDetailsService") to your configuration to load the user's roles. - +We have assumed here that the <> is being used for configuration. +It is also assumed that you have added a `UserDetailsService` (called `userDetailsService`) to your configuration to load the user's roles. ==== 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 <>. +The `J2eePreAuthenticatedProcessingFilter` class extracts 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 earlier in <>. -There is a sample application in the codebase which uses this approach, so get hold of the code from github and have a look at the application context file if you are interested. +There is a sample application that uses this approach in the codebase, so get hold of the code from Github and have a look at the application context file if you are interested. The code is in the `samples/xml/preauth` directory. diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/rememberme.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/rememberme.adoc index 25f6fd791d4..541d86535f7 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/rememberme.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/rememberme.adoc @@ -1,23 +1,22 @@ [[servlet-rememberme]] == Remember-Me Authentication - [[remember-me-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. +Spring Security provides the necessary hooks for these operations to take place and has two concrete remember-me implementations. One uses hashing to preserve the security of cookie-based tokens and the other uses a database or other persistent storage mechanism to store the generated tokens. Note that both implementations require a `UserDetailsService`. -If you are using an authentication provider which doesn't use a `UserDetailsService` (for example, the LDAP provider) then it won't work unless you also have a `UserDetailsService` bean in your application context. +If you use an authentication provider that does not use a `UserDetailsService` (for example, the LDAP provider), it does not work unless you also have a `UserDetailsService` bean in your application context. [[remember-me-hash-token]] === 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: +In essence, a cookie is sent to the browser upon successful interactive authentication, with the cookie being composed as follows: +==== [source,txt] ---- base64(username + ":" + expirationTime + ":" + @@ -28,16 +27,18 @@ password: That matches the one in the retrieved UserDetails expirationTime: The date and time when the remember-me token expires, expressed in milliseconds key: A private key to prevent modification of the remember-me token ---- +==== -As such the remember-me token is valid only for the period specified, and provided that the username, password and key does not change. -Notably, this has a potential security issue in that a captured remember-me token will be usable from any user agent until such time as the token expires. -This is the same issue as with digest authentication. -If a principal is aware a token has been captured, they can easily change their password and immediately invalidate all remember-me tokens on issue. -If more significant security is needed you should use the approach described in the next section. -Alternatively remember-me services should simply not be used at all. +The remember-me token is valid only for the period specified and only if the username, password, and key do not change. +Notably, this has a potential security issue, in that a captured remember-me token is usable from any user agent until such time as the token expires. +This is the same issue as with <>. +If a principal is aware that a token has been captured, they can easily change their password and immediately invalidate all remember-me tokens on issue. +If more significant security is needed, you should use the approach described in the next section. +Alternatively, remember-me services should not be used at all. -If you are familiar with the topics discussed in the chapter on <>, you can enable remember-me authentication just by adding the `` element: +If you are familiar with the topics discussed in the chapter on <>, you can enable remember-me authentication by adding the `` element: +==== [source,xml] ---- @@ -45,16 +46,18 @@ If you are familiar with the topics discussed in the chapter on < ---- +==== -The `UserDetailsService` will normally be selected automatically. +The `UserDetailsService` is normally 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 -This approach is based on the article 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: +This approach is based on the article titled http://jaspan.com/improved_persistent_login_cookie_best_practice[http://jaspan.com/improved_persistent_login_cookie_best_practice], with some minor modifications. (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, supply a datasource reference: +==== [source,xml] ---- @@ -62,9 +65,11 @@ To use the this approach with namespace configuration, you would supply a dataso ---- +==== -The database should contain a `persistent_logins` table, created using the following SQL (or equivalent): +The database should contain a `persistent_logins` table, created by using the following SQL (or equivalent): +==== [source,ddl] ---- create table persistent_logins (username varchar(64) not null, @@ -72,14 +77,16 @@ create table persistent_logins (username varchar(64) not null, token varchar(64) not null, last_used timestamp not null) ---- +==== [[remember-me-impls]] === Remember-Me Interfaces and Implementations -Remember-me is used with `UsernamePasswordAuthenticationFilter`, and is implemented via hooks in the `AbstractAuthenticationProcessingFilter` superclass. +Remember-me is used with `UsernamePasswordAuthenticationFilter` and is implemented through hooks in the `AbstractAuthenticationProcessingFilter` superclass. It is also used within `BasicAuthenticationFilter`. -The hooks will invoke a concrete `RememberMeServices` at the appropriate times. -The interface looks like this: +The hooks invoke a concrete `RememberMeServices` at the appropriate times. +The following listing shows the interface: +==== [source,java] ---- Authentication autoLogin(HttpServletRequest request, HttpServletResponse response); @@ -89,24 +96,27 @@ void loginFail(HttpServletRequest request, HttpServletResponse response); void loginSuccess(HttpServletRequest request, HttpServletResponse response, Authentication successfulAuthentication); ---- +==== -Please refer to the Javadoc for a fuller discussion on what the methods do, although note at this stage that `AbstractAuthenticationProcessingFilter` only calls the `loginFail()` and `loginSuccess()` methods. +See the Javadoc for {security-api-url}org/springframework/security/web/authentication/RememberMeServices.html[`RememberMeServices`] for a fuller discussion on what the methods do, although note that, at this stage, `AbstractAuthenticationProcessingFilter` calls only the `loginFail()` and `loginSuccess()` methods. The `autoLogin()` method is called by `RememberMeAuthenticationFilter` whenever the `SecurityContextHolder` does not contain an `Authentication`. -This interface therefore provides the underlying remember-me implementation with sufficient notification of authentication-related events, and delegates to the implementation whenever a candidate web request might contain a cookie and wish to be remembered. +This interface, therefore, provides the underlying remember-me implementation with sufficient notification of authentication-related events and delegates to the implementation whenever a candidate web request might contain a cookie and wish to be remembered. 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. + +We have seen earlier that Spring Security provides two implementations. +We look at each of these in turn. ==== TokenBasedRememberMeServices This implementation supports the simpler approach described in <>. `TokenBasedRememberMeServices` generates a `RememberMeAuthenticationToken`, which is processed by `RememberMeAuthenticationProvider`. A `key` is shared between this authentication provider and the `TokenBasedRememberMeServices`. -In addition, `TokenBasedRememberMeServices` requires A UserDetailsService from which it can retrieve the username and password for signature comparison purposes, and generate the `RememberMeAuthenticationToken` to contain the correct `GrantedAuthority` s. +In addition, `TokenBasedRememberMeServices` requires a `UserDetailsService`, from which it can retrieve the username and password for signature comparison purposes and generate the `RememberMeAuthenticationToken` to contain the correct `GrantedAuthority` instances. Some sort of logout command should be provided by the application that invalidates the cookie if the user requests this. -`TokenBasedRememberMeServices` also implements Spring Security's `LogoutHandler` interface so can be used with `LogoutFilter` to have the cookie cleared automatically. +`TokenBasedRememberMeServices` also implements Spring Security's `LogoutHandler` interface so that it can be used with `LogoutFilter` to have the cookie cleared automatically. -The beans required in an application context to enable remember-me services are as follows: +The following beans are required in an application context to enable remember-me services: +==== [source,xml] ---- ---- +==== -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`). +Remember 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 -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. +You can use this class 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. -* `InMemoryTokenRepositoryImpl` which is intended for testing only. -* `JdbcTokenRepositoryImpl` which stores the tokens in a database. +* `InMemoryTokenRepositoryImpl`, which is intended for testing only. +* `JdbcTokenRepositoryImpl`, which stores the tokens in a database. -The database schema is described above in <>. +See <> for the database schema. diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/runas.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/runas.adoc index 8eb5de89ec5..4cc14957828 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/runas.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/runas.adoc @@ -2,19 +2,19 @@ == Run-As Authentication Replacement [[runas-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`. +The `RunAsManager` indicates the replacement `Authentication` object, if any, that should be used during the `SecurityInterceptorCallback`. -By temporarily replacing the `Authentication` object during the secure object callback phase, the secured invocation will be able to call other objects which require different authentication and authorization credentials. -It will also be able to perform any internal security checks for specific `GrantedAuthority` objects. +By temporarily replacing the `Authentication` object during the secure object callback phase, the secured invocation can call other objects that require different authentication and authorization credentials. +It can also perform any internal security checks for specific `GrantedAuthority` objects. 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 -A `RunAsManager` interface is provided by Spring Security: +Spring Security provices a `RunAsManager` interface: +==== [source,java] ---- Authentication buildRunAs(Authentication authentication, Object object, @@ -24,31 +24,30 @@ boolean supports(ConfigAttribute attribute); boolean supports(Class clazz); ---- - - +==== The first method returns the `Authentication` object that should replace the existing `Authentication` object for the duration of the method invocation. If the method returns `null`, it indicates no replacement should be made. The second method is used by the `AbstractSecurityInterceptor` as part of its startup validation of configuration attributes. -The `supports(Class)` method is called by a security interceptor implementation to ensure the configured `RunAsManager` supports the type of secure object that the security interceptor will present. +The `supports(Class)` method is called by a security interceptor implementation to ensure that the configured `RunAsManager` supports the type of secure object that the security interceptor presents. -One concrete implementation of a `RunAsManager` is provided with Spring Security. +Spring Security provides one concrete implementation of `RunAsManager`. The `RunAsManagerImpl` class returns a replacement `RunAsUserToken` if any `ConfigAttribute` starts with `RUN_AS_`. -If any such `ConfigAttribute` is found, the replacement `RunAsUserToken` will contain the same principal, credentials and granted authorities as the original `Authentication` object, along with a new `SimpleGrantedAuthority` for each `RUN_AS_` `ConfigAttribute`. -Each new `SimpleGrantedAuthority` will be prefixed with `ROLE_`, followed by the `RUN_AS` `ConfigAttribute`. -For example, a `RUN_AS_SERVER` will result in the replacement `RunAsUserToken` containing a `ROLE_RUN_AS_SERVER` granted authority. +If any such `ConfigAttribute` is found, the replacement `RunAsUserToken` contains the same principal, credentials, and granted authorities as the original `Authentication` object, along with a new `SimpleGrantedAuthority` for each `RUN_AS_` `ConfigAttribute`. +Each new `SimpleGrantedAuthority` is prefixed with `ROLE_`, followed by the `RUN_AS` `ConfigAttribute`. +For example, a `RUN_AS_SERVER` results in the replacement `RunAsUserToken` containing a `ROLE_RUN_AS_SERVER` granted authority. -The replacement `RunAsUserToken` is just like any other `Authentication` object. -It needs to be authenticated by the `AuthenticationManager`, probably via delegation to a suitable `AuthenticationProvider`. +The replacement `RunAsUserToken` is like any other `Authentication` object. +It needs to be authenticated by the `AuthenticationManager`, probably through delegation to a suitable `AuthenticationProvider`. The `RunAsImplAuthenticationProvider` performs such authentication. -It simply accepts as valid any `RunAsUserToken` presented. +It accepts as valid any `RunAsUserToken` presented. To ensure malicious code does not create a `RunAsUserToken` and present it for guaranteed acceptance by the `RunAsImplAuthenticationProvider`, the hash of a key is stored in all generated tokens. The `RunAsManagerImpl` and `RunAsImplAuthenticationProvider` is created in the bean context with the same key: +==== [source,xml] ---- - @@ -59,8 +58,7 @@ The `RunAsManagerImpl` and `RunAsImplAuthenticationProvider` is created in the b ---- +==== - - -By using the same key, each `RunAsUserToken` can be validated it was created by an approved `RunAsManagerImpl`. -The `RunAsUserToken` is immutable after creation for security reasons +By using the same key, each `RunAsUserToken` can be validated because it was created by an approved `RunAsManagerImpl`. +The `RunAsUserToken` is immutable after creation, for security reasons. diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/session-management.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/session-management.adoc index 2250445a736..0916bd138f1 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/session-management.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/session-management.adoc @@ -1,12 +1,13 @@ [[session-mgmt]] == 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. +HTTP session-related functionality is handled by a combination of the {security-api-url}org/springframework/security/authentication/AuthenticationProvider.html[`SessionManagementFilter`] and the {security-api-url}org/springframework/security/web/authentication/session/SessionAuthenticationStrategy.html[`SessionAuthenticationStrategy`] interface, to which the filter delegates. +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 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: +To do so, configure the `session-management` element: +==== [source,xml] ---- @@ -14,25 +15,29 @@ This is achieved through the `session-management` element: ---- +==== -Note that if you use this mechanism to detect session timeouts, it may falsely report an error if the user logs out and then logs back in without closing the browser. -This is because the session cookie is not cleared when you invalidate the session and will be resubmitted even if the user has logged out. -You may be able to explicitly delete the JSESSIONID cookie on logging out, for example by using the following syntax in the logout handler: +Note that, if you use this mechanism to detect session timeouts, it may falsely report an error if the user logs out and then logs back in without closing the browser. +This is because the session cookie is not cleared when you invalidate the session and is resubmitted even if the user has logged out. +You may be able to explicitly delete the `JSESSIONID` cookie on logging out -- for example, by using the following syntax in the logout handler: +==== [source,xml] ---- ---- +==== -Unfortunately this can't be guaranteed to work with every servlet container, so you will need to test it in your environment +Unfortunately, this cannot be guaranteed to work with every servlet container, so you need to test it in your environment. [NOTE] -==== -If you are running your application behind a proxy, you may also be able to remove the session cookie by configuring the proxy server. -For example, using Apache HTTPD's mod_headers, the following directive would delete the `JSESSIONID` cookie by expiring it in the response to a logout request (assuming the application is deployed under the path `/tutorial`): +===== +If you run your application behind a proxy, you may also be able to remove the session cookie by configuring the proxy server. +For example, by using Apache HTTPD's `mod_headers`, the following directive deletes the `JSESSIONID` cookie by expiring it in the response to a logout request (assuming the application is deployed under the `/tutorial` path): +==== [source,xml] ---- @@ -40,13 +45,15 @@ Header always set Set-Cookie "JSESSIONID=;Path=/tutorial;Expires=Thu, 01 Jan 197 ---- ==== +===== [[ns-concurrent-sessions]] === 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 `web.xml` file to keep Spring Security updated about session lifecycle events: +If you wish to place constraints on a single user's ability to log in to your application, Spring Security supports this with the following simple additions. +First, you need to add the following listener to your `web.xml` file to keep Spring Security updated about session lifecycle events: +==== [source,xml] ---- @@ -55,9 +62,11 @@ First you need to add the following listener to your `web.xml` file to keep Spri ---- +==== Then add the following lines to your application context: +==== [source,xml] ---- @@ -67,10 +76,12 @@ Then add the following lines to your application context: ---- +==== -This will prevent a user from logging in multiple times - a second login will cause the first to be invalidated. -Often you would prefer to prevent a second login, in which case you can use +These changes prevent a user from logging in multiple times. A second login causes the first to be invalidated. +Often, you would prefer to prevent a second login. In that case, you can use: +==== [source,xml] ---- @@ -80,61 +91,61 @@ Often you would prefer to prevent a second login, in which case you can use ---- +==== -The second login will then be rejected. -By "rejected", we mean that the user will be sent to the `authentication-failure-url` if form-based login is being used. -If the second authentication takes place through another non-interactive mechanism, such as "remember-me", an "unauthorized" (401) error will be sent to the client. -If instead you want to use an error page, you can add the attribute `session-authentication-error-url` to the `session-management` element. +The second login is then rejected. +By "`rejected`", we mean that the user is sent to the `authentication-failure-url` if form-based login is being used. +If the second authentication takes place through another non-interactive mechanism, such as "`remember-me`", an "`unauthorized`" (401) error is sent to the client. +If, instead, you want to use an error page, you can add the `session-authentication-error-url` attribute to the `session-management` element. -If you are using a customized authentication filter for form-based login, then you have to configure concurrent session control support explicitly. -More details can be found in the <>. +If you use a customized authentication filter for form-based login, you have to configure concurrent session control support explicitly. +You can find more details in the <>. [[ns-session-fixation]] === 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 ``, which has four options +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 and 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 automatically protects against this by creating a new session or otherwise changing the session ID when a user logs in. +If you do not require this protection or it conflicts with some other requirement, you can control the behavior setting the `session-fixation-protection` attribute on ``, which has four options -* `none` - Don't do anything. -The original session will be retained. +* `none`: Do nothing. +The original session is retained. -* `newSession` - Create a new "clean" session, without copying the existing session data (Spring Security-related attributes will still be copied). +* `newSession`: Create a new, "`clean`" session, without copying the existing session data (Spring Security-related attributes are still copied). -* `migrateSession` - Create a new session and copy all existing session attributes to the new session. +* `migrateSession`: Create a new session and copy all existing session attributes to the new session. This is the default in Servlet 3.0 or older containers. -* `changeSessionId` - Do not create a new session. +* `changeSessionId`: Do not create a new session. Instead, use the session fixation protection provided by the Servlet container (`HttpServletRequest#changeSessionId()`). -This option is only available in Servlet 3.1 (Java EE 7) and newer containers. -Specifying it in older containers will result in an exception. -This is the default in Servlet 3.1 and newer containers. - +This option is available only in Servlet 3.1 (Java EE 7) and newer containers, where it is the default. +Specifying it in older containers results in an exception. When session fixation protection occurs, it results in a `SessionFixationProtectionEvent` being published in the application context. -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. +If you use `changeSessionId`, this protection will _also_ result in any `javax.servlet.http.HttpSessionIdListener` instances being notified, so use caution if your code listens for both events. See the <> chapter for additional information. === 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. +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 + +NOTE: Authentication by mechanisms that perform a redirect after authenticating (such as form-login) are not detected by `SessionManagementFilter`, as the filter is not invoked during the authenticating request. Session-management functionality has to be handled separately in these cases. -]. + If the repository contains a security context, the filter does nothing. -If it doesn't, and the thread-local `SecurityContext` contains a (non-anonymous) `Authentication` object, the filter assumes they have been authenticated by a previous filter in the stack. -It will then invoke the configured `SessionAuthenticationStrategy`. +If it does not and the thread-local `SecurityContext` contains a (non-anonymous) `Authentication` object, the filter assumes they have been authenticated by a previous filter in the stack. +It then invokes the configured `SessionAuthenticationStrategy`. -If the user is not currently authenticated, the filter will check whether an invalid session ID has been requested (because of a timeout, for example) and will invoke the configured `InvalidSessionStrategy`, if one is set. -The most common behaviour is just to redirect to a fixed URL and this is encapsulated in the standard implementation `SimpleRedirectInvalidSessionStrategy`. -The latter is also used when configuring an invalid session URL through the namespace,<>. +If the user is not currently authenticated, the filter checks whether an invalid session ID has been requested (because of a timeout, for example) and invokes the configured `InvalidSessionStrategy`, if one is set. +The most common behavior is to redirect to a fixed URL, and this is encapsulated in the standard implementation (`SimpleRedirectInvalidSessionStrategy`). +The latter is also used when configuring an invalid session URL through the namespace, <>. === 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: +`SessionAuthenticationStrategy` is used by both `SessionManagementFilter` and `AbstractAuthenticationProcessingFilter`, so, if you are using a customized form-login class, for example, you need to inject it into both of these. +In this case, a typical configuration that combines the namespace and custom beans might look like this: +==== [source,xml] ---- - @@ -148,56 +159,53 @@ In this case, a typical configuration, combining the namespace and custom beans - ---- +==== -Note that the use of the default, `SessionFixationProtectionStrategy` may cause issues if you are storing beans in the session which implement `HttpSessionBindingListener`, including Spring session-scoped beans. -See the Javadoc for this class for more information. +Note that the use of the default, `SessionFixationProtectionStrategy`, may cause issues if you are storing beans in the session that implement `HttpSessionBindingListener`, including Spring session-scoped beans. +See the Javadoc for this Java class for more information. [[concurrent-sessions]] === 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. +Spring Security can 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, while 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. You can either expire their previous login or you can report an error when they try to log in again, preventing the second login. -Note that if you are using the second approach, a user who has not explicitly logged out (but who has just closed their browser, for example) will not be able to log in again until their original session expires. +Note that, if you use the second approach, a user who has not explicitly logged out (but who has just closed their browser, for example) cannot log in again until their original session expires. +//FIXME: Add a link to the namespace chapter. Concurrency control is supported by the namespace, so please check the earlier namespace chapter for the simplest configuration. -Sometimes you need to customize things though. +Sometimes, though, you need to customize things. The implementation uses a specialized version of `SessionAuthenticationStrategy`, called `ConcurrentSessionControlAuthenticationStrategy`. -[NOTE] -==== -Previously the concurrent authentication check was made by the `ProviderManager`, which could be injected with a `ConcurrentSessionController`. +NOTE: Previously, the concurrent authentication check was made by the `ProviderManager`, which could be injected with a `ConcurrentSessionController`. The latter would check if the user was attempting to exceed the number of permitted sessions. However, this approach required that an HTTP session be created in advance, which is undesirable. -In Spring Security 3, the user is first authenticated by the `AuthenticationManager` and once they are successfully authenticated, a session is created and the check is made whether they are allowed to have another session open. - -==== +In Spring Security 3 and later, the user is first authenticated by the `AuthenticationManager` and once they are successfully authenticated, a session is created and the check is made whether they are allowed to have another session open. +To use concurrent session support, you need to add the following to `web.xml`: -To use concurrent session support, you'll need to add the following to `web.xml`: - +==== [source,xml] ---- - org.springframework.security.web.session.HttpSessionEventPublisher ---- +==== +In addition, you need to add the `ConcurrentSessionFilter` to your `FilterChainProxy`. +The `ConcurrentSessionFilter` requires two constructor arguments: +* `sessionRegistry`, which generally points to an instance of `SessionRegistryImpl` +* `sessionInformationExpiredStrategy`, which defines the strategy to apply when a session has expired +The following sample configuration uses the namespace to create the `FilterChainProxy` and other default beans: - -In addition, you will need to add the `ConcurrentSessionFilter` to your `FilterChainProxy`. -The `ConcurrentSessionFilter` requires two constructor arguments, `sessionRegistry`, which generally points to an instance of `SessionRegistryImpl`, and `sessionInformationExpiredStrategy`, which defines the strategy to apply when a session has expired. -A configuration using the namespace to create the `FilterChainProxy` and other default beans might look like this: - +==== [source,xml] ---- - @@ -241,25 +249,22 @@ class="org.springframework.security.web.session.ConcurrentSessionFilter"> - ---- - - +==== Adding the listener to `web.xml` causes an `ApplicationEvent` to be published to the Spring `ApplicationContext` every time a `HttpSession` commences or ends. -This is critical, as it allows the `SessionRegistryImpl` to be notified when a session ends. -Without it, a user will never be able to log back in again once they have exceeded their session allowance, even if they log out of another session or it times out. - +This is critical, as it lets the `SessionRegistryImpl` be notified when a session ends. +Without it, a user can never log back in again once they have exceeded their session allowance, even if they log out of another session or it times out. [[list-authenticated-principals]] ==== 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. +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` that you can use directly within your application. So, even if you do not 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 use the namespace, you can set an alias for the internally-created `SessionRegistry` by using the `session-registry-alias` attribute, providing a reference that you can inject into your own beans. The `getAllPrincipals()` method supplies you with a list of the currently authenticated users. You can list a user's sessions by calling the `getAllSessions(Object principal, boolean includeExpiredSessions)` method, which returns a list of `SessionInformation` objects. You can also expire a user's session by calling `expireNow()` on a `SessionInformation` instance. -When the user returns to the application, they will be prevented from proceeding. +When the user returns to the application, they are prevented from proceeding. You may find these methods useful in an administration application, for example. -Have a look at the Javadoc for more information. +See the Javadoc for more information about the {security-api-url}org/springframework/security/core/session/SessionRegistry.html[`SessionRegistry`] interface. diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/basic.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/basic.adoc index aa2ff02f297..02a746d3b47 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/basic.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/basic.adoc @@ -1,60 +1,61 @@ [[servlet-authentication-basic]] = Basic Authentication -This section provides details on how Spring Security provides support for https://tools.ietf.org/html/rfc7617[Basic HTTP Authentication] for servlet based applications. +This section provides details on how Spring Security provides support for https://tools.ietf.org/html/rfc7617[Basic HTTP Authentication] for servlet-based applications. // FIXME: describe authenticationentrypoint, authenticationfailurehandler, authenticationsuccesshandler -Let's take a look at how HTTP Basic Authentication works within Spring Security. -First, we see the https://tools.ietf.org/html/rfc7235#section-4.1[WWW-Authenticate] header is sent back to an unauthenticated client. +This section describes how HTTP Basic Authentication works within Spring Security. +First, we see the https://tools.ietf.org/html/rfc7235#section-4.1[WWW-Authenticate] header is sent back to an unauthenticated client: .Sending WWW-Authenticate Header image::{figures}/basicauthenticationentrypoint.png[] -The figure builds off our <> diagram. +The preceding figure builds off our <> diagram. 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 <> indicates that the unauthenticated request is __Denied__ by throwing an `AccessDeniedException`. image:{icondir}/number_3.png[] Since the user is not authenticated, <> initiates __Start Authentication__. -The configured <> is an instance of {security-api-url}org/springframework/security/web/authentication/www/BasicAuthenticationEntryPoint.html[`BasicAuthenticationEntryPoint`] which sends a WWW-Authenticate header. +The configured <> is an instance of {security-api-url}org/springframework/security/web/authentication/www/BasicAuthenticationEntryPoint.html[`BasicAuthenticationEntryPoint`], which sends a WWW-Authenticate header. The `RequestCache` is typically a `NullRequestCache` that does not save the request since the client is capable of replaying the requests it originally requested. -When a client receives the WWW-Authenticate header it knows it should retry with a username and password. -Below is the flow for the username and password being processed. +When a client receives the `WWW-Authenticate` header, it knows it should retry with a username and password. +The following image shows the flow for the username and password being processed: [[servlet-authentication-basicauthenticationfilter]] .Authenticating Username and Password image::{figures}/basicauthenticationfilter.png[] -The figure builds off our <> diagram. +The preceding figure builds off our <> diagram. - -image:{icondir}/number_1.png[] When the user submits their username and password, the `BasicAuthenticationFilter` creates a `UsernamePasswordAuthenticationToken` which is a type of <> by extracting the username and password from the `HttpServletRequest`. +image:{icondir}/number_1.png[] When the user submits their username and password, the `BasicAuthenticationFilter` creates a `UsernamePasswordAuthenticationToken`, which is a type of <> by extracting the username and password from the `HttpServletRequest`. image:{icondir}/number_2.png[] Next, the `UsernamePasswordAuthenticationToken` is passed into the `AuthenticationManager` to be authenticated. The details of what `AuthenticationManager` look like depend on how the <>. -image:{icondir}/number_3.png[] If authentication fails, then __Failure__ +image:{icondir}/number_3.png[] If authentication fails, then __Failure__. -* The <> is cleared out. -* `RememberMeServices.loginFail` is invoked. +. The <> is cleared out. +. `RememberMeServices.loginFail` is invoked. If remember me is not configured, this is a no-op. -// FIXME: link to rememberme -* `AuthenticationEntryPoint` is invoked to trigger the WWW-Authenticate to be sent again. +See the {security-api-url}org/springframework/security/web/authentication/RememberMeServices.html[`RememberMeServices`] interface in the Javadoc. +. `AuthenticationEntryPoint` is invoked to trigger the WWW-Authenticate to be sent again. +See the {security-api-url}org/springframework/security/web/AuthenticationEntryPoint.html[`AuthenticationEntryPoint`] interface in the Javadoc. image:{icondir}/number_4.png[] If authentication is successful, then __Success__. -* The <> is set on the <>. -* `RememberMeServices.loginSuccess` is invoked. +. The <> is set on the <>. +. `RememberMeServices.loginSuccess` is invoked. If remember me is not configured, this is a no-op. -// FIXME: link to rememberme -* The `BasicAuthenticationFilter` invokes `FilterChain.doFilter(request,response)` to continue with the rest of the application logic. +See the {security-api-url}org/springframework/security/web/authentication/RememberMeServices.html[`RememberMeServices`] interface in the Javadoc. +. The `BasicAuthenticationFilter` invokes `FilterChain.doFilter(request,response)` to continue with the rest of the application logic. +See the {security-api-url}org/springframework/security/web/authentication/www/BasicAuthenticationFilter.html[`BasicAuthenticationFilter`] Class in the Javadoc -Spring Security's HTTP Basic Authentication support in is enabled by default. +By default, Spring Security's HTTP Basic Authentication support is enabled. However, as soon as any servlet based configuration is provided, HTTP Basic must be explicitly provided. -A minimal, explicit configuration can be found below: +The following example shows a minimal, explicit configuration: .Explicit HTTP Basic Configuration ==== diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/dao-authentication-provider.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/dao-authentication-provider.adoc index 3818a019aca..3daf2cb6acf 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/dao-authentication-provider.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/dao-authentication-provider.adoc @@ -1,21 +1,21 @@ [[servlet-authentication-daoauthenticationprovider]] = DaoAuthenticationProvider -{security-api-url}org/springframework/security/authentication/dao/DaoAuthenticationProvider.html[`DaoAuthenticationProvider`] is an <> implementation that leverages a <> and <> to authenticate a username and password. +{security-api-url}org/springframework/security/authentication/dao/DaoAuthenticationProvider.html[`DaoAuthenticationProvider`] is an <> implementation that uses a <> and <> to authenticate a username and password. -Let's take a look at how `DaoAuthenticationProvider` works within Spring Security. -The figure explains details of how the <> in figures from <> works. +This section examines how `DaoAuthenticationProvider` works within Spring Security. +The following figure explains the workings of the <> in figures from the <> section. .`DaoAuthenticationProvider` Usage image::{figures}/daoauthenticationprovider.png[] -image:{icondir}/number_1.png[] The authentication `Filter` from <> passes a `UsernamePasswordAuthenticationToken` to the `AuthenticationManager` which is implemented by <>. +image:{icondir}/number_1.png[] The authentication `Filter` from the <> section passes a `UsernamePasswordAuthenticationToken` to the `AuthenticationManager`, which is implemented by <>. image:{icondir}/number_2.png[] The `ProviderManager` is configured to use an <> of type `DaoAuthenticationProvider`. image:{icondir}/number_3.png[] `DaoAuthenticationProvider` looks up the `UserDetails` from the `UserDetailsService`. -image:{icondir}/number_4.png[] `DaoAuthenticationProvider` then uses the <> to validate the password on the `UserDetails` returned in the previous step. +image:{icondir}/number_4.png[] `DaoAuthenticationProvider` uses the <> to validate the password on the `UserDetails` returned in the previous step. image:{icondir}/number_5.png[] When authentication is successful, the <> that is returned is of type `UsernamePasswordAuthenticationToken` and has a principal that is the `UserDetails` returned by the configured `UserDetailsService`. -Ultimately, the returned `UsernamePasswordAuthenticationToken` will be set on the <> by the authentication `Filter`. +Ultimately, the returned `UsernamePasswordAuthenticationToken` is set on the <> by the authentication `Filter`. diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/digest.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/digest.adoc index 603db7d93d3..565503a29fb 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/digest.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/digest.adoc @@ -1,26 +1,23 @@ [[servlet-authentication-digest]] = Digest Authentication -This section provides details on how Spring Security provides support for https://tools.ietf.org/html/rfc2617[Digest Authentication] which is provided `DigestAuthenticationFilter`. +This section provides details on how Spring Security provides support for https://tools.ietf.org/html/rfc2617[Digest Authentication], which is provided `DigestAuthenticationFilter`. -[WARNING] -==== -You should not use Digest Authentication in modern applications because it is not considered secure. -The most obvious problem is that you must store your passwords in plaintext, encrypted, or an MD5 format. +WARNING: You should not use Digest Authentication in modern applications, because it is not considered to be secure. +The most obvious problem is that you must store your passwords in plaintext or an encrypted or MD5 format. All of these storage formats are considered insecure. -Instead, you should store credentials using a one way adaptive password hash (i.e. bCrypt, PBKDF2, SCrypt, etc) which is not supported by Digest Authentication. -==== +Instead, you should store credentials by using a one way adaptive password hash (bCrypt, PBKDF2, SCrypt, and others), which is not supported by Digest Authentication. -Digest Authentication attempts to solve many of the weaknesses of <>, specifically by ensuring credentials are never sent in clear text across the wire. +Digest Authentication tries to solve many of the weaknesses of <>, specifically by ensuring credentials are never sent in clear text across the wire. Many https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Digest#Browser_compatibility[browsers support Digest Authentication]. The standard governing HTTP Digest Authentication is defined by https://tools.ietf.org/html/rfc2617[RFC 2617], which updates an earlier version of the Digest Authentication standard prescribed by https://tools.ietf.org/html/rfc2069[RFC 2069]. Most user agents implement RFC 2617. Spring Security's Digest Authentication support is compatible with the "`auth`" quality of protection (`qop`) prescribed by RFC 2617, which also provides backward compatibility with RFC 2069. -Digest Authentication was seen as a more attractive option if you need to use unencrypted HTTP (i.e. no TLS/HTTPS) and wish to maximise security of the authentication process. +Digest Authentication was seen as a more attractive option if you need to use unencrypted HTTP (no TLS or HTTPS) and wish to maximize security of the authentication process. However, everyone should use <>. -Central to Digest Authentication is a "nonce". +Central to Digest Authentication is a "`nonce`". This is a value the server generates. Spring Security's nonce adopts the following format: @@ -34,7 +31,8 @@ key: A private key to prevent modification of the nonce token ---- ==== -You will need to ensure you <> insecure plain text <> using NoOpPasswordEncoder`. +You need to ensure that you <> insecure plain text <> by using `NoOpPasswordEncoder`. +(See the {security-api-url}org/springframework/security/crypto/password/NoOpPasswordEncoder.html[`NoOpPasswordEncoder`] class in the Javadoc.) The following provides an example of configuring Digest Authentication with Java Configuration: .Digest Authentication diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/form.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/form.adoc index 27343234e50..85f7601fcda 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/form.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/form.adoc @@ -1,71 +1,70 @@ [[servlet-authentication-form]] = Form Login -Spring Security provides support for username and password being provided through an html form. +Spring Security provides support for username and password being provided through an HTML form. This section provides details on how form based authentication works within Spring Security. // FIXME: describe authenticationentrypoint, authenticationfailurehandler, authenticationsuccesshandler -Let's take a look at how form based log in works within Spring Security. -First, we see how the user is redirected to the log in form. +This section examines how form-based login works within Spring Security. +First, we see how the user is redirected to the log in form: .Redirecting to the Log In Page image::{figures}/loginurlauthenticationentrypoint.png[] -The figure builds off our <> diagram. +The preceding figure builds off our <> diagram. -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_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 <> indicates that the unauthenticated request is __Denied__ by throwing an `AccessDeniedException`. -image:{icondir}/number_3.png[] Since the user is not authenticated, <> initiates __Start Authentication__ and sends a redirect to the log in page with the configured <>. -In most cases the `AuthenticationEntryPoint` is an instance of {security-api-url}org/springframework/security/web/authentication/LoginUrlAuthenticationEntryPoint.html[`LoginUrlAuthenticationEntryPoint`]. +image:{icondir}/number_3.png[] Since the user is not authenticated, <> initiates __Start Authentication__ and sends a redirect to the login page with the configured <>. +In most cases, the `AuthenticationEntryPoint` is an instance of {security-api-url}org/springframework/security/web/authentication/LoginUrlAuthenticationEntryPoint.html[`LoginUrlAuthenticationEntryPoint`]. -image:{icondir}/number_4.png[] The browser will then request the log in page that it was redirected to. +image:{icondir}/number_4.png[] The browser requests the login page to which it was redirected. -image:{icondir}/number_5.png[] Something within the application, must <>. +image:{icondir}/number_5.png[] Something within the application must <>. [[servlet-authentication-usernamepasswordauthenticationfilter]] When the username and password are submitted, the `UsernamePasswordAuthenticationFilter` authenticates the username and password. -The `UsernamePasswordAuthenticationFilter` extends <>, so this diagram should look pretty similar. +The `UsernamePasswordAuthenticationFilter` extends <>, so the following diagram should look pretty similar: .Authenticating Username and Password image::{figures}/usernamepasswordauthenticationfilter.png[] The figure builds off our <> diagram. +image:{icondir}/number_1.png[] When the user submits their username and password, the `UsernamePasswordAuthenticationFilter` creates a `UsernamePasswordAuthenticationToken`, which is a type of <>, by extracting the username and password from the `HttpServletRequest` instance. -image:{icondir}/number_1.png[] When the user submits their username and password, the `UsernamePasswordAuthenticationFilter` creates a `UsernamePasswordAuthenticationToken` which is a type of <> by extracting the username and password from the `HttpServletRequest`. - -image:{icondir}/number_2.png[] Next, the `UsernamePasswordAuthenticationToken` is passed into the `AuthenticationManager` to be authenticated. +image:{icondir}/number_2.png[] Next, the `UsernamePasswordAuthenticationToken` is passed into the `AuthenticationManager` instance to be authenticated. The details of what `AuthenticationManager` look like depend on how the <>. -image:{icondir}/number_3.png[] If authentication fails, then __Failure__ +image:{icondir}/number_3.png[] If authentication fails, then __Failure__. -* The <> is cleared out. -* `RememberMeServices.loginFail` is invoked. +. The <> is cleared out. +. `RememberMeServices.loginFail` is invoked. If remember me is not configured, this is a no-op. -// FIXME: link to rememberme -* `AuthenticationFailureHandler` is invoked. -// FIXME: link to AuthenticationFailureHandler +See the {security-api-url}org/springframework/security/web/authentication/RememberMeServices.html[`RememberMeServices`] interface in the Javadoc. +. `AuthenticationFailureHandler` is invoked. +See the {security-api-url}springframework/security/web/authentication/AuthenticationFailureHandler.html[`AuthenticationFailureHandler`] class in the Javadoc image:{icondir}/number_4.png[] If authentication is successful, then __Success__. -* `SessionAuthenticationStrategy` is notified of a new log in. -// FIXME: Add link to SessionAuthenticationStrategy -* The <> is set on the <>. -// FIXME: link securitycontextpersistencefilter -* `RememberMeServices.loginSuccess` is invoked. +. `SessionAuthenticationStrategy` is notified of a new log in. +See the {security-api-url}springframework/security/web/authentication/session/SessionAuthenticationStrategy.html[`SessionAuthenticationStrategy`] interface in the Javadoc. +. The <> is set on the <>. +See the {security-api-url}springframework/security/web/context/SecurityContextPersistenceFilter.html[`SecurityContextPersistenceFilter`] class in the Javadoc. +. `RememberMeServices.loginSuccess` is invoked. If remember me is not configured, this is a no-op. -// FIXME: link to rememberme -* `ApplicationEventPublisher` publishes an `InteractiveAuthenticationSuccessEvent`. -* The `AuthenticationSuccessHandler` is invoked. Typically this is a `SimpleUrlAuthenticationSuccessHandler` which will redirect to a request saved by <> when we redirect to the log in page. +See the {security-api-url}springframework/security/web/authentication/RememberMeServices.html[`RememberMeServices`] interface in the Javadoc. +. `ApplicationEventPublisher` publishes an `InteractiveAuthenticationSuccessEvent`. +. The `AuthenticationSuccessHandler` is invoked. Typically, this is a `SimpleUrlAuthenticationSuccessHandler`, which redirects to a request saved by <> when we redirect to the login page. [[servlet-authentication-form-min]] -Spring Security form log in is enabled by default. -However, as soon as any servlet based configuration is provided, form based log in must be explicitly provided. -A minimal, explicit Java configuration can be found below: +By default, Spring Security form login is enabled. +However, as soon as any servlet-based configuration is provided, form based login must be explicitly provided. +The following example shows a minimal, explicit Java configuration: -.Form Log In +.Form LogIn ==== .Java [source,java,role="primary"] @@ -98,11 +97,11 @@ fun configure(http: HttpSecurity) { ---- ==== -In this configuration Spring Security will render a default log in page. -Most production applications will require a custom log in form. +In the preceding configuration, Spring Security renders a default login page. +Most production applications require a custom login form. [[servlet-authentication-form-custom]] -The configuration below demonstrates how to provide a custom log in form. +The following configuration demonstrates how to provide a custom login form. .Custom Log In Form Configuration ==== @@ -147,9 +146,9 @@ fun configure(http: HttpSecurity) { [[servlet-authentication-form-custom-html]] When the login page is specified in the Spring Security configuration, you are responsible for rendering the page. // FIXME: default login page rendered by Spring Security -Below is a https://www.thymeleaf.org/[Thymeleaf] template that produces an HTML login form that complies with a login page of `/login`.: +The following https://www.thymeleaf.org/[Thymeleaf] template produces an HTML login form that complies with a login page of `/login`.: -.Log In Form +.Login Form ==== .src/main/resources/templates/login.html [source,xml] @@ -181,19 +180,19 @@ Below is a https://www.thymeleaf.org/[Thymeleaf] template that produces an HTML There are a few key points about the default HTML form: -* The form should perform a `post` to `/login` -* The form will need to include a <> which is <> by Thymeleaf. -* The form should specify the username in a parameter named `username` -* The form should specify the password in a parameter named `password` -* If the HTTP parameter error is found, it indicates the user failed to provide a valid username / password -* If the HTTP parameter logout is found, it indicates the user has logged out successfully +* The form should perform a `post` to `/login`. +* The form needs to include a <>, which is <> by Thymeleaf. +* The form should specify the username in a parameter named `username`. +* The form should specify the password in a parameter named `password`. +* If the HTTP parameter named `error` is found, it indicates the user failed to provide a valid username or password. +* If the HTTP parameter named `logout` is found, it indicates the user has logged out successfully. -Many users will not need much more than to customize the log in page. -However, if needed everything above can be customized with additional configuration. +Many users do not need much more than to customize the log in page. +However, if needed, you can customize everything shown earlier with additional configuration. [[servlet-authentication-form-custom-controller]] -If you are using Spring MVC, you will need a controller that maps `GET /login` to the login template we created. -A minimal sample `LoginController` can be see below: +If you use Spring MVC, you need a controller that maps `GET /login` to the login template we created. +The following example shows a minimal `LoginController`: .LoginController ==== diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/in-memory.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/in-memory.adoc index a364cee0e1a..5b2a37a49f8 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/in-memory.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/in-memory.adoc @@ -3,9 +3,9 @@ Spring Security's `InMemoryUserDetailsManager` implements <> to provide support for username/password based authentication that is retrieved in memory. `InMemoryUserDetailsManager` provides management of `UserDetails` by implementing the `UserDetailsManager` interface. -`UserDetails` based authentication is used by Spring Security when it is configured to <> for authentication. +`UserDetails`-based authentication is used by Spring Security when it is configured to <> for authentication. -In this sample we use <> to encode the password of `password` and get the encoded password of `+{bcrypt}$2a$10$GRLdNijSQMUvl/au9ofL.eDwmoohzzS7.rmNSJZ.0FxO/BTk76klW+`. +In the following sample, we use <> to encode a password value of `password` and get the encoded password of `+{bcrypt}$2a$10$GRLdNijSQMUvl/au9ofL.eDwmoohzzS7.rmNSJZ.0FxO/BTk76klW+`: .InMemoryUserDetailsManager Java Configuration ==== @@ -61,12 +61,11 @@ fun users(): UserDetailsService { ---- ==== -The samples above store the passwords in a secure format, but leave a lot to be desired in terms of getting started experience. +The preceding samples store the passwords in a secure format but leave a lot to be desired in terms of a getting started experience. - -In the sample below we leverage <> to ensure that the password stored in memory is protected. +In the following sample, we use <> to ensure that the password stored in memory is protected. However, it does not protect against obtaining the password by decompiling the source code. -For this reason, `User.withDefaultPasswordEncoder` should only be used for "getting started" and is not intended for production. +For this reason, `User.withDefaultPasswordEncoder` should only be used for "`getting started`" and is not intended for production. .InMemoryUserDetailsManager with User.withDefaultPasswordEncoder ==== @@ -113,8 +112,8 @@ fun users(): UserDetailsService { ---- ==== -There is no simple way to use `User.withDefaultPasswordEncoder` with XML based configuration. -For demos or just getting started, you can choose to prefix the password with `+{noop}+` to indicate <>. +There is no simple way to use `User.withDefaultPasswordEncoder` with XML-based configuration. +For demos or just getting started, you can choose to prefix the password with `+{noop}+` to indicate <>: . `+{noop}+` XML Configuration ==== diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/index.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/index.adoc index 415d8281186..13fc12aed9c 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/index.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/index.adoc @@ -4,21 +4,21 @@ :icondir: images/icons One of the most common ways to authenticate a user is by validating a username and password. -As such, Spring Security provides comprehensive support for authenticating with a username and password. +Spring Security provides comprehensive support for authenticating with a username and password. [[servlet-authentication-unpwd-input]] -*Reading the Username & Password* +== Reading the Username & Password -Spring Security provides the following built in mechanisms for reading a username and password from the `HttpServletRequest`: +Spring Security provides the following built-in mechanisms for reading a username and password from `HttpServletRequest`: * <> * <> * <> [[servlet-authentication-unpwd-storage]] -*Storage Mechanisms* +== Storage Mechanisms -Each of the supported mechanisms for reading a username and password can leverage any of the supported storage mechanisms: +Each of the supported mechanisms for reading a username and password can use any of the supported storage mechanisms: * Simple Storage with <> * Relational Databases with <> diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/jdbc.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/jdbc.adoc index 009e5515129..740c8b4de73 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/jdbc.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/jdbc.adoc @@ -1,11 +1,11 @@ [[servlet-authentication-jdbc]] = JDBC Authentication -Spring Security's `JdbcDaoImpl` implements <> to provide support for username/password based authentication that is retrieved using JDBC. +Spring Security's `JdbcDaoImpl` implements <> to provide support for username-and-password-based authentication that is retrieved by using JDBC. `JdbcUserDetailsManager` extends `JdbcDaoImpl` to provide management of `UserDetails` through the `UserDetailsManager` interface. -`UserDetails` based authentication is used by Spring Security when it is configured to <> for authentication. +`UserDetails`-based authentication is used by Spring Security when it is configured to <> for authentication. -In the following sections we will discuss: +In the following sections, we discuss: * The <> used by Spring Security JDBC Authentication * <> @@ -14,20 +14,16 @@ In the following sections we will discuss: [[servlet-authentication-jdbc-schema]] == Default Schema -Spring Security provides default queries for JDBC based authentication. +Spring Security provides default queries for JDBC-based authentication. This section provides the corresponding default schemas used with the default queries. -You will need to adjust the schema to match any customizations to the queries and the database dialect you are using. +You need to adjust the schema to match any customizations to the queries and the database dialect you use. [[servlet-authentication-jdbc-schema-user]] === User Schema `JdbcDaoImpl` requires tables to load the password, account status (enabled or disabled) and a list of authorities (roles) for the user. -The default schema required can be found below. -[NOTE] -==== -The default schema is also exposed as a classpath resource named `org/springframework/security/core/userdetails/jdbc/users.ddl`. -==== +NOTE: The default schema is also exposed as a classpath resource named `org/springframework/security/core/userdetails/jdbc/users.ddl`. .Default User Schema ==== @@ -48,8 +44,7 @@ create unique index ix_auth_username on authorities (username,authority); ---- ==== -Oracle is a popular database choice, but requires a slightly different schema. -You can find the default Oracle Schema for users below. +Oracle is a popular database choice but requires a slightly different schema: .Default User Schema for Oracle Databases ==== @@ -74,8 +69,7 @@ ALTER TABLE AUTHORITIES ADD CONSTRAINT AUTHORITIES_FK1 FOREIGN KEY (USERNAME) RE [[servlet-authentication-jdbc-schema-group]] === Group Schema -If your application is leveraging groups, you will need to provide the groups schema. -The default schema for groups can be found below. +If your application uses groups, you need to provide the groups schema: .Default Group Schema ==== @@ -105,7 +99,7 @@ create table group_members ( == Setting up a DataSource Before we configure `JdbcUserDetailsManager`, we must create a `DataSource`. -In our example, we will setup an https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/data-access.html#jdbc-embedded-database-support[embedded DataSource] that is initialized with the <>. +In our example, we set up an https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/data-access.html#jdbc-embedded-database-support[embedded DataSource] that is initialized with the <>. .Embedded Data Source ==== @@ -142,12 +136,12 @@ fun dataSource(): DataSource { ---- ==== -In a production environment, you will want to ensure you setup a connection to an external database. +In a production environment, you want to ensure that you set up a connection to an external database. [[servlet-authentication-jdbc-bean]] == JdbcUserDetailsManager Bean -In this sample we use <> to encode the password of `password` and get the encoded password of `+{bcrypt}$2a$10$GRLdNijSQMUvl/au9ofL.eDwmoohzzS7.rmNSJZ.0FxO/BTk76klW+`. +In this sample, we use <> to encode a password value of `password` and get the encoded password of `+{bcrypt}$2a$10$GRLdNijSQMUvl/au9ofL.eDwmoohzzS7.rmNSJZ.0FxO/BTk76klW+`. See the <> section for more details about how to store passwords. .JdbcUserDetailsManager @@ -171,7 +165,7 @@ UserDetailsManager users(DataSource dataSource) { JdbcUserDetailsManager users = new JdbcUserDetailsManager(dataSource); users.createUser(user); users.createUser(admin); - return users; + return users; } ---- diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/ldap.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/ldap.adoc index 57f456deb8a..f1c32667e26 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/ldap.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/ldap.adoc @@ -1,25 +1,25 @@ [[servlet-authentication-ldap]] = LDAP Authentication -LDAP is often used by organizations as a central repository for user information and as an authentication service. +LDAP (Lightweight Directory Access Protocol) is often used by organizations as a central repository for user information and as an authentication service. It can also be used to store the role information for application users. -Spring Security's LDAP based authentication is used by Spring Security when it is configured to <> for authentication. -However, despite leveraging a username/password for authentication it does not integrate using `UserDetailsService` because in <> the LDAP server does not return the password so the application cannot perform validation of the password. +Spring Security's LDAP-based authentication is used by Spring Security when it is configured to <> for authentication. +However, despite using a username and password for authentication, it does not use `UserDetailsService`, because, in <>, the LDAP server does not return the password, so the application cannot perform validation of the password. -There are many different scenarios for how an LDAP server may be configured so Spring Security's LDAP provider is fully configurable. -It uses separate strategy interfaces for authentication and role retrieval and provides default implementations which can be configured to handle a wide range of situations. +There are many different scenarios for how an LDAP server can be configured, so Spring Security's LDAP provider is fully configurable. +It uses separate strategy interfaces for authentication and role retrieval and provides default implementations, which can be configured to handle a wide range of situations. [[servlet-authentication-ldap-prerequisites]] == Prerequisites You should be familiar with LDAP before trying to use it with Spring Security. -The following link provides a good introduction to the concepts involved and a guide to setting up a directory using the free LDAP server OpenLDAP: https://www.zytrax.com/books/ldap/. -Some familiarity with the JNDI APIs used to access LDAP from Java may also be useful. -We don't use any third-party LDAP libraries (Mozilla, JLDAP etc.) in the LDAP provider, but extensive use is made of Spring LDAP, so some familiarity with that project may be useful if you plan on adding your own customizations. +The following link provides a good introduction to the concepts involved and a guide to setting up a directory using the free LDAP server, OpenLDAP: https://www.zytrax.com/books/ldap/. +Some familiarity with the JNDI APIs used to access LDAP from Java can also be useful. +We do not use any third-party LDAP libraries (Mozilla, JLDAP, or others) in the LDAP provider, but extensive use is made of Spring LDAP, so some familiarity with that project may be useful if you plan on adding your own customizations. -When using LDAP authentication, it is important to ensure that you configure LDAP connection pooling properly. -If you are unfamiliar with how to do this, you can refer to the https://docs.oracle.com/javase/jndi/tutorial/ldap/connect/config.html[Java LDAP documentation]. +When using LDAP authentication, you should ensure that you properly configure LDAP connection pooling. +If you are unfamiliar with how to do so, see the https://docs.oracle.com/javase/jndi/tutorial/ldap/connect/config.html[Java LDAP documentation]. // FIXME: @@ -35,16 +35,17 @@ If you are unfamiliar with how to do this, you can refer to the https://docs.ora [[servlet-authentication-ldap-embedded]] == Setting up an Embedded LDAP Server -The first thing you will need to do is to ensure that you have an LDAP Server to point your configuration to. -For simplicity, it often best to start with an embedded LDAP Server. +The first thing you need to do is to ensure that you have an LDAP Server to which to point your configuration. +For simplicity, it is often best to start with an embedded LDAP Server. Spring Security supports using either: * <> * <> -In the samples below, we expose the following as `users.ldif` as a classpath resource to initialize the embedded LDAP server with the users `user` and `admin` both of which have a password of `password`. +In the following samples, we expose `users.ldif` as a classpath resource to initialize the embedded LDAP server with two users, `user` and `admin`, both of which have a password of `password`: .users.ldif +==== [source,ldif] ---- dn: ou=groups,dc=springframework,dc=org @@ -90,11 +91,12 @@ objectclass: groupOfNames cn: admin uniqueMember: uid=admin,ou=people,dc=springframework,dc=org ---- +==== [[servlet-authentication-ldap-unboundid]] === Embedded UnboundID Server -If you wish to use https://ldap.com/unboundid-ldap-sdk-for-java/[UnboundID], then specify the following dependencies: +If you wish to use https://ldap.com/unboundid-ldap-sdk-for-java/[UnboundID], specify the following dependencies: .UnboundID Dependencies ==== @@ -118,7 +120,7 @@ depenendencies { ---- ==== -You can then configure the Embedded LDAP Server +You can then configure the Embedded LDAP Server: .Embedded LDAP Server Configuration ==== @@ -153,14 +155,11 @@ fun ldapContainer(): UnboundIdContainer { [[servlet-authentication-ldap-apacheds]] === Embedded ApacheDS Server -[NOTE] -==== -Spring Security uses ApacheDS 1.x which is no longer maintained. +NOTE: Spring Security uses ApacheDS 1.x, which is no longer maintained. Unfortunately, ApacheDS 2.x has only released milestone versions with no stable release. Once a stable release of ApacheDS 2.x is available, we will consider updating. -==== -If you wish to use https://directory.apache.org/apacheds/[Apache DS], then specify the following dependencies: +If you wish to use https://directory.apache.org/apacheds/[Apache DS], specify the following dependencies: .ApacheDS Dependencies ==== @@ -191,7 +190,7 @@ depenendencies { ---- ==== -You can then configure the Embedded LDAP Server +You can then configure the Embedded LDAP Server: .Embedded LDAP Server Configuration ==== @@ -226,8 +225,8 @@ fun ldapContainer(): ApacheDSContainer { [[servlet-authentication-ldap-contextsource]] == LDAP ContextSource -Once you have an LDAP Server to point your configuration to, you need configure Spring Security to point to an LDAP server that should be used to authenticate users. -This is done by creating an LDAP `ContextSource`, which is the equivalent of a JDBC `DataSource`. +Once you have an LDAP Server to which to point your configuration, you need to configure Spring Security to point to an LDAP server that should be used to authenticate users. +To do so, create an LDAP `ContextSource` (which is the equivalent of a JDBC `DataSource`): .LDAP Context Source ==== @@ -258,15 +257,15 @@ fun contextSource(container: UnboundIdContainer): ContextSource { [[servlet-authentication-ldap-authentication]] == Authentication -Spring Security's LDAP support does not use the <> because LDAP bind authentication does not allow clients to read the password or even a hashed version of the password. -This means there is no way a password to be read and then authenticated by Spring Security. +Spring Security's LDAP support does not use the <> because LDAP bind authentication does not let clients read the password or even a hashed version of the password. +This means there is no way for a password to be read and then authenticated by Spring Security. -For this reason, LDAP support is implemented using the `LdapAuthenticator` interface. -The `LdapAuthenticator` is also responsible for retrieving any required user attributes. +For this reason, LDAP support is implemented through the `LdapAuthenticator` interface. +The `LdapAuthenticator` interface is also responsible for retrieving any required user attributes. This is because the permissions on the attributes may depend on the type of authentication being used. -For example, if binding as the user, it may be necessary to read them with the user's own permissions. +For example, if binding as the user, it may be necessary to read the attributes with the user's own permissions. -There are two `LdapAuthenticator` implementations supplied with Spring Security: +Spring Security supplies two `LdapAuthenticator` implementations: * <> * <> @@ -275,11 +274,10 @@ There are two `LdapAuthenticator` implementations supplied with Spring Security: == Using Bind Authentication https://ldap.com/the-ldap-bind-operation/[Bind Authentication] is the most common mechanism for authenticating users with LDAP. -In bind authentication the users credentials (i.e. username/password) are submitted to the LDAP server which authenticates them. -The advantage to using bind authentication is that the user's secrets (i.e. password) do not need to be exposed to clients which helps to protect them from leaking. +In bind authentication, the user's credentials (username and password) are submitted to the LDAP server, which authenticates them. +The advantage to using bind authentication is that the user's secrets (the password) do not need to be exposed to clients, which helps to protect them from leaking. - -An example of bind authentication configuration can be found below. +The following example shows bind authentication configuration: .Bind Authentication ==== @@ -323,9 +321,9 @@ fun authenticationProvider(authenticator: LdapAuthenticator): LdapAuthentication ---- ==== -This simple example would obtain the DN for the user by substituting the user login name in the supplied pattern and attempting to bind as that user with the login password. +The preceding simple example would obtain the DN for the user by substituting the user login name in the supplied pattern and attempting to bind as that user with the login password. This is OK if all your users are stored under a single node in the directory. -If instead you wished to configure an LDAP search filter to locate the user, you could use the following: +If, instead, you wish to configure an LDAP search filter to locate the user, you could use the following: .Bind Authentication with Search Filter ==== @@ -377,15 +375,15 @@ fun authenticationProvider(authenticator: LdapAuthenticator): LdapAuthentication ---- ==== -If used with the `ContextSource` <>, this would perform a search under the DN `ou=people,dc=springframework,dc=org` using `+(uid={0})+` as a filter. -Again the user login name is substituted for the parameter in the filter name, so it will search for an entry with the `uid` attribute equal to the user name. -If a user search base isn't supplied, the search will be performed from the root. +If used with the `ContextSource` <>, this would perform a search under the DN `ou=people,dc=springframework,dc=org` by using `+(uid={0})+` as a filter. +Again, the user login name is substituted for the parameter in the filter name, so it searchs for an entry with the `uid` attribute equal to the user name. +If a user search base is not supplied, the search is performed from the root. [[servlet-authentication-ldap-pwd]] == Using Password Authentication Password comparison is when the password supplied by the user is compared with the one stored in the repository. -This can either be done by retrieving the value of the password attribute and checking it locally or by performing an LDAP "compare" operation, where the supplied password is passed to the server for comparison and the real password value is never retrieved. +This can either be done by retrieving the value of the password attribute and checking it locally or by performing an LDAP "`compare`" operation, where the supplied password is passed to the server for comparison and the real password value is never retrieved. An LDAP compare cannot be done when the password is properly hashed with a random salt. .Minimal Password Compare Configuration @@ -428,7 +426,7 @@ fun authenticationProvider(authenticator: LdapAuthenticator): LdapAuthentication ---- ==== -A more advanced configuration with some customizations can be found below. +The following example shows a more advanced configuration with some customizations: .Password Compare Configuration ==== @@ -481,13 +479,14 @@ fun authenticationProvider(authenticator: LdapAuthenticator): LdapAuthentication ---- ==== -<1> Specify the password attribute as `pwd` -<2> Use `BCryptPasswordEncoder` +<1> Specify the password attribute as `pwd`. +<2> Use `BCryptPasswordEncoder`. == LdapAuthoritiesPopulator -Spring Security's `LdapAuthoritiesPopulator` is used to determine what authorites are returned for the user. +Spring Security's `LdapAuthoritiesPopulator` is used to determine what authorities are returned for the user. +The following example shows how configure `LdapAuthoritiesPopulator`: .LdapAuthoritiesPopulator Configuration ==== @@ -537,14 +536,17 @@ fun authenticationProvider(authenticator: LdapAuthenticator, authorities: LdapAu == Active Directory -Active Directory supports its own non-standard authentication options, and the normal usage pattern doesn't fit too cleanly with the standard `LdapAuthenticationProvider`. -Typically authentication is performed using the domain username (in the form `user@domain`), rather than using an LDAP distinguished name. -To make this easier, Spring Security has an authentication provider which is customized for a typical Active Directory setup. +Active Directory supports its own non-standard authentication options, and the normal usage pattern does not fit too cleanly with the standard `LdapAuthenticationProvider`. +Typically, authentication is performed by using the domain username (in the form of `user@domain`), rather than using an LDAP distinguished name. +To make this easier, Spring Security has an authentication provider, which is customized for a typical Active Directory setup. Configuring `ActiveDirectoryLdapAuthenticationProvider` is quite straightforward. -You just need to supply the domain name and an LDAP URL supplying the address of the server footnote:[It is also possible to obtain the server's IP address using a DNS lookup. -This is not currently supported, but hopefully will be in a future version.]. -An example configuration can be seen below: +You need only supply the domain name and an LDAP URL that supplies the address of the server. + +NOTE: It is also possible to obtain the server's IP address byusing a DNS lookup. +This is not currently supported, but hopefully will be in a future version. + +The following example configures Active Directory: .Example Active Directory Configuration ==== diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/password-encoder.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/password-encoder.adoc index 73f9e1f2e10..70b7e792529 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/password-encoder.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/password-encoder.adoc @@ -1,5 +1,5 @@ [[servlet-authentication-password-storage]] = PasswordEncoder -Spring Security's servlet support storing passwords securely by integrating with <>. -Customizing the `PasswordEncoder` implementation used by Spring Security can be done by <>. +Spring Security's servlet support includes storing passwords securely by integrating with <>. +You can customize the `PasswordEncoder` implementation used by Spring Security by <>. diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/user-details-service.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/user-details-service.adoc index 9147cedbd2e..f630021ee5c 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/user-details-service.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/user-details-service.adoc @@ -1,11 +1,11 @@ [[servlet-authentication-userdetailsservice]] = UserDetailsService -{security-api-url}org/springframework/security/core/userdetails/UserDetailsService.html[`UserDetailsService`] is used by <> for retrieving a username, password, and other attributes for authenticating with a username and password. +{security-api-url}org/springframework/security/core/userdetails/UserDetailsService.html[`UserDetailsService`] is used by <> for retrieving a username, a password, and other attributes for authenticating with a username and password. Spring Security provides <> and <> implementations of `UserDetailsService`. You can define custom authentication by exposing a custom `UserDetailsService` as a bean. -For example, the following will customize authentication assuming that `CustomUserDetailsService` implements `UserDetailsService`: +For example, the following listing customizes authentication, assuming that `CustomUserDetailsService` implements `UserDetailsService`: NOTE: This is only used if the `AuthenticationManagerBuilder` has not been populated and no `AuthenticationProviderBean` is defined. diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/x509.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/x509.adoc index d84ae8560c6..a3fbb9017ef 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/x509.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/x509.adoc @@ -1,28 +1,27 @@ [[servlet-x509]] == X.509 Authentication - [[x509-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. +The browser automatically checks that the certificate presented by a server has been issued (digitally signed) by one of a list of trusted certificate authorities that it maintains. -You can also use SSL with "mutual authentication"; the server will then request a valid certificate from the client as part of the SSL handshake. -The server will authenticate the client by checking that its certificate is signed by an acceptable authority. +You can also use SSL with "`mutual authentication`". The server then requests a valid certificate from the client as part of the SSL handshake. +The server authenticates the client by checking that its certificate is signed by an acceptable authority. If a valid certificate has been provided, it can be obtained through the servlet API in an application. -Spring Security X.509 module extracts the certificate using a filter. +The Spring Security X.509 module extracts the certificate by using a filter. It maps the certificate to an application user and loads that user's set of granted authorities for use with the standard Spring Security infrastructure. You should be familiar with using certificates and setting up client authentication for your servlet container before attempting to use it with Spring Security. Most of the work is in creating and installing suitable certificates and keys. -For example, if you're using Tomcat then read the instructions here https://tomcat.apache.org/tomcat-9.0-doc/ssl-howto.html[https://tomcat.apache.org/tomcat-9.0-doc/ssl-howto.html]. -It's important that you get this working before trying it out with Spring Security +For example, if you use Tomcat, you should read the https://tomcat.apache.org/tomcat-9.0-doc/ssl-howto.html[Tomcat SSL instructions]. +You should get this working before trying it out with Spring Security. === Adding X.509 Authentication to Your Web Application Enabling X.509 client authentication is very straightforward. -Just add the `` element to your http security namespace configuration. +To do so, add the `` element to your http security namespace configuration: +==== [source,xml] ---- @@ -30,39 +29,40 @@ Just add the `` element to your http security namespace configuration. ; ---- +==== The element has two optional attributes: * `subject-principal-regex`. The regular expression used to extract a username from the certificate's subject name. -The default value is shown above. -This is the username which will be passed to the `UserDetailsService` to load the authorities for the user. +The default value is shown in the preceding listing. +This is the username that is passed to the `UserDetailsService` to load the authorities for the user. * `user-service-ref`. -This is the bean Id of the `UserDetailsService` to be used with X.509. -It isn't needed if there is only one defined in your application context. +This is the bean ID of the `UserDetailsService` to be used with X.509. +It is not needed if there is only one defined in your application context. The `subject-principal-regex` should contain a single group. -For example the default expression "CN=(.*?)," matches the common name field. -So if the subject name in the certificate is "CN=Jimi Hendrix, OU=...", this will give a user name of "Jimi Hendrix". +For example, the default expression (`CN=(.*?)`) matches the common name field. +So, if the subject name in the certificate is "CN=Jimi Hendrix, OU=...", this gives a user name of "Jimi Hendrix". The matches are case insensitive. -So "emailAddress=(+.*?+)," will match "EMAILADDRESS=jimi@hendrix.org,CN=..." giving a user name "jimi@hendrix.org". -If the client presents a certificate and a valid username is successfully extracted, then there should be a valid `Authentication` object in the security context. -If no certificate is found, or no corresponding user could be found then the security context will remain empty. -This means that you can easily use X.509 authentication with other options such as a form-based login. +So "emailAddress=(+.*?+)," matches "EMAILADDRESS=jimi@hendrix.org,CN=...", giving a user name "jimi@hendrix.org". +If the client presents a certificate and a valid username is successfully extracted, there should be a valid `Authentication` object in the security context. +If no certificate is found or no corresponding user could be found, the security context remains empty. +This means that you can use X.509 authentication with other options, such as a form-based login. [[x509-ssl-config]] === Setting up SSL in Tomcat There are some pre-generated certificates in the `samples/certificate` directory in the Spring Security project. -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. +You can use these to enable SSL for testing if you do not want to generate your own. +The `server.jks` file contains the server certificate, the private key, and the issuing authority certificate. There are also some client certificate files for the users from the sample applications. You can install these in your browser to enable SSL client authentication. -To run tomcat with SSL support, drop the `server.jks` file into the tomcat `conf` directory and add the following connector to the `server.xml` file +To run tomcat with SSL support, drop the `server.jks` file into the tomcat `conf` directory and add the following connector to the `server.xml` file: +==== [source,xml] ---- - - ---- +==== -`clientAuth` can also be set to `want` if you still want SSL connections to succeed even if the client doesn't provide a certificate. -Clients which don't present a certificate won't be able to access any objects secured by Spring Security unless you use a non-X.509 authentication mechanism, such as form authentication. - +`clientAuth` can also be set to `want` if you still want SSL connections to succeed even if the client does not provide a certificate. +Clients that do not present a certificate cannot access any objects secured by Spring Security unless you use a non-X.509 authentication mechanism, such as form authentication. diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authorization/acls.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authorization/acls.adoc index f87e83d4ee0..f55f59ec1b7 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/authorization/acls.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authorization/acls.adoc @@ -1,153 +1,146 @@ [[domain-acls]] == Domain Object Security (ACLs) +This section describes how Spring Security provides domain object security with Access Control Lists (ACLs). + [[domain-acls-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`). +Complex applications often need to define access permissions beyond a web request or method invocation level. +Instead, security decisions need to comprise 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. -Imagine you're designing an application for a pet clinic. -There will be two main groups of users of your Spring-based application: staff of the pet clinic, as well as the pet clinic's customers. -The staff will have access to all of the data, whilst your customers will only be able to see their own customer records. -To make it a little more interesting, your customers can allow other users to see their customer records, such as their "puppy preschool" mentor or president of their local "Pony Club". -Using Spring Security as the foundation, you have several approaches that can be used: +Imagine you are designing an application for a pet clinic. +There are two main groups of users of your Spring-based application: staff of the pet clinic and the pet clinic's customers. +The staff should have access to all of the data, while your customers should be able to see only their own customer records. +To make it a little more interesting, your customers can let other users see their customer records, such as their "`puppy preschool`" mentor or the president of their local "`Pony Club`". +When you use Spring Security as the foundation, you have several possible approaches: * Write your business methods to enforce the security. You could consult a collection within the `Customer` domain object instance to determine which users have access. -By using the `SecurityContextHolder.getContext().getAuthentication()`, you'll be able to access the `Authentication` object. -* Write an `AccessDecisionVoter` to enforce the security from the `GrantedAuthority[]` s stored in the `Authentication` object. -This would mean your `AuthenticationManager` would need to populate the `Authentication` with custom ``GrantedAuthority[]``s representing each of the `Customer` domain object instances the principal has access to. +By using `SecurityContextHolder.getContext().getAuthentication()`, you can access the `Authentication` object. +* Write an `AccessDecisionVoter` to enforce the security from the `GrantedAuthority[]` instances stored in the `Authentication` object. +This means that your `AuthenticationManager` needs to populate the `Authentication` with custom `GrantedAuthority[]` objects to represent each of the `Customer` domain object instances to which the principal has access. * Write an `AccessDecisionVoter` to enforce the security and open the target `Customer` domain object directly. -This would mean your voter needs access to a DAO that allows it to retrieve the `Customer` object. -It would then access the `Customer` object's collection of approved users and make the appropriate decision. - +This would mean your voter needs access to a DAO that lets it retrieve the `Customer` object. +It can then access the `Customer` object's collection of approved users and make the appropriate decision. Each one of these approaches is perfectly legitimate. However, the first couples your authorization checking to your business code. -The main problems with this include the enhanced difficulty of unit testing and the fact it would be more difficult to reuse the `Customer` authorization logic elsewhere. -Obtaining the `GrantedAuthority[]` s from the `Authentication` object is also fine, but will not scale to large numbers of `Customer` s. -If a user might be able to access 5,000 `Customer` s (unlikely in this case, but imagine if it were a popular vet for a large Pony Club!) the amount of memory consumed and time required to construct the `Authentication` object would be undesirable. +The main problems with this include the enhanced difficulty of unit testing and the fact that it would be more difficult to reuse the `Customer` authorization logic elsewhere. +Obtaining the `GrantedAuthority[]` instances from the `Authentication` object is also fine but will not scale to large numbers of `Customer` objects. +If a user can access 5,000 `Customer` objects (unlikely in this case, but imagine if it were a popular vet for a large Pony Club!) the amount of memory consumed and the time required to construct the `Authentication` object would be undesirable. The final method, opening the `Customer` directly from external code, is probably the best of the three. -It achieves separation of concerns, and doesn't misuse memory or CPU cycles, but it is still inefficient in that both the `AccessDecisionVoter` and the eventual business method itself will perform a call to the DAO responsible for retrieving the `Customer` object. +It achieves separation of concerns and does not misuse memory or CPU cycles, but it is still inefficient in that both the `AccessDecisionVoter` and the eventual business method itself perform a call to the DAO responsible for retrieving the `Customer` object. Two accesses per method invocation is clearly undesirable. -In addition, with every approach listed you'll need to write your own access control list (ACL) persistence and business logic from scratch. - -Fortunately, there is another alternative, which we'll talk about below. +In addition, with every approach listed, you need to write your own access control list (ACL) persistence and business logic from scratch. +Fortunately, there is another alternative, which we discuss later. [[domain-acls-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. +You need to add this JAR to your classpath to use Spring Security's domain object instance security capabilities. -Spring Security's domain object instance security capabilities centre on the concept of an access control list (ACL). -Every domain object instance in your system has its own ACL, and the ACL records details of who can and can't work with that domain object. -With this in mind, Spring Security delivers three main ACL-related capabilities to your application: +Spring Security's domain object instance security capabilities center on the concept of an access control list (ACL). +Every domain object instance in your system has its own ACL, and the ACL records details of who can and cannot work with that domain object. +With this in mind, Spring Security provides three main ACL-related capabilities to your application: -* A way of efficiently retrieving ACL entries for all of your domain objects (and modifying those ACLs) -* A way of ensuring a given principal is permitted to work with your objects, before methods are called -* A way of ensuring a given principal is permitted to work with your objects (or something they return), after methods are called +* A way to efficiently retrieve ACL entries for all of your domain objects (and modifying those ACLs) +* A way to ensure a given principal is permitted to work with your objects before methods are called +* A way to ensure a given principal is permitted to work with your objects (or something they return) after methods are called As indicated by the first bullet point, one of the main capabilities of the Spring Security ACL module is providing a high-performance way of retrieving ACLs. -This ACL repository capability is extremely important, because every domain object instance in your system might have several access control entries, and each ACL might inherit from other ACLs in a tree-like structure (this is supported out-of-the-box by Spring Security, and is very commonly used). +This ACL repository capability is extremely important, because every domain object instance in your system might have several access control entries, and each ACL might inherit from other ACLs in a tree-like structure (this is supported by Spring Security, and it is very commonly used). Spring Security's ACL capability has been carefully designed to provide high performance retrieval of ACLs, together with pluggable caching, deadlock-minimizing database updates, independence from ORM frameworks (we use JDBC directly), proper encapsulation, and transparent database updating. -Given databases are central to the operation of the ACL module, let's explore the four main tables used by default in the implementation. -The tables are presented below in order of size in a typical Spring Security ACL deployment, with the table with the most rows listed last: - +Given that databases are central to the operation of the ACL module, we need explore the four main tables used by default in the implementation. +The tables are presented in order of size in a typical Spring Security ACL deployment, with the table with the most rows listed last: - -* ACL_SID allows us to uniquely identify any principal or authority in the system ("SID" stands for "security identity"). +[[acl_tables]] +* `ACL_SID` lets us uniquely identify any principal or authority in the system ("`SID`" stands for "`Security IDentity`"). The only columns are the ID, a textual representation of the SID, and a flag to indicate whether the textual representation refers to a principal name or a `GrantedAuthority`. Thus, there is a single row for each unique principal or `GrantedAuthority`. -When used in the context of receiving a permission, a SID is generally called a "recipient". +When used in the context of receiving a permission, an SID is generally called a "`recipient`". -* ACL_CLASS allows us to uniquely identify any domain object class in the system. +* `ACL_CLASS` lets us uniquely identify any domain object class in the system. The only columns are the ID and the Java class name. -Thus, there is a single row for each unique Class we wish to store ACL permissions for. +Thus, there is a single row for each unique Class for which we wish to store ACL permissions. -* ACL_OBJECT_IDENTITY stores information for each unique domain object instance in the system. -Columns include the ID, a foreign key to the ACL_CLASS table, a unique identifier so we know which ACL_CLASS instance we're providing information for, the parent, a foreign key to the ACL_SID table to represent the owner of the domain object instance, and whether we allow ACL entries to inherit from any parent ACL. -We have a single row for every domain object instance we're storing ACL permissions for. +* `ACL_OBJECT_IDENTITY` stores information for each unique domain object instance in the system. +Columns include the ID, a foreign key to the ACL_CLASS table, a unique identifier so we know the ACL_CLASS instance for which we provide information, the parent, a foreign key to the ACL_SID table to represent the owner of the domain object instance, and whether we allow ACL entries to inherit from any parent ACL. +We have a single row for every domain object instance for which we store ACL permissions. -* Finally, ACL_ENTRY stores the individual permissions assigned to each recipient. -Columns include a foreign key to the ACL_OBJECT_IDENTITY, the recipient (i.e. a foreign key to ACL_SID), whether we'll be auditing or not, and the integer bit mask that represents the actual permission being granted or denied. +* Finally, `ACL_ENTRY` stores the individual permissions assigned to each recipient. +Columns include a foreign key to the ACL_OBJECT_IDENTITY, the recipient (which is a foreign key to ACL_SID), whether we audit or not, and the integer bit mask that represents the actual permission being granted or denied. We have a single row for every recipient that receives a permission to work with a domain object. - - - As mentioned in the last paragraph, the ACL system uses integer bit masking. -Don't worry, you need not be aware of the finer points of bit shifting to use the ACL system, but suffice to say that we have 32 bits we can switch on or off. -Each of these bits represents a permission, and by default the permissions are read (bit 0), write (bit 1), create (bit 2), delete (bit 3) and administer (bit 4). -It's easy to implement your own `Permission` instance if you wish to use other permissions, and the remainder of the ACL framework will operate without knowledge of your extensions. - -It is important to understand that the number of domain objects in your system has absolutely no bearing on the fact we've chosen to use integer bit masking. -Whilst you have 32 bits available for permissions, you could have billions of domain object instances (which will mean billions of rows in ACL_OBJECT_IDENTITY and quite probably ACL_ENTRY). -We make this point because we've found sometimes people mistakenly believe they need a bit for each potential domain object, which is not the case. +However, you need not be aware of the finer points of bit shifting to use the ACL system. +Suffice it to say that we have 32 bits we can switch on or off. +Each of these bits represents a permission. By default, the permissions are read (bit 0), write (bit 1), create (bit 2), delete (bit 3), and administer (bit 4). +You can implement your own `Permission` instance if you wish to use other permissions, and the remainder of the ACL framework operates without knowledge of your extensions. -Now that we've provided a basic overview of what the ACL system does, and what it looks like at a table structure, let's explore the key interfaces. -The key interfaces are: +You should understand that the number of domain objects in your system has absolutely no bearing on the fact that we have chosen to use integer bit masking. +While you have 32 bits available for permissions, you could have billions of domain object instances (which means billions of rows in ACL_OBJECT_IDENTITY and, probably, ACL_ENTRY). +We make this point because we have found that people sometimes mistakenly that believe they need a bit for each potential domain object, which is not the case. +Now that we have provided a basic overview of what the ACL system does, and what it looks like at a table-structure level, we need to explore the key interfaces: -* `Acl`: Every domain object has one and only one `Acl` object, which internally holds the `AccessControlEntry` s as well as knows the owner of the `Acl`. +* `Acl`: Every domain object has one and only one `Acl` object, which internally holds the `AccessControlEntry` objects and knows the owner of the `Acl`. An Acl does not refer directly to the domain object, but instead to an `ObjectIdentity`. -The `Acl` is stored in the ACL_OBJECT_IDENTITY table. +The `Acl` is stored in the `ACL_OBJECT_IDENTITY` table. -* `AccessControlEntry`: An `Acl` holds multiple `AccessControlEntry` s, which are often abbreviated as ACEs in the framework. -Each ACE refers to a specific tuple of `Permission`, `Sid` and `Acl`. +* `AccessControlEntry`: An `Acl` holds multiple `AccessControlEntry` objects, which are often abbreviated as ACEs in the framework. +Each ACE refers to a specific tuple of `Permission`, `Sid`, and `Acl`. An ACE can also be granting or non-granting and contain audit settings. -The ACE is stored in the ACL_ENTRY table. +The ACE is stored in the `ACL_ENTRY` table. -* `Permission`: A permission represents a particular immutable bit mask, and offers convenience functions for bit masking and outputting information. +* `Permission`: A permission represents a particular immutable bit mask and offers convenience functions for bit masking and outputting information. The basic permissions presented above (bits 0 through 4) are contained in the `BasePermission` class. -* `Sid`: The ACL module needs to refer to principals and `GrantedAuthority[]` s. -A level of indirection is provided by the `Sid` interface, which is an abbreviation of "security identity". +* `Sid`: The ACL module needs to refer to principals and `GrantedAuthority[]` instances. +A level of indirection is provided by the `Sid` interface. ("`SID`" is an abbreviation of "`Security IDentity`".) Common classes include `PrincipalSid` (to represent the principal inside an `Authentication` object) and `GrantedAuthoritySid`. -The security identity information is stored in the ACL_SID table. +The security identity information is stored in the `ACL_SID` table. * `ObjectIdentity`: Each domain object is represented internally within the ACL module by an `ObjectIdentity`. The default implementation is called `ObjectIdentityImpl`. * `AclService`: Retrieves the `Acl` applicable for a given `ObjectIdentity`. In the included implementation (`JdbcAclService`), retrieval operations are delegated to a `LookupStrategy`. -The `LookupStrategy` provides a highly optimized strategy for retrieving ACL information, using batched retrievals (`BasicLookupStrategy`) and supporting custom implementations that leverage materialized views, hierarchical queries and similar performance-centric, non-ANSI SQL capabilities. - -* `MutableAclService`: Allows a modified `Acl` to be presented for persistence. -It is not essential to use this interface if you do not wish. - +The `LookupStrategy` provides a highly optimized strategy for retrieving ACL information, using batched retrievals (`BasicLookupStrategy`) and supporting custom implementations that use materialized views, hierarchical queries, and similar performance-centric, non-ANSI SQL capabilities. +* `MutableAclService`: Lets a modified `Acl` be presented for persistence. +Use of this interface is optional. -Please note that our out-of-the-box AclService and related database classes all use ANSI SQL. +Note that our `AclService` and related database classes all use ANSI SQL. This should therefore work with all major databases. -At the time of writing, the system had been successfully tested using Hypersonic SQL, PostgreSQL, Microsoft SQL Server and Oracle. +At the time of writing, the system had been successfully tested with Hypersonic SQL, PostgreSQL, Microsoft SQL Server, and Oracle. Two samples ship with Spring Security that demonstrate the ACL module. -The first is the Contacts Sample, and the other is the Document Management System (DMS) Sample. -We suggest taking a look over these for examples. +The first is the https://github.com/spring-projects/spring-security/tree/master/samples/xml/contacts[Contacts sample], and the other is the https://github.com/spring-projects/spring-security/tree/master/samples/xml/dms[Document Management System (DMS) sample]. +We suggest taking a look at these examples. [[domain-acls-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. -The latter provides high-performance ACL retrieval capabilities, and the former provides mutator capabilities. -Refer to one of the samples that ship with Spring Security for an example configuration. -You'll also need to populate the database with the four ACL-specific tables listed in the last section (refer to the ACL samples for the appropriate SQL statements). - -Once you've created the required schema and instantiated `JdbcMutableAclService`, you'll next need to ensure your domain model supports interoperability with the Spring Security ACL package. -Hopefully `ObjectIdentityImpl` will prove sufficient, as it provides a large number of ways in which it can be used. -Most people will have domain objects that contain a `public Serializable getId()` method. -If the return type is long, or compatible with long (e.g. an int), you will find you need not give further consideration to `ObjectIdentity` issues. +To get starting with Spring Security's ACL capability, you need to store your ACL information somewhere. +This necessitates the instantiation of a `DataSource` in Spring. +The `DataSource` is then injected into a `JdbcMutableAclService` and a `BasicLookupStrategy` instance. +The former provides mutator capabilities, and the latter provides high-performance ACL retrieval capabilities. +See one of the https://github.com/spring-projects/spring-security/tree/master/samples[samples] that ship with Spring Security for an example configuration. +You also need to populate the database with the <> listed in the previous section (see the ACL samples for the appropriate SQL statements). + +Once you have created the required schema and instantiated `JdbcMutableAclService`, you need to ensure your domain model supports interoperability with the Spring Security ACL package. +Hopefully, `ObjectIdentityImpl` proves sufficient, as it provides a large number of ways in which it can be used. +Most people have domain objects that contain a `public Serializable getId()` method. +If the return type is `long` or compatible with `long` (such as an `int`), you may find that you need not give further consideration to `ObjectIdentity` issues. Many parts of the ACL module rely on long identifiers. -If you're not using long (or an int, byte etc), there is a very good chance you'll need to reimplement a number of classes. -We do not intend to support non-long identifiers in Spring Security's ACL module, as longs are already compatible with all database sequences, the most common identifier data type, and are of sufficient length to accommodate all common usage scenarios. +If you do not use `long` (or an `int`, `byte`, and so on), you probably need to reimplement a number of classes. +We do not intend to support non-long identifiers in Spring Security's ACL module, as longs are already compatible with all database sequences, are the most common identifier data type, and are of sufficient length to accommodate all common usage scenarios. -The following fragment of code shows how to create an `Acl`, or modify an existing `Acl`: +The following fragment of code shows how to create an `Acl` or modify an existing `Acl`: +==== [source,java] ---- // Prepare the information we'd like in our access control entry (ACE) @@ -167,27 +160,25 @@ acl = aclService.createAcl(oi); acl.insertAce(acl.getEntries().length, p, sid, true); aclService.updateAcl(acl); ---- +==== - - -In the example above, we're retrieving the ACL associated with the "Foo" domain object with identifier number 44. -We're then adding an ACE so that a principal named "Samantha" can "administer" the object. -The code fragment is relatively self-explanatory, except the insertAce method. -The first argument to the insertAce method is determining at what position in the Acl the new entry will be inserted. -In the example above, we're just putting the new ACE at the end of the existing ACEs. +In the preceding example, we retrieve the ACL associated with the `Foo` domain object with identifier number 44. +We then add an ACE so that a principal named "`Samantha`" can "`administer`" the object. +The code fragment is relatively self-explanatory, except for the `insertAce` method. +The first argument to the `insertAce` method determine position in the Acl at which the new entry is inserted. +In the preceding example, we put the new ACE at the end of the existing ACEs. The final argument is a Boolean indicating whether the ACE is granting or denying. -Most of the time it will be granting (true), but if it is denying (false), the permissions are effectively being blocked. +Most of the time it grants (`true`). However, if it denies (`false`), the permissions are effectively being blocked. -Spring Security does not provide any special integration to automatically create, update or delete ACLs as part of your DAO or repository operations. -Instead, you will need to write code like shown above for your individual domain objects. -It's worth considering using AOP on your services layer to automatically integrate the ACL information with your services layer operations. -We've found this quite an effective approach in the past. +Spring Security does not provide any special integration to automatically create, update, or delete ACLs as part of your DAO or repository operations. +Instead, you need to write code similar to that shown in the preceding example for your individual domain objects. +You should consider using AOP on your services layer to automatically integrate the ACL information with your services layer operations. +We have found this approach to be effective. -Once you've used the above techniques to store some ACL information in the database, the next step is to actually use the ACL information as part of authorization decision logic. +Once you have used the techniques described here to store some ACL information in the database, the next step is to actually use the ACL information as part of authorization decision logic. You have a number of choices here. -You could write your own `AccessDecisionVoter` or `AfterInvocationProvider` that respectively fires before or after a method invocation. +You could write your own `AccessDecisionVoter` or `AfterInvocationProvider` that (respectively) fires before or after a method invocation. Such classes would use `AclService` to retrieve the relevant ACL and then call `Acl.isGranted(Permission[] permission, Sid[] sids, boolean administrativeMode)` to decide whether permission is granted or denied. -Alternately, you could use our `AclEntryVoter`, `AclEntryAfterInvocationProvider` or `AclEntryAfterInvocationCollectionFilteringProvider` classes. +Alternately, you could use our `AclEntryVoter`, `AclEntryAfterInvocationProvider`, or `AclEntryAfterInvocationCollectionFilteringProvider` classes. All of these classes provide a declarative-based approach to evaluating ACL information at runtime, freeing you from needing to write any code. -Please refer to the sample applications to learn how to use these classes. - +See the https://github.com/spring-projects/spring-security/tree/master/samples[sample applications] to learn how to use these classes. diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authorization/architecture.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authorization/architecture.adoc index 15de8dbf70d..7d44250a391 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/authorization/architecture.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authorization/architecture.adoc @@ -1,41 +1,41 @@ // from the original documentation - [[authz-arch]] = Authorization Architecture +This section describes the Spring Security architecture that applies to authorization. [[authz-authorities]] == Authorities -<>, discusses how all `Authentication` implementations store a list of `GrantedAuthority` objects. +<> discusses how all `Authentication` implementations store a list of `GrantedAuthority` objects. These represent the authorities that have been granted to the principal. -the `GrantedAuthority` objects are inserted into the `Authentication` object by the `AuthenticationManager` and are later read by `AccessDecisionManager` s when making authorization decisions. +The `GrantedAuthority` objects are inserted into the `Authentication` object by the `AuthenticationManager` and are later read by `AccessDecisionManager` instances when making authorization decisions. -`GrantedAuthority` is an interface with only one method: +The `GrantedAuthority` interface has only one method: +==== [source,java] ---- - String getAuthority(); - ---- +==== -This method allows -`AccessDecisionManager` s to obtain a precise `String` representation of the `GrantedAuthority`. -By returning a representation as a `String`, a `GrantedAuthority` can be easily "read" by most `AccessDecisionManager` s. -If a `GrantedAuthority` cannot be precisely represented as a `String`, the `GrantedAuthority` is considered "complex" and `getAuthority()` must return `null`. +This method lets an +`AccessDecisionManager` instance to obtain a precise `String` representation of the `GrantedAuthority`. +By returning a representation as a `String`, a `GrantedAuthority` can be easily "`read`" by most `AccessDecisionManager` implementations. +If a `GrantedAuthority` cannot be precisely represented as a `String`, the `GrantedAuthority` is considered "`complex`" and `getAuthority()` must return `null`. -An example of a "complex" `GrantedAuthority` would be an implementation that stores a list of operations and authority thresholds that apply to different customer account numbers. -Representing this complex `GrantedAuthority` as a `String` would be quite difficult, and as a result the `getAuthority()` method should return `null`. -This will indicate to any `AccessDecisionManager` that it will need to specifically support the `GrantedAuthority` implementation in order to understand its contents. +An example of a "`complex`" `GrantedAuthority` would be an implementation that stores a list of operations and authority thresholds that apply to different customer account numbers. +Representing this complex `GrantedAuthority` as a `String` would be quite difficult. As a result, the `getAuthority()` method should return `null`. +This indicates to any `AccessDecisionManager` that it needs to support the specific `GrantedAuthority` implementation to understand its contents. -Spring Security includes one concrete `GrantedAuthority` implementation, `SimpleGrantedAuthority`. -This allows any user-specified `String` to be converted into a `GrantedAuthority`. -All `AuthenticationProvider` s included with the security architecture use `SimpleGrantedAuthority` to populate the `Authentication` object. +Spring Security includes one concrete `GrantedAuthority` implementation: `SimpleGrantedAuthority`. +This implementation lets any user-specified `String` be converted into a `GrantedAuthority`. +All `AuthenticationProvider` instances included with the security architecture use `SimpleGrantedAuthority` to populate the `Authentication` object. [[authz-pre-invocation]] == Pre-Invocation Handling -Spring Security provides interceptors which control access to secure objects such as method invocations or web requests. +Spring Security provides interceptors that control access to secure objects, such as method invocations or web requests. A pre-invocation decision on whether the invocation is allowed to proceed is made by the `AccessDecisionManager`. @@ -44,6 +44,7 @@ A pre-invocation decision on whether the invocation is allowed to proceed is mad The `AccessDecisionManager` is called by the `AbstractSecurityInterceptor` and is responsible for making final access control decisions. The `AccessDecisionManager` interface contains three methods: +==== [source,java] ---- void decide(Authentication authentication, Object secureObject, @@ -53,32 +54,34 @@ boolean supports(ConfigAttribute attribute); boolean supports(Class clazz); ---- +==== -The ``AccessDecisionManager``'s `decide` method is passed all the relevant information it needs in order to make an authorization decision. -In particular, passing the secure `Object` enables those arguments contained in the actual secure object invocation to be inspected. -For example, let's assume the secure object was a `MethodInvocation`. -It would be easy to query the `MethodInvocation` for any `Customer` argument, and then implement some sort of security logic in the `AccessDecisionManager` to ensure the principal is permitted to operate on that customer. +The `decide` method of the `AccessDecisionManager` is passed all the relevant information it needs to make an authorization decision. +In particular, passing the secure `Object` lets those arguments contained in the actual secure object invocation be inspected. +For example, assume the secure object is a `MethodInvocation`. +You can query the `MethodInvocation` for any `Customer` argument and then implement some sort of security logic in the `AccessDecisionManager` to ensure the principal is permitted to operate on that customer. Implementations are expected to throw an `AccessDeniedException` if access is denied. The `supports(ConfigAttribute)` method is called by the `AbstractSecurityInterceptor` at startup time to determine if the `AccessDecisionManager` can process the passed `ConfigAttribute`. -The `supports(Class)` method is called by a security interceptor implementation to ensure the configured `AccessDecisionManager` supports the type of secure object that the security interceptor will present. +The `supports(Class)` method is called by a security interceptor implementation to ensure the configured `AccessDecisionManager` supports the type of secure object that the security interceptor presents. [[authz-voting-based]] === Voting-Based AccessDecisionManager Implementations -Whilst users can implement their own `AccessDecisionManager` to control all aspects of authorization, Spring Security includes several `AccessDecisionManager` implementations that are based on voting. -<> illustrates the relevant classes. +While users can implement their own `AccessDecisionManager` to control all aspects of authorization, Spring Security includes several `AccessDecisionManager` implementations that are based on voting. +<> describes the relevant classes. + +The following image shows the `AccessDecisionManager` interface: [[authz-access-voting]] .Voting Decision Manager image::images/access-decision-voting.png[] - - -Using this approach, a series of `AccessDecisionVoter` implementations are polled on an authorization decision. +By using this approach, a series of `AccessDecisionVoter` implementations are polled on an authorization decision. The `AccessDecisionManager` then decides whether or not to throw an `AccessDeniedException` based on its assessment of the votes. The `AccessDecisionVoter` interface has three methods: +==== [source,java] ---- int vote(Authentication authentication, Object object, Collection attrs); @@ -87,87 +90,88 @@ boolean supports(ConfigAttribute attribute); boolean supports(Class clazz); ---- +==== -Concrete implementations return an `int`, with possible values being reflected in the `AccessDecisionVoter` static fields `ACCESS_ABSTAIN`, `ACCESS_DENIED` and `ACCESS_GRANTED`. -A voting implementation will return `ACCESS_ABSTAIN` if it has no opinion on an authorization decision. +Concrete implementations return an `int`, with possible values being reflected in the `AccessDecisionVoter` static fields named `ACCESS_ABSTAIN`, `ACCESS_DENIED` and `ACCESS_GRANTED`. +A voting implementation returns `ACCESS_ABSTAIN` if it has no opinion on an authorization decision. If it does have an opinion, it must return either `ACCESS_DENIED` or `ACCESS_GRANTED`. -There are three concrete `AccessDecisionManager` s provided with Spring Security that tally the votes. -The `ConsensusBased` implementation will grant or deny access based on the consensus of non-abstain votes. +There are three concrete `AccessDecisionManager` implementations provided with Spring Security to tally the votes. +The `ConsensusBased` implementation grants or denies access based on the consensus of non-abstain votes. Properties are provided to control behavior in the event of an equality of votes or if all votes are abstain. -The `AffirmativeBased` implementation will grant access if one or more `ACCESS_GRANTED` votes were received (i.e. a deny vote will be ignored, provided there was at least one grant vote). +The `AffirmativeBased` implementation grants access if one or more `ACCESS_GRANTED` votes were received (in other words, a deny vote will be ignored, provided there was at least one grant vote). Like the `ConsensusBased` implementation, there is a parameter that controls the behavior if all voters abstain. The `UnanimousBased` provider expects unanimous `ACCESS_GRANTED` votes in order to grant access, ignoring abstains. -It will deny access if there is any `ACCESS_DENIED` vote. -Like the other implementations, there is a parameter that controls the behaviour if all voters abstain. +It denies access if there is any `ACCESS_DENIED` vote. +Like the other implementations, there is a parameter that controls the behavior if all voters abstain. -It is possible to implement a custom `AccessDecisionManager` that tallies votes differently. -For example, votes from a particular `AccessDecisionVoter` might receive additional weighting, whilst a deny vote from a particular voter may have a veto effect. +You can implement a custom `AccessDecisionManager` that tallies votes differently. +For example, votes from a particular `AccessDecisionVoter` might receive additional weighting, while a deny vote from a particular voter may have a veto effect. [[authz-role-voter]] ==== RoleVoter -The most commonly used `AccessDecisionVoter` provided with Spring Security is the simple `RoleVoter`, which treats configuration attributes as simple role names and votes to grant access if the user has been assigned that role. +The most commonly used `AccessDecisionVoter` provided with Spring Security is the `RoleVoter`, which treats configuration attributes as role names and votes to grant access if the user has been assigned that role. -It will vote if any `ConfigAttribute` begins with the prefix `ROLE_`. -It will vote to grant access if there is a `GrantedAuthority` which returns a `String` representation (via the `getAuthority()` method) exactly equal to one or more `ConfigAttributes` starting with the prefix `ROLE_`. -If there is no exact match of any `ConfigAttribute` starting with `ROLE_`, the `RoleVoter` will vote to deny access. -If no `ConfigAttribute` begins with `ROLE_`, the voter will abstain. +It votes if any `ConfigAttribute` begins with the `ROLE_` prefix. +It votes to grant access if there is a `GrantedAuthority` that returns a `String` representation (from the `getAuthority()` method) exactly equal to one or more `ConfigAttributes` that start with the `ROLE_` prefix. +If there is no exact match of any `ConfigAttribute` starting with `ROLE_`, `RoleVoter` votes to deny access. +If no `ConfigAttribute` begins with `ROLE_`, the voter abstains. [[authz-authenticated-voter]] ==== AuthenticatedVoter -Another voter which we've implicitly seen is the `AuthenticatedVoter`, which can be used to differentiate between anonymous, fully-authenticated and remember-me authenticated users. -Many sites allow certain limited access under remember-me authentication, but require a user to confirm their identity by logging in for full access. - -When we've used the attribute `IS_AUTHENTICATED_ANONYMOUSLY` to grant anonymous access, this attribute was being processed by the `AuthenticatedVoter`. -See the Javadoc for this class for more information. +Another voter which we have implicitly seen is the `AuthenticatedVoter`, which can be used to differentiate between anonymous, fully-authenticated, and remember-me authenticated users. +Many sites allow certain limited access under remember-me authentication but require a user to confirm their identity by logging in for full access. +When we have used the `IS_AUTHENTICATED_ANONYMOUSLY` attribute to grant anonymous access, this attribute was being processed by the `AuthenticatedVoter`. +For more information, see +{security-api-url}org/springframework/security/access/vote/AuthenticatedVoter.html[`AuthenticatedVoter`]. [[authz-custom-voter]] ==== Custom Voters -Obviously, you can also implement a custom `AccessDecisionVoter` and you can put just about any access-control logic you want in it. +You can also implement a custom `AccessDecisionVoter` and put just about any access-control logic you want in it. It might be specific to your application (business-logic related) or it might implement some security administration logic. -For example, you'll find a https://spring.io/blog/2009/01/03/spring-security-customization-part-2-adjusting-secured-session-in-real-time[blog article] on the Spring web site which describes how to use a voter to deny access in real-time to users whose accounts have been suspended. +For example, on the Spring web site, you can find a https://spring.io/blog/2009/01/03/spring-security-customization-part-2-adjusting-secured-session-in-real-time[blog article] that describes how to use a voter to deny access in real-time to users whose accounts have been suspended. [[authz-after-invocation-handling]] == After Invocation Handling -Whilst the `AccessDecisionManager` is called by the `AbstractSecurityInterceptor` before proceeding with the secure object invocation, some applications need a way of modifying the object actually returned by the secure object invocation. -Whilst you could easily implement your own AOP concern to achieve this, Spring Security provides a convenient hook that has several concrete implementations that integrate with its ACL capabilities. +While the `AccessDecisionManager` is called by the `AbstractSecurityInterceptor` before proceeding with the secure object invocation, some applications need a way to modify the object actually returned by the secure object invocation. +While you could implement your own AOP concern to achieve this, Spring Security provides a convenient hook that has several concrete implementations that integrate with its ACL capabilities. -<> illustrates Spring Security's `AfterInvocationManager` and its concrete implementations. +<> describes Spring Security's `AfterInvocationManager` and its concrete implementations. +The following image shows the `AfterInvocationManager`: [[authz-after-invocation]] .After Invocation Implementation image::images/after-invocation.png[] -Like many other parts of Spring Security, `AfterInvocationManager` has a single concrete implementation, `AfterInvocationProviderManager`, which polls a list of `AfterInvocationProvider` s. +Like many other parts of Spring Security, `AfterInvocationManager` has a single concrete implementation, `AfterInvocationProviderManager`, which polls a list of `AfterInvocationProvider` instances. Each `AfterInvocationProvider` is allowed to modify the return object or throw an `AccessDeniedException`. -Indeed multiple providers can modify the object, as the result of the previous provider is passed to the next in the list. +Indeed, multiple providers can modify the object, as the result of the previous provider is passed to the next in the list. -Please be aware that if you're using `AfterInvocationManager`, you will still need configuration attributes that allow the ``MethodSecurityInterceptor``'s `AccessDecisionManager` to allow an operation. -If you're using the typical Spring Security included `AccessDecisionManager` implementations, having no configuration attributes defined for a particular secure method invocation will cause each `AccessDecisionVoter` to abstain from voting. -In turn, if the `AccessDecisionManager` property "`allowIfAllAbstainDecisions`" is `false`, an `AccessDeniedException` will be thrown. -You may avoid this potential issue by either (i) setting "`allowIfAllAbstainDecisions`" to `true` (although this is generally not recommended) or (ii) simply ensure that there is at least one configuration attribute that an `AccessDecisionVoter` will vote to grant access for. +Note that, if you use `AfterInvocationManager`, you still need configuration attributes to let the `AccessDecisionManager` of the `MethodSecurityInterceptor` allow an operation. +If you use the typical Spring Security `AccessDecisionManager` implementations, having no configuration attributes defined for a particular secure method invocation causes each `AccessDecisionVoter` to abstain from voting. +In turn, if the `allowIfAllAbstainDecisions` property of `AccessDecisionManager` is `false`, an `AccessDeniedException` is thrown. +You may avoid this potential issue by either (i) setting `allowIfAllAbstainDecisions` to `true` (although this is generally not recommended) or (ii) ensuring that there is at least one configuration attribute for which an `AccessDecisionVoter` votes to grant access. This latter (recommended) approach is usually achieved through a `ROLE_USER` or `ROLE_AUTHENTICATED` configuration attribute. [[authz-hierarchical-roles]] == Hierarchical Roles -It is a common requirement that a particular role in an application should automatically "include" other roles. +It is a common requirement that a particular role in an application should automatically "`include`" other roles. For example, in an application which has the concept of an "admin" and a "user" role, you may want an admin to be able to do everything a normal user can. -To achieve this, you can either make sure that all admin users are also assigned the "user" role. -Alternatively, you can modify every access constraint which requires the "user" role to also include the "admin" role. -This can get quite complicated if you have a lot of different roles in your application. +To achieve this, you can either make sure that all admin users are also assigned the "`user`" role or you can modify every access constraint which requires the "`user`" role to also include the "`admin`" role. +This can get complicated if you have a lot of different roles in your application. -The use of a role-hierarchy allows you to configure which roles (or authorities) should include others. -An extended version of Spring Security's <>, `RoleHierarchyVoter`, is configured with a `RoleHierarchy`, from which it obtains all the "reachable authorities" which the user is assigned. -A typical configuration might look like this: +The use of a role-hierarchy lets you configure which roles (or authorities) should include others. +An extended version of Spring Security's <>, `RoleHierarchyVoter`, is configured with a `RoleHierarchy`, from which it obtains all the "`reachable authorities`" that the user is assigned. +The following example shows a typical configuration: +==== [source,xml] ---- - @@ -182,10 +186,11 @@ A typical configuration might look like this: ---- +==== -Here we have four roles in a hierarchy `ROLE_ADMIN => ROLE_STAFF => ROLE_USER => ROLE_GUEST`. -A user who is authenticated with `ROLE_ADMIN`, will behave as if they have all four roles when security constraints are evaluated against an `AccessDecisionManager` configured with the above `RoleHierarchyVoter`. -The `>` symbol can be thought of as meaning "includes". +Here, we have four roles in a hierarchy `ROLE_ADMIN => ROLE_STAFF => ROLE_USER => ROLE_GUEST`. +A user who is authenticated with `ROLE_ADMIN` behaves as if they have all four roles when security constraints are evaluated against an `AccessDecisionManager` configured with the preceding `RoleHierarchyVoter`. +The `>` symbol can be thought of as meaning "`includes`". -Role hierarchies offer a convenient means of simplifying the access-control configuration data for your application and/or reducing the number of authorities which you need to assign to a user. -For more complex requirements you may wish to define a logical mapping between the specific access-rights your application requires and the roles that are assigned to users, translating between the two when loading the user information. +Role hierarchies offer a convenient means of simplifying the access-control configuration data for your application and reducing the number of authorities that you need to assign to a user. +For more complex requirements, you may wish to define a logical mapping between the specific access-rights your application requires and the roles that are assigned to users, translating between the two when loading the user information. diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authorization/authorize-requests.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authorization/authorize-requests.adoc index 31ce88ecee4..48ad3a3e158 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/authorization/authorize-requests.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authorization/authorize-requests.adoc @@ -3,27 +3,28 @@ :figures: images/servlet/authorization :icondir: images/icons -This section builds on <> by digging deeper into how <> works within Servlet based applications. +This section builds on <> by digging deeper into how <> works within Servlet-based applications. -The {security-api-url}org/springframework/security/web/access/intercept/FilterSecurityInterceptor.html[`FilterSecurityInterceptor`] provides <> for ``HttpServletRequest``s. +The {security-api-url}org/springframework/security/web/access/intercept/FilterSecurityInterceptor.html[`FilterSecurityInterceptor`] provides <> for `HttpServletRequest` instances. It is inserted into the <> as one of the <>. +The following image shows the role of `FilterSecurityInterceptor`: + .Authorize HttpServletRequest image::{figures}/filtersecurityinterceptor.png[] -* image:{icondir}/number_1.png[] First, the `FilterSecurityInterceptor` obtains an <> from the <>. -* image:{icondir}/number_2.png[] Second, `FilterSecurityInterceptor` creates a {security-api-url}org/springframework/security/web/FilterInvocation.html[`FilterInvocation`] from the `HttpServletRequest`, `HttpServletResponse`, and `FilterChain` that are passed into the `FilterSecurityInterceptor`. -// FIXME: link to FilterInvocation -* image:{icondir}/number_3.png[] Next, it passes the `FilterInvocation` to `SecurityMetadataSource` to get the ``ConfigAttribute``s. -* image:{icondir}/number_4.png[] Finally, it passes the `Authentication`, `FilterInvocation`, and ``ConfigAttribute``s to the `AccessDecisionManager`. -** image:{icondir}/number_5.png[] If authorization is denied, an `AccessDeniedException` is thrown. -In this case the <> handles the `AccessDeniedException`. -** image:{icondir}/number_6.png[] If access is granted, `FilterSecurityInterceptor` continues with the <> which allows the application to process normally. +image:{icondir}/number_1.png[] The `FilterSecurityInterceptor` obtains an <> from the <>. +image:{icondir}/number_2.png[] `FilterSecurityInterceptor` creates a {security-api-url}org/springframework/security/web/FilterInvocation.html[`FilterInvocation`] from the `HttpServletRequest`, `HttpServletResponse`, and `FilterChain` that are passed into the `FilterSecurityInterceptor`. +image:{icondir}/number_3.png[] It passes the `FilterInvocation` to `SecurityMetadataSource` to get the ``ConfigAttribute``s. +image:{icondir}/number_4.png[] It passes the `Authentication`, `FilterInvocation`, and ``ConfigAttribute``s to the `AccessDecisionManager`. +image:{icondir}/number_5.png[] If authorization is denied, an `AccessDeniedException` is thrown. +In this case, the <> handles the `AccessDeniedException`. +image:{icondir}/number_6.png[] If access is granted, `FilterSecurityInterceptor` continues with the <>, which lets the application process normally. // configuration (xml/java) -By default, Spring Security's authorization will require all requests to be authenticated. -The explicit configuration looks like: +By default, Spring Security's authorization requires all requests to be authenticated. +The following listing shows the explicit configuration: .Every Request Must be Authenticated ==== @@ -62,7 +63,7 @@ fun configure(http: HttpSecurity) { ---- ==== -We can configure Spring Security to have different rules by adding more rules in order of precedence. +We can configure Spring Security to have different rules by adding more rules in order of precedence: .Authorize Requests ==== @@ -115,13 +116,13 @@ fun configure(http: HttpSecurity) { } ---- ==== -<1> There are multiple authorization rules specified. -Each rule is considered in the order they were declared. -<2> We specified multiple URL patterns that any user can access. -Specifically, any user can access a request if the URL starts with "/resources/", equals "/signup", or equals "/about". -<3> Any URL that starts with "/admin/" will be restricted to users who have the role "ROLE_ADMIN". -You will notice that since we are invoking the `hasRole` method we do not need to specify the "ROLE_" prefix. -<4> Any URL that starts with "/db/" requires the user to have both "ROLE_ADMIN" and "ROLE_DBA". -You will notice that since we are using the `hasRole` expression we do not need to specify the "ROLE_" prefix. -<5> Any URL that has not already been matched on is denied access. +<1> Multiple authorization rules are specified. +Each rule is considered in the order in which it is declared. +<2> Specify multiple URL patterns that any user can access. +Specifically, any user can access a request if the URL starts with `/resources/`, equals `/signup`, or equals `/about`. +<3> Any URL that starts with `/admin/` is restricted to users who have the `ROLE_ADMIN` role. +Notice that, since we invoke the `hasRole` method, we need not specify the `ROLE_` prefix. +<4> Any URL that starts with `/db/` requires the user to have both `ROLE_ADMIN` and `ROLE_DBA`. +Notice that, since we use the `hasRole` expression, we need not specify the `ROLE_` prefix. +<5> Any URL that has not already been matched is denied access. This is a good strategy if you do not want to accidentally forget to update your authorization rules. diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authorization/expression-based.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authorization/expression-based.adoc index 76d5f0ae5ac..a9f15822f6f 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/authorization/expression-based.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authorization/expression-based.adoc @@ -1,20 +1,20 @@ [[el-access]] == 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 seen before. -Expression-based access control is built on the same architecture but allows complicated Boolean logic to be encapsulated in a single expression. +Spring Security 3.0 introduced the ability to use Spring Expression Language (SpEL) expressions as an authorization mechanism in addition to the existing configuration attributes and access-decision voters. +Expression-based access control is built on the same architecture but lets complicated Boolean logic be encapsulated in a single expression. === 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. +Spring Security uses SpEL 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 to provide built-in expressions and access to values, such as the current principal. [[el-common-built-in]] ==== 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. +This provides some common expressions that are available in both web and method security: [[common-expressions]] .Common built-in expressions @@ -24,95 +24,94 @@ This provides some common expressions which are available in both web and method | `hasRole(String role)` | Returns `true` if the current principal has the specified role. -For example, `hasRole('admin')` +Example: `hasRole('admin')` -By default if the supplied role does not start with 'ROLE_' it will be added. -This can be customized by modifying the `defaultRolePrefix` on `DefaultWebSecurityExpressionHandler`. +By default, if the supplied role does not start with `ROLE_`, it is added. +You can customize this behavior by modifying the `defaultRolePrefix` on `DefaultWebSecurityExpressionHandler`. | `hasAnyRole(String... roles)` | Returns `true` if the current principal has any of the supplied roles (given as a comma-separated list of strings). -For example, `hasAnyRole('admin', 'user')` +Example: `hasAnyRole('admin', 'user')`. -By default if the supplied role does not start with 'ROLE_' it will be added. -This can be customized by modifying the `defaultRolePrefix` on `DefaultWebSecurityExpressionHandler`. +By default, if the supplied role does not start with `ROLE_`, it is added. +You can customize this behavior by modifying the `defaultRolePrefix` on `DefaultWebSecurityExpressionHandler`. | `hasAuthority(String authority)` | Returns `true` if the current principal has the specified authority. -For example, `hasAuthority('read')` +Example: `hasAuthority('read')` | `hasAnyAuthority(String... authorities)` -| Returns `true` if the current principal has any of the supplied authorities (given as a comma-separated list of strings) +| Returns `true` if the current principal has any of the supplied authorities (given as a comma-separated list of strings). -For example, `hasAnyAuthority('read', 'write')` +Example: `hasAnyAuthority('read', 'write')`. | `principal` -| Allows direct access to the principal object representing the current user +| Allows direct access to the principal object that represents the current user. | `authentication` -| Allows direct access to the current `Authentication` object obtained from the `SecurityContext` +| Allows direct access to the current `Authentication` object obtained from the `SecurityContext`. | `permitAll` -| Always evaluates to `true` +| Always evaluates to `true`. | `denyAll` -| Always evaluates to `false` +| Always evaluates to `false`. | `isAnonymous()` -| Returns `true` if the current principal is an anonymous user +| Returns `true` if the current principal is an anonymous user. | `isRememberMe()` -| Returns `true` if the current principal is a remember-me user +| Returns `true` if the current principal is a remember-me user. | `isAuthenticated()` -| Returns `true` if the user is not anonymous +| Returns `true` if the user is not anonymous. | `isFullyAuthenticated()` -| Returns `true` if the user is not an anonymous or a remember-me user +| Returns `true` if the user is not an anonymous and is not a remember-me user. | `hasPermission(Object target, Object permission)` | Returns `true` if the user has access to the provided target for the given permission. -For example, `hasPermission(domainObject, 'read')` +Example, `hasPermission(domainObject, 'read')`. | `hasPermission(Object targetId, String targetType, Object permission)` | Returns `true` if the user has access to the provided target for the given permission. -For example, `hasPermission(1, 'com.example.domain.Message', 'read')` +Example, `hasPermission(1, 'com.example.domain.Message', 'read')`. |=== - [[el-access-web]] === Web Security Expressions -To use expressions to secure individual URLs, you would first need to set the `use-expressions` attribute in the `` element to `true`. -Spring Security will then expect the `access` attributes of the `` elements to contain Spring EL expressions. -The expressions should evaluate to a Boolean, defining whether access should be allowed or not. -For example: +To use expressions to secure individual URLs, you first need to set the `use-expressions` attribute in the `` element to `true`. +Spring Security then expects the `access` attributes of the `` elements to contain SpEL expressions. +Each expression should evaluate to a Boolean, defining whether access should be allowed or not. +The following listing shows an example: +==== [source,xml] ---- - ... - ---- +==== -Here we have defined that the "admin" area of an application (defined by the URL pattern) should only be available to users who have the granted authority "admin" and whose IP address matches a local subnet. -We've already seen the built-in `hasRole` expression in the previous section. -The expression `hasIpAddress` is an additional built-in expression which is specific to web security. +Here, we have defined that the `admin` area of an application (defined by the URL pattern) should be available only to users who have the granted authority (`admin`) and whose IP address matches a local subnet. +We have already seen the built-in `hasRole` expression in the previous section. +The `hasIpAddress` expression is an additional built-in expression that is specific to web security. It is defined by the `WebSecurityExpressionRoot` class, an instance of which is used as the expression root object when evaluating web-access expressions. -This object also directly exposed the `HttpServletRequest` object under the name `request` so you can invoke the request directly in an expression. -If expressions are being used, a `WebExpressionVoter` will be added to the `AccessDecisionManager` which is used by the namespace. -So if you aren't using the namespace and want to use expressions, you will have to add one of these to your configuration. +This object also directly exposed the `HttpServletRequest` object under the name `request` so that you can invoke the request directly in an expression. +If expressions are being used, a `WebExpressionVoter` is added to the `AccessDecisionManager` that is used by the namespace. +So, if you do not use the namespace and want to use expressions, you have to add one of these to your configuration. [[el-access-web-beans]] ==== 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: +For example, you could use the following, assuming you have a Bean with the name of `webSecurity` that contains the following method signature: ==== .Java @@ -136,7 +135,7 @@ class WebSecurity { ---- ==== -You could refer to the method using: +You could then refer to the method as follows: .Refer to method ==== @@ -174,11 +173,11 @@ http { [[el-access-web-path-variables]] ==== 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}+`. +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 a URL path in a format of `+/user/{userId}+`. You can easily refer to the path variable by placing it in the pattern. -For example, if you had a Bean with the name of `webSecurity` that contains the following method signature: +For example, you could use the following if you had a Bean with the name of `webSecurity` that contains the following method signature: ==== .Java @@ -202,7 +201,7 @@ class WebSecurity { ---- ==== -You could refer to the method using: +You could then refer to the method as follows: .Path Variables ==== @@ -237,28 +236,30 @@ 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`. +In this configuration, URLs that match would pass in the path variable (and convert it) into the `checkUserId` method. +For example, if the URL were `/user/123/resource`, the ID passed in would be `123`. === 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. +Spring Security 3.0 introduced some new annotations to allow comprehensive support for the use of expressions. [[el-pre-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`. +There are four annotations that 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: +==== [source,xml] ---- ---- +==== ===== 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 "Contacts" sample application) +The most obviously useful annotation is `@PreAuthorize`, which decides whether a method can actually be invoked or not. +The following example (from the "Contacts" sample application) uses the `@PreAuthorize` annotation: ==== .Java @@ -276,9 +277,9 @@ fun create(contact: Contact?) ---- ==== -which means that access will only be allowed for users with the role "ROLE_USER". -Obviously the same thing could easily be achieved using a traditional configuration and a simple configuration attribute for the required role. -But what about: +This means that access is allowed only for users with the `ROLE_USER` role. +Obviously, the same thing could easily be achieved by using a traditional configuration and a simple configuration attribute for the required role. +However, consider the following example: ==== .Java @@ -296,20 +297,18 @@ fun deletePermission(contact: Contact?, recipient: Sid?, permission: Permission? ---- ==== -Here we're actually using a method argument as part of the expression to decide whether the current user has the "admin"permission for the given contact. -The built-in `hasPermission()` expression is linked into the Spring Security ACL module through the application context, as we'll <>. +Here, we actually use a method argument as part of the expression to decide whether the current user has the `admin` permission for the given contact. +The built-in `hasPermission()` expression is linked into the Spring Security ACL module through the application context, as we <>. You can access any of the method arguments by name as expression variables. -There are a number of ways in which Spring Security can resolve the method arguments. +Spring Security can resolve the method arguments in a number of ways. Spring Security uses `DefaultSecurityParameterNameDiscoverer` to discover the parameter names. -By default, the following options are tried for a method as a whole. - -* If Spring Security's `@P` annotation is present on a single argument to the method, the value will be used. -This is useful for interfaces compiled with a JDK prior to JDK 8 which do not contain any information about the parameter names. -For example: +By default, the following options are tried for a method. +* If Spring Security's `@P` annotation is present on a single argument to the method, the value is used. +This is useful for interfaces compiled with a JDK prior to JDK 8 (which do not contain any information about the parameter names). +The following example uses the `@P` annotation: + - ==== .Java [source,java,role="primary"] @@ -333,17 +332,13 @@ import org.springframework.security.access.method.P fun doSomething(@P("c") contact: Contact?) ---- ==== - + +Behind the scenes, this is implemented by using `AnnotationParameterNameDiscoverer`, which you can customize to support the value attribute of any specified annotation. -Behind the scenes this is implemented using `AnnotationParameterNameDiscoverer` which can be customized to support the value attribute of any specified annotation. - -* If Spring Data's `@Param` annotation is present on at least one parameter for the method, the value will be used. +* If Spring Data's `@Param` annotation is present on at least one parameter for the method, the value is used. This is useful for interfaces compiled with a JDK prior to JDK 8 which do not contain any information about the parameter names. -For example: - +The following example uses the `@Param` annotation: + - ==== .Java [source,java,role="primary"] @@ -367,23 +362,19 @@ import org.springframework.data.repository.query.Param fun findContactByName(@Param("n") name: String?): Contact? ---- ==== - + +Behind the scenes, this is implemented by using `AnnotationParameterNameDiscoverer`, which you can customize to support the value attribute of any specified annotation. -Behind the scenes this is implemented using `AnnotationParameterNameDiscoverer` which can be customized to support the value attribute of any specified annotation. - -* If JDK 8 was used to compile the source with the -parameters argument and Spring 4+ is being used, then the standard JDK reflection API is used to discover the parameter names. +* If JDK 8 was used to compile the source with the `-parameters` argument and Spring 4+ is being used, the standard JDK reflection API is used to discover the parameter names. This works on both classes and interfaces. -* Last, if the code was compiled with the debug symbols, the parameter names will be discovered using the debug symbols. -This will not work for interfaces since they do not have debug information about the parameter names. +* Finally, if the code was compiled with the debug symbols, the parameter names are discovered by using the debug symbols. +This does not work for interfaces, since they do not have debug information about the parameter names. For interfaces, annotations or the JDK 8 approach must be used. .[[el-pre-post-annotations-spel]] --- -Any Spring-EL functionality is available within the expression, so you can also access properties on the arguments. -For example, if you wanted a particular method to only allow access to a user whose username matched that of the contact, you could write --- +Any SpEL functionality is available within the expression, so you can also access properties on the arguments. +For example, if you wanted a particular method to allow access only to a user whose username matched that of the contact, you could write ==== .Java @@ -401,21 +392,19 @@ fun doSomething(contact: Contact?) ---- ==== -Here we are accessing another built-in expression, `authentication`, which is the `Authentication` stored in the security context. -You can also access its "principal" property directly, using the expression `principal`. -The value will often be a `UserDetails` instance, so you might use an expression like `principal.username` or `principal.enabled`. +Here, we access another built-in expression, `authentication`, which is the `Authentication` stored in the security context. +You can also access its `principal` property directly, by using the `principal` expression. +The value is often a `UserDetails` instance, so you might use an expression such as `principal.username` or `principal.enabled`. .[[el-pre-post-annotations-post]] --- Less commonly, you may wish to perform an access-control check after the method has been invoked. -This can be achieved using the `@PostAuthorize` annotation. +You can do so by 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 -Spring Security supports filtering of collections, arrays, maps and streams using expressions. +Spring Security supports filtering of collections, arrays, maps, and streams by using expressions. This is most commonly performed on the return value of a method. -For example: +The following example uses `@PostFilter`: ==== .Java @@ -436,29 +425,30 @@ fun getAll(): List ==== When using the `@PostFilter` annotation, Spring Security iterates through the returned collection or map and removes any elements for which the supplied expression is false. -For an array, a new array instance will be returned containing filtered elements. -The name `filterObject` refers to the current object in the collection. -In case when a map is used it will refer to the current `Map.Entry` object which allows one to use `filterObject.key` or `filterObject.value` in the expresion. -You can also filter before the method call, using `@PreFilter`, though this is a less common requirement. -The syntax is just the same, but if there is more than one argument which is a collection type then you have to select one by name using the `filterTarget` property of this annotation. +For an array, a new array instance that contains filtered elements is returned. +`filterObject` refers to the current object in the collection. +When a map is used, it refers to the current `Map.Entry` object, which lets you use `filterObject.key` or `filterObject.value` in the expression. +You can also filter before the method call by using `@PreFilter`, though this is a less common requirement. +The syntax is the same. However, if there is more than one argument that is a collection type, you have to select one by name using the `filterTarget` property of this annotation. Note that filtering is obviously not a substitute for tuning your data retrieval queries. -If you are filtering large collections and removing many of the entries then this is likely to be inefficient. +If you are filtering large collections and removing many of the entries, this is likely to be inefficient. [[el-method-built-in]] ==== Built-In Expressions -There are some built-in expressions which are specific to method security, which we have already seen in use above. +There are some built-in expressions that are specific to method security, which we have already seen in use earlier. 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 `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 is intended to bridge between the expression system and Spring Security's ACL system, letting you 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. The interface has two methods: +==== [source,java] ---- boolean hasPermission(Authentication authentication, Object targetDomainObject, @@ -467,17 +457,19 @@ boolean hasPermission(Authentication authentication, Object targetDomainObject, boolean hasPermission(Authentication authentication, Serializable targetId, String targetType, Object permission); ---- +==== -which map directly to the available versions of the expression, with the exception that the first argument (the `Authentication` object) is not supplied. +These methods map directly to the available versions of the expression, with the exception that the first argument (the `Authentication` object) is not supplied. The first is used in situations where the domain object, to which access is being controlled, is already loaded. -Then expression will return true if the current user has the given permission for that object. -The second version is used in cases where the object is not loaded, but its identifier is known. -An abstract "type" specifier for the domain object is also required, allowing the correct ACL permissions to be loaded. -This has traditionally been the Java class of the object, but does not have to be as long as it is consistent with how the permissions are loaded. +Then the expression returns `true` if the current user has the given permission for that object. +The second version is used in cases where the object is not loaded but its identifier is known. +An abstract "`type`" specifier for the domain object is also required, letting the correct ACL permissions be loaded. +This has traditionally been the Java class of the object but does not have to be, as long as it is consistent with how the permissions are loaded. To use `hasPermission()` expressions, you have to explicitly configure a `PermissionEvaluator` in your application context. -This would look something like this: +The following example shows how to do so: +==== [source,xml] ---- @@ -489,23 +481,26 @@ This would look something like this: ---- +==== Where `myPermissionEvaluator` is the bean which implements `PermissionEvaluator`. -Usually this will be the implementation from the ACL module which is called `AclPermissionEvaluator`. -See the "Contacts" sample application configuration for more details. +Usually, this is the implementation from the ACL module, which is called `AclPermissionEvaluator`. +See the "`Contacts`" sample application configuration for more details. ===== 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. +This is especially convenient if you find that you repeat the same complex expression throughout your code base. For example, consider the following: +==== [source,java] ---- @PreAuthorize("#contact.name == authentication.name") ---- +==== -Instead of repeating this everywhere, we can create a meta annotation that can be used instead. +Instead of repeating this everywhere, you can create a meta annotation: ==== .Java @@ -525,6 +520,5 @@ annotation class ContactPermission ---- ==== -Meta annotations can be used for any of the Spring Security method security annotations. -In order to remain compliant with the specification JSR-250 annotations do not support meta annotations. - +You can use meta annotations for any of the Spring Security method security annotations. +To remain compliant with the specification, JSR-250 annotations do not support meta annotations. diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authorization/index.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authorization/index.adoc index 2e4dfc59ace..d16b22ca153 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/authorization/index.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authorization/index.adoc @@ -1,10 +1,10 @@ [[servlet-authorization]] = Authorization The advanced authorization capabilities within Spring Security represent one of the most compelling reasons for its popularity. -Irrespective of how you choose to authenticate - whether using a Spring Security-provided mechanism and provider, or integrating with a container or other non-Spring Security authentication authority - you will find the authorization services can be used within your application in a consistent and simple way. +Irrespective of how you choose to authenticate (whether using a Spring Security-provided mechanism and provider or integrating with a container or other non-Spring Security authentication authority), the authorization services can be used within your application in a consistent and simple way. -In this part we'll explore the different `AbstractSecurityInterceptor` implementations, which were introduced in Part I. -We then move on to explore how to fine-tune authorization through use of domain access control lists. +In this part, we explore the different `AbstractSecurityInterceptor` implementations, which were introduced in Part I. +We then move on to explore how to fine-tune authorization through the use of domain access control lists. include::architecture.adoc[leveloffset=+1] @@ -17,4 +17,3 @@ include::secure-objects.adoc[] include::method-security.adoc[] include::acls.adoc[] - diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authorization/method-security.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authorization/method-security.adoc index a05b62dfc7a..859b5f27ce7 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/authorization/method-security.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authorization/method-security.adoc @@ -1,10 +1,10 @@ [[jc-method]] == Method Security -From version 2.0 onwards Spring Security has improved support substantially for adding security to your service layer methods. +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 <>. -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. +From 3.0, you can also make use of new <>. +You can apply security to a single bean, by using the `intercept-methods` element to decorate the bean declaration, or you can secure multiple beans across the entire service layer by using AspectJ style pointcuts. === EnableMethodSecurity @@ -600,9 +600,10 @@ and it will be invoked after the `@PostAuthorize` interceptor. [[jc-enable-global-method-security]] === 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. +We can enable annotation-based security by using the `@EnableGlobalMethodSecurity` annotation on any `@Configuration` instance. +The following example enables Spring Security's `@Secured` annotation: +==== [source,java] ---- @EnableGlobalMethodSecurity(securedEnabled = true) @@ -610,11 +611,13 @@ public class MethodSecurityConfig { // ... } ---- +==== Adding an annotation to a method (on a class or interface) would then limit the access to that method accordingly. Spring Security's native annotation support defines a set of attributes for the method. -These will be passed to the AccessDecisionManager for it to make the actual decision: +These are passed to the `AccessDecisionManager` for it to make the actual decision: +==== [source,java] ---- public interface BankService { @@ -629,9 +632,11 @@ public Account[] findAccounts(); public Account post(Account account, double amount); } ---- +==== -Support for JSR-250 annotations can be enabled using +Support for JSR-250 annotations can be enabled by using: +==== [source,java] ---- @EnableGlobalMethodSecurity(jsr250Enabled = true) @@ -639,10 +644,12 @@ public class MethodSecurityConfig { // ... } ---- +==== -These are standards-based and allow simple role-based constraints to be applied but do not have the power Spring Security's native annotations. -To use the new expression-based syntax, you would use +These are standards-based and let simple role-based constraints be applied but do not have the power Spring Security's native annotations. +To use the new expression-based syntax, you would use: +==== [source,java] ---- @EnableGlobalMethodSecurity(prePostEnabled = true) @@ -650,9 +657,11 @@ public class MethodSecurityConfig { // ... } ---- +==== -and the equivalent Java code would be +The equivalent Java code is: +==== [source,java] ---- public interface BankService { @@ -667,13 +676,15 @@ public Account[] findAccounts(); public Account post(Account account, double amount); } ---- +==== === 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. +Sometimes, you may need to perform operations that are more complicated than are possible with the `@EnableGlobalMethodSecurity` annotation. +For these instances, you can extend the `GlobalMethodSecurityConfiguration`, ensuring that the `@EnableGlobalMethodSecurity` annotation is present on your subclass. For example, if you wanted to provide a custom `MethodSecurityExpressionHandler`, you could use the following configuration: +==== [source,java] ---- @EnableGlobalMethodSecurity(prePostEnabled = true) @@ -685,24 +696,29 @@ public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration { } } ---- +==== -For additional information about methods that can be overridden, refer to the `GlobalMethodSecurityConfiguration` Javadoc. +For additional information about methods that can be overridden, see the Javadoc for the {security-api-url}org/springframework/security/config/annotation/method/configuration/GlobalMethodSecurityConfiguration.html[`GlobalMethodSecurityConfiguration`] class. [[ns-global-method]] === The 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. +This element is used to enable annotation-based security in your application (by setting the appropriate attributes on the element) and to group together security pointcut declarations that are applied across your entire application context. You should only declare one `` element. -The following declaration would enable support for Spring Security's `@Secured`: +The following declaration enables support for Spring Security's `@Secured`: +==== [source,xml] ---- ---- +==== -Adding an annotation to a method (on an class or interface) would then limit the access to that method accordingly. +Adding an annotation to a method (on a class or interface) would then limit the access to that method accordingly. Spring Security's native annotation support defines a set of attributes for the method. -These will be passed to the `AccessDecisionManager` for it to make the actual decision: +These are passed to the `AccessDecisionManager` for it to make the actual decision. +The following example shows the `@Secured` annotation in a typical interface: +==== [source,java] ---- public interface BankService { @@ -717,24 +733,30 @@ public Account[] findAccounts(); public Account post(Account account, double amount); } ---- +==== -Support for JSR-250 annotations can be enabled using +Support for JSR-250 annotations can be enabled by using: +==== [source,xml] ---- ---- +==== -These are standards-based and allow simple role-based constraints to be applied but do not have the power Spring Security's native annotations. -To use the new expression-based syntax, you would use +These are standards-based and allow simple role-based constraints to be applied, but they do not have the power Spring Security's native annotations. +To use the expression-based syntax, use: +==== [source,xml] ---- ---- +==== -and the equivalent Java code would be +The equivalent Java code is: +==== [source,java] ---- public interface BankService { @@ -749,27 +771,23 @@ public Account[] findAccounts(); public Account post(Account account, double amount); } ---- +==== Expression-based annotations are a good choice if you need to define simple rules that go beyond checking the role names against the user's list of authorities. -[NOTE] -==== -The annotated methods will only be secured for instances which are defined as Spring beans (in the same application context in which method-security is enabled). +NOTE: The annotated methods will only be secured for instances which are defined as Spring beans (in the same application context in which method-security is enabled). If you want to secure instances which are not created by Spring (using the `new` operator, for example) then you need to use AspectJ. -==== -[NOTE] -==== -You can enable more than one type of annotation in the same application, but only one type should be used for any interface or class as the behaviour will not be well-defined otherwise. +NOTE: You can enable more than one type of annotation in the same application, but only one type should be used for any interface or class as the behaviour will not be well-defined otherwise. If two annotations are found which apply to a particular method, then only one of them will be applied. -==== [[ns-protect-pointcut]] -=== Adding Security Pointcuts using protect-pointcut +=== Adding Security Pointcuts by 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. +`protect-pointcut` is particularly powerful, as it lets you apply security to many beans with only a simple declaration. Consider the following example: +==== [source,xml] ---- @@ -777,8 +795,9 @@ Consider the following example: access="ROLE_USER"/> ---- +==== -This will protect all methods on beans declared in the application context whose classes are in the `com.mycompany` package and whose class names end in "Service". -Only users with the `ROLE_USER` role will be able to invoke these methods. -As with URL matching, the most specific matches must come first in the list of pointcuts, as the first matching expression will be used. +This configuration protects all methods on beans declared in the application context whose classes are in the `com.mycompany` package and whose class names end in `Service`. +Only users with the `ROLE_USER` role can invoke these methods. +As with URL matching, the most specific matches must come first in the list of pointcuts, as the first matching expression is used. Security annotations take precedence over pointcuts. diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authorization/secure-objects.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authorization/secure-objects.adoc index 7370a4202ce..ebc9008e440 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/authorization/secure-objects.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authorization/secure-objects.adoc @@ -2,25 +2,27 @@ [[secure-object-impls]] == Secure Object Implementations +This section covers how Spring Security handles Secure Object implementations. + [[aop-alliance]] === AOP Alliance (MethodInvocation) Security Interceptor -Prior to Spring Security 2.0, securing `MethodInvocation` s needed quite a lot of boiler plate configuration. +Prior to Spring Security 2.0, securing `MethodInvocation` instances needed a lot of boiler plate configuration. Now the recommended approach for method security is to use <>. -This way the method security infrastructure beans are configured automatically for you so you don't really need to know about the implementation classes. -We'll just provide a quick overview of the classes that are involved here. +This way, the method security infrastructure beans are configured automatically for you, so you need not know about the implementation classes. +We provide only a quick overview of the classes that are involved here. -Method security is enforced using a `MethodSecurityInterceptor`, which secures `MethodInvocation` s. +Method security is enforced by using a `MethodSecurityInterceptor`, which secures `MethodInvocation` instances. Depending on the configuration approach, an interceptor may be specific to a single bean or shared between multiple beans. The interceptor uses a `MethodSecurityMetadataSource` instance to obtain the configuration attributes that apply to a particular method invocation. -`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 `` or `` elements. -Other implementations will be used to handle annotation-based configuration. +`MapBasedMethodSecurityMetadataSource` is used to store configuration attributes keyed by method names (which can be wildcarded) and is used internally when the attributes are defined in the application context by using the `` or `` elements. +Other implementations are used to handle annotation-based 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: +You can configure a `MethodSecurityInterceptor` directly in your application context for use with one of Spring AOP's proxying mechanisms: +==== [source,xml] ---- - @@ -34,22 +36,22 @@ You can of course configure a `MethodSecurityInterceptor` directly in your appli ---- +==== [[aspectj]] === 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. +We discuss only the differences in this section. The AspectJ interceptor is named `AspectJSecurityInterceptor`. -Unlike the AOP Alliance security interceptor, which relies on the Spring application context to weave in the security interceptor via proxying, the `AspectJSecurityInterceptor` is weaved in via the AspectJ compiler. +Unlike the AOP Alliance security interceptor, which relies on the Spring application context to weave in the security interceptor through proxying, the `AspectJSecurityInterceptor` is woven in through the AspectJ compiler. It would not be uncommon to use both types of security interceptors in the same application, with `AspectJSecurityInterceptor` being used for domain object instance security and the AOP Alliance `MethodSecurityInterceptor` being used for services layer security. -Let's first consider how the `AspectJSecurityInterceptor` is configured in the Spring application context: - +We first consider how the `AspectJSecurityInterceptor` is configured in the Spring application context: +==== [source,xml] ---- - @@ -63,19 +65,17 @@ Let's first consider how the `AspectJSecurityInterceptor` is configured in the S ---- - +==== As you can see, aside from the class name, the `AspectJSecurityInterceptor` is exactly the same as the AOP Alliance security interceptor. -Indeed the two interceptors can share the same `securityMetadataSource`, as the `SecurityMetadataSource` works with `java.lang.reflect.Method` s rather than an AOP library-specific class. -Of course, your access decisions have access to the relevant AOP library-specific invocation (ie `MethodInvocation` or `JoinPoint`) and as such can consider a range of addition criteria when making access decisions (such as method arguments). - -Next you'll need to define an AspectJ `aspect`. -For example: +The two interceptors can share the same `securityMetadataSource`, as the `SecurityMetadataSource` works with `java.lang.reflect.Method` instances rather than an AOP library-specific class. +Your access decisions have access to the relevant AOP library-specific invocation (`MethodInvocation` or `JoinPoint`) and can consider a range of additional criteria (such as method arguments) when making access decisions. +Next, you need to define an AspectJ `aspect`, as the following example shows: +==== [source,java] ---- - package org.springframework.security.samples.aspectj; import org.springframework.security.access.intercept.aspectj.AspectJSecurityInterceptor; @@ -118,16 +118,16 @@ public aspect DomainObjectInstanceSecurityAspect implements InitializingBean { } } ---- +==== - -In the above example, the security interceptor will be applied to every instance of `PersistableEntity`, which is an abstract class not shown (you can use any other class or `pointcut` expression you like). +In the preceding example, the security interceptor is applied to every instance of `PersistableEntity`, which is an abstract class not shown (you can use any other class or `pointcut` expression you like). For those curious, `AspectJCallback` is needed because the `proceed();` statement has special meaning only within an `around()` body. The `AspectJSecurityInterceptor` calls this anonymous `AspectJCallback` class when it wants the target object to continue. -You will need to configure Spring to load the aspect and wire it with the `AspectJSecurityInterceptor`. -A bean declaration which achieves this is shown below: - +You need to configure Spring to load the aspect and wire it with the `AspectJSecurityInterceptor`. +The following example shows a bean declaration that achieves this: +==== [source,xml] ---- @@ -137,7 +137,6 @@ A bean declaration which achieves this is shown below: ---- +==== - -That's it! -Now you can create your beans from anywhere within your application, using whatever means you think fit (e.g. `new Person();`) and they will have the security interceptor applied. +Now you can create your beans from anywhere within your application, using whatever means you think fit (e.g. `new Person();`), and they have the security interceptor applied. diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/crypto/index.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/crypto/index.adoc index 137b3e8b694..e5cd9f81e55 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/crypto/index.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/crypto/index.adoc @@ -3,21 +3,22 @@ [[spring-security-crypto-introduction]] -== Introduction The Spring Security Crypto module provides support for symmetric encryption, key generation, and password encoding. The code is distributed as part of the core module but has no dependencies on any other Spring Security (or Spring) code. [[spring-security-crypto-encryption]] == Encryptors -The Encryptors class provides factory methods for constructing symmetric encryptors. -Using this class, you can create ByteEncryptors to encrypt data in raw byte[] form. -You can also construct TextEncryptors to encrypt text strings. +The {security-api-url}org/springframework/security/crypto/encrypt/Encryptors.html[`Encryptors`] class provides factory methods for constructing symmetric encryptors. +This class lets you create {security-api-url}org/springframework/security/crypto/encrypt/BytesEncryptor.html[`BytesEncryptor`] instances to encrypt data in raw `byte[]` form. +You can also construct {security-api-url}org/springframework/security/crypto/encrypt/TextEncryptor.html[TextEncryptor] instances to encrypt text strings. Encryptors are thread-safe. +NOTE: Both `BytesEncryptor` and `TextEncryptor` are interfaces. `BytesEncryptor` has multiple implementations. + [[spring-security-crypto-encryption-bytes]] === BytesEncryptor -Use the `Encryptors.stronger` factory method to construct a BytesEncryptor: +YOu can use the `Encryptors.stronger` factory method to construct a `BytesEncryptor`: .BytesEncryptor ==== @@ -34,16 +35,16 @@ Encryptors.stronger("password", "salt") ---- ==== -The "stronger" encryption method creates an encryptor using 256 bit AES encryption with +The `stronger` encryption method creates an encryptor by using 256-bit AES encryption with Galois Counter Mode (GCM). -It derives the secret key using PKCS #5's PBKDF2 (Password-Based Key Derivation Function #2). +It derives the secret key by using PKCS #5's PBKDF2 (Password-Based Key Derivation Function #2). This method requires Java 6. -The password used to generate the SecretKey should be kept in a secure place and not be shared. -The salt is used to prevent dictionary attacks against the key in the event your encrypted data is compromised. -A 16-byte random initialization vector is also applied so each encrypted message is unique. +The password used to generate the `SecretKey` should be kept in a secure place and should not be shared. +The salt is used to prevent dictionary attacks against the key in the event that your encrypted data is compromised. +A 16-byte random initialization vector is also applied so that each encrypted message is unique. The provided salt should be in hex-encoded String form, be random, and be at least 8 bytes in length. -Such a salt may be generated using a KeyGenerator: +You can generate such a salt by using a `KeyGenerator`: .Generating a key ==== @@ -60,14 +61,14 @@ val salt = KeyGenerators.string().generateKey() // generates a random 8-byte sal ---- ==== -Users may also use the `standard` encryption method, which is 256-bit AES in Cipher Block Chaining (CBC) Mode. +You can also use the `standard` encryption method, which is 256-bit AES in Cipher Block Chaining (CBC) Mode. This mode is not https://en.wikipedia.org/wiki/Authenticated_encryption[authenticated] and does not provide any guarantees about the authenticity of the data. -For a more secure alternative, users should prefer `Encryptors.stronger`. +For a more secure alternative, use `Encryptors.stronger`. [[spring-security-crypto-encryption-text]] === TextEncryptor -Use the Encryptors.text factory method to construct a standard TextEncryptor: +You can use the `Encryptors.text` factory method to construct a standard TextEncryptor: .TextEncryptor ==== @@ -84,10 +85,10 @@ Encryptors.text("password", "salt") ---- ==== -A TextEncryptor uses a standard BytesEncryptor to encrypt text data. -Encrypted results are returned as hex-encoded strings for easy storage on the filesystem or in the database. +A `TextEncryptor` uses a standard `BytesEncryptor` to encrypt text data. +Encrypted results are returned as hex-encoded strings for easy storage on the filesystem or in a database. -Use the Encryptors.queryableText factory method to construct a "queryable" TextEncryptor: +You can use the `Encryptors.queryableText` factory method to construct a "`queryable`" `TextEncryptor`: .Queryable TextEncryptor ==== @@ -104,21 +105,21 @@ Encryptors.queryableText("password", "salt") ---- ==== -The difference between a queryable TextEncryptor and a standard TextEncryptor has to do with initialization vector (iv) handling. -The iv used in a queryable TextEncryptor#encrypt operation is shared, or constant, and is not randomly generated. -This means the same text encrypted multiple times will always produce the same encryption result. -This is less secure, but necessary for encrypted data that needs to be queried against. -An example of queryable encrypted text would be an OAuth apiKey. +The difference between a queryable `TextEncryptor` and a standard `TextEncryptor` has to do with initialization vector (IV) handling. +The IV used in a queryable `TextEncryptor.encrypt` operation is shared, or constant, and is not randomly generated. +This means the same text encrypted multiple times always produces the same encryption result. +This is less secure but necessary for encrypted data that needs to be queried against. +An example of queryable encrypted text would be an OAuth `apiKey`. [[spring-security-crypto-keygenerators]] == Key Generators -The KeyGenerators class provides a number of convenience factory methods for constructing different types of key generators. -Using this class, you can create a BytesKeyGenerator to generate byte[] keys. -You can also construct a StringKeyGenerator to generate string keys. -KeyGenerators are thread-safe. +The {security-api-url}org/springframework/security/crypto/keygen/KeyGenerators.html[`KeyGenerators`] class provides a number of convenience factory methods for constructing different types of key generators. +By using this class, you can create a {security-api-url}org/springframework/security/crypto/keygen/BytesKeyGenerator.html[`BytesKeyGenerator`] to generate `byte[]` keys. +You can also construct a {security-api-url}org/springframework/security/crypto/keygen/StringKeyGenerator.html`[StringKeyGenerator]` to generate string keys. +`KeyGenerators` is a thread-safe class. === BytesKeyGenerator -Use the KeyGenerators.secureRandom factory methods to generate a BytesKeyGenerator backed by a SecureRandom instance: +You can use the `KeyGenerators.secureRandom` factory methods to generate a `BytesKeyGenerator` backed by a `SecureRandom` instance: .BytesKeyGenerator ==== @@ -138,7 +139,7 @@ val key = generator.generateKey() ==== The default key length is 8 bytes. -There is also a KeyGenerators.secureRandom variant that provides control over the key length: +A `KeyGenerators.secureRandom` variant provides control over the key length: .KeyGenerators.secureRandom ==== @@ -155,7 +156,7 @@ KeyGenerators.secureRandom(16) ---- ==== -Use the KeyGenerators.shared factory method to construct a BytesKeyGenerator that always returns the same key on every invocation: +Use the `KeyGenerators.shared` factory method to construct a BytesKeyGenerator that always returns the same key on every invocation: .KeyGenerators.shared ==== @@ -173,7 +174,7 @@ KeyGenerators.shared(16) ==== === StringKeyGenerator -Use the KeyGenerators.string factory method to construct a 8-byte, SecureRandom KeyGenerator that hex-encodes each key as a String: +You can use the `KeyGenerators.string` factory method to construct an 8-byte, `SecureRandom` `KeyGenerator` that hex-encodes each key as a `String`: .StringKeyGenerator ==== @@ -192,9 +193,10 @@ KeyGenerators.string() [[spring-security-crypto-passwordencoders]] == Password Encoding -The password package of the spring-security-crypto module provides support for encoding passwords. +The password package of the `spring-security-crypto` module provides support for encoding passwords. `PasswordEncoder` is the central service interface and has the following signature: +==== [source,java] ---- public interface PasswordEncoder { @@ -204,16 +206,18 @@ String encode(String rawPassword); boolean matches(String rawPassword, String encodedPassword); } ---- +==== -The matches method returns true if the rawPassword, once encoded, equals the encodedPassword. +The `matches` method returns true if the `rawPassword`, once encoded, equals the `encodedPassword`. This method is designed to support password-based authentication schemes. -The `BCryptPasswordEncoder` implementation uses the widely supported "bcrypt" algorithm to hash the passwords. -Bcrypt uses a random 16 byte salt value and is a deliberately slow algorithm, in order to hinder password crackers. -The amount of work it does can be tuned using the "strength" parameter which takes values from 4 to 31. +The `BCryptPasswordEncoder` implementation uses the widely supported "`bcrypt`" algorithm to hash the passwords. +Bcrypt uses a random 16-byte salt value and is a deliberately slow algorithm, to hinder password crackers. +You can tune the amount of work it does by using the `strength` parameter, which takes a value from 4 to 31. The higher the value, the more work has to be done to calculate the hash. -The default value is 10. +The default value is `10`. You can change this value in your deployed system without affecting existing passwords, as the value is also stored in the encoded hash. +The following example uses the `BCryptPasswordEncoder`: .BCryptPasswordEncoder ==== @@ -239,8 +243,8 @@ assertTrue(encoder.matches("myPassword", result)) ==== The `Pbkdf2PasswordEncoder` implementation uses PBKDF2 algorithm to hash the passwords. -In order to defeat password cracking PBKDF2 is a deliberately slow algorithm and should be tuned to take about .5 seconds to verify a password on your system. - +To defeat password cracking, PBKDF2 is a deliberately slow algorithm and should be tuned to take about .5 seconds to verify a password on your system. +The following system uses the `Pbkdf2PasswordEncoder`: .Pbkdf2PasswordEncoder ==== diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/exploits/csrf.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/exploits/csrf.adoc index ec05a78fc0a..ca941c692f6 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/exploits/csrf.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/exploits/csrf.adoc @@ -7,33 +7,32 @@ This section discusses Spring Security's <> -* <> -* <> +* <> +* <> +* <> [[servlet-csrf-idempotent]] === Use proper HTTP verbs -The first step to protecting against CSRF attacks is to ensure your website uses proper HTTP verbs. +The first step to protecting against CSRF attacks is to ensure that your website uses proper HTTP verbs. This is covered in detail in <>. [[servlet-csrf-configure]] === Configure CSRF Protection The next step is to configure Spring Security's CSRF protection within your application. Spring Security's CSRF protection is enabled by default, but you may need to customize the configuration. -Below are a few common customizations. +The next few sections cover a few common customizations. [[servlet-csrf-configure-custom-repository]] ==== Custom CsrfTokenRepository -By default Spring Security stores the expected CSRF token in the `HttpSession` using `HttpSessionCsrfTokenRepository`. -There can be cases where users will want to configure a custom `CsrfTokenRepository`. -For example, it might be desirable to persist the `CsrfToken` in a cookie to <>. +By default, Spring Security stores the expected CSRF token in the `HttpSession` by using `HttpSessionCsrfTokenRepository`. +There can be cases where users want to configure a custom `CsrfTokenRepository`. +For example, it might be desirable to persist the `CsrfToken` in a cookie to <>. -By default the `CookieCsrfTokenRepository` will write to a cookie named `XSRF-TOKEN` and read it from a header named `X-XSRF-TOKEN` or the HTTP parameter `_csrf`. -These defaults come from https://docs.angularjs.org/api/ng/service/$http#cross-site-request-forgery-xsrf-protection[AngularJS] - -You can configure `CookieCsrfTokenRepository` in XML using the following: +By default, the `CookieCsrfTokenRepository` writes to a cookie named `XSRF-TOKEN` and reads it from a header named `X-XSRF-TOKEN` or the HTTP parameter `_csrf`. +These defaults come from https://docs.angularjs.org/api/ng/service/$http#cross-site-request-forgery-xsrf-protection[AngularJS]. +You can configure `CookieCsrfTokenRepository` in XML byusing the following: .Store CSRF Token in a Cookie with XML Configuration ==== @@ -49,15 +48,11 @@ You can configure `CookieCsrfTokenRepository` in XML using the following: ---- ==== -[NOTE] -==== -The sample explicitly sets `cookieHttpOnly=false`. -This is necessary to allow JavaScript (i.e. AngularJS) to read it. -If you do not need the ability to read the cookie with JavaScript directly, it is recommended to omit `cookieHttpOnly=false` to improve security. -==== +NOTE: The sample explicitly sets `cookieHttpOnly=false`. +This is necessary to allow JavaScript (such as AngularJS) to read it. +If you do not need the ability to read the cookie with JavaScript directly, we recommend omitting `cookieHttpOnly=false` to improve security. - -You can configure `CookieCsrfTokenRepository` in Java Configuration using: +You can configure `CookieCsrfTokenRepository` in Java or Kotlin configuration by using: .Store CSRF Token in a Cookie ==== @@ -95,20 +90,16 @@ class SecurityConfig : WebSecurityConfigurerAdapter() { ---- ==== -[NOTE] -==== -The sample explicitly sets `cookieHttpOnly=false`. -This is necessary to allow JavaScript (i.e. AngularJS) to read it. -If you do not need the ability to read the cookie with JavaScript directly, it is recommended to omit `cookieHttpOnly=false` (by using `new CookieCsrfTokenRepository()` instead) to improve security. -==== +NOTE: The sample explicitly sets `cookieHttpOnly=false`. +This is necessary to let JavaScript (such as AngularJS) read it. +If you do not need the ability to read the cookie with JavaScript directly, we recommend omitting `cookieHttpOnly=false` (by using `new CookieCsrfTokenRepository()` instead) to improve security. [[servlet-csrf-configure-disable]] ==== Disable CSRF Protection -CSRF protection is enabled by default. -However, it is simple to disable CSRF protection if it <>. - -The XML configuration below will disable CSRF protection. +By default, CSRF protection is enabled. +However, you can disable CSRF protection if it <>. +The following XML configuration disables CSRF protection: .Disable CSRF XML Configuration ==== @@ -121,7 +112,7 @@ The XML configuration below will disable CSRF protection. ---- ==== -The Java configuration below will disable CSRF protection. +The following Java or Kotlin configuration disables CSRF protection: .Disable CSRF ==== @@ -162,16 +153,16 @@ class SecurityConfig : WebSecurityConfigurerAdapter() { [[servlet-csrf-include]] === Include the CSRF Token -In order for the <> to protect against CSRF attacks, we must include the actual CSRF token in the HTTP request. -This must be included in a part of the request (i.e. form parameter, HTTP header, etc) that is not automatically included in the HTTP request by the browser. +For the <> to protect against CSRF attacks, we must include the actual CSRF token in the HTTP request. +This must be included in a part of the request (a form parameter, an HTTP header, or other part) that is not automatically included in the HTTP request by the browser. -Spring Security's https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/web/csrf/CsrfFilter.html[CsrfFilter] exposes a https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/web/csrf/CsrfToken.html[CsrfToken] as an `HttpServletRequest` attribute named `_csrf`. +Spring Security's https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/web/csrf/CsrfFilter.html[`CsrfFilter`] exposes a https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/web/csrf/CsrfToken.html[`CsrfToken`] as an `HttpServletRequest` attribute named `_csrf`. This means that any view technology can access the `CsrfToken` to expose the expected token as either a <> or <>. -Fortunately, there are integrations listed below that make including the token in <> and <> requests even easier. +Fortunately, there are integrations listed later in this chapter that make including the token in <> and <> requests even easier. [[servlet-csrf-include-form]] ==== Form URL Encoded -In order to post an HTML form the CSRF token must be included in the form as a hidden input. +To post an HTML form, the CSRF token must be included in the form as a hidden input. For example, the rendered HTML might look like: .CSRF Token HTML @@ -184,26 +175,26 @@ For example, the rendered HTML might look like: ---- ==== -Next we will discuss various ways of including the CSRF token in a form as a hidden input. +Next, we discuss various ways of including the CSRF token in a form as a hidden input. [[servlet-csrf-include-form-auto]] ===== Automatic CSRF Token Inclusion -Spring Security's CSRF support provides integration with Spring's https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/servlet/support/RequestDataValueProcessor.html[RequestDataValueProcessor] via its https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/web/servlet/support/csrf/CsrfRequestDataValueProcessor.html[CsrfRequestDataValueProcessor]. -This means that if you leverage https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#mvc-view-jsp-formtaglib[Spring’s form tag library], https://www.thymeleaf.org/doc/tutorials/2.1/thymeleafspring.html#integration-with-requestdatavalueprocessor[Thymeleaf], or any other view technology that integrates with `RequestDataValueProcessor`, then forms that have an unsafe HTTP method (i.e. post) will automatically include the actual CSRF token. +Spring Security's CSRF support provides integration with Spring's https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/servlet/support/RequestDataValueProcessor.html[`RequestDataValueProcessor`] through its https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/web/servlet/support/csrf/CsrfRequestDataValueProcessor.html[`CsrfRequestDataValueProcessor`]. +This means that, if you use https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#mvc-view-jsp-formtaglib[Spring’s form tag library], https://www.thymeleaf.org/doc/tutorials/2.1/thymeleafspring.html#integration-with-requestdatavalueprocessor[Thymeleaf], or any other view technology that integrates with `RequestDataValueProcessor`, then forms that have an unsafe HTTP method (such as post) automatically include the actual CSRF token. [[servlet-csrf-include-form-tag]] ===== csrfInput Tag -If you are using JSPs, then you can use https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#mvc-view-jsp-formtaglib[Spring’s form tag library]. -However, if that is not an option, you can also easily include the token with the <> tag. +If you use JSPs, you can use https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#mvc-view-jsp-formtaglib[Spring’s form tag library]. +However, if that is not an option, you can also include the token with the <> tag. [[servlet-csrf-include-form-attr]] ===== CsrfToken Request Attribute If the <> for including the actual CSRF token in the request do not work, you can take advantage of the fact that the `CsrfToken` <> as an `HttpServletRequest` attribute named `_csrf`. -An example of doing this with a JSP is shown below: +The following example does this with a JSP: .CSRF Token in Form with Request Attribute ==== @@ -223,19 +214,19 @@ An example of doing this with a JSP is shown below: [[servlet-csrf-include-ajax]] ==== Ajax and JSON Requests -If you are using JSON, then it is not possible to submit the CSRF token within an HTTP parameter. -Instead you can submit the token within a HTTP header. +If you use JSON, you cannot submit the CSRF token within an HTTP parameter. +Instead, you can submit the token within a HTTP header. -In the following sections we will discuss various ways of including the CSRF token as an HTTP request header in JavaScript based applications. +The following sections discuss various ways of including the CSRF token as an HTTP request header in JavaScript based applications. [[servlet-csrf-include-ajax-auto]] ===== Automatic Inclusion -Spring Security can easily be <> to store the expected CSRF token in a cookie. -By storing the expected CSRF in a cookie, JavaScript frameworks like https://docs.angularjs.org/api/ng/service/$http#cross-site-request-forgery-xsrf-protection[AngularJS] will automatically include the actual CSRF token in the HTTP request headers. +You can <> Spring Security to store the expected CSRF token in a cookie. +By storing the expected CSRF in a cookie, JavaScript frameworks, such as https://docs.angularjs.org/api/ng/service/$http#cross-site-request-forgery-xsrf-protection[AngularJS], automatically include the actual CSRF token in the HTTP request headers. [[servlet-csrf-include-ajax-meta]] -===== Meta tags +===== Meta Tags An alternative pattern to <> is to include the CSRF token within your `meta` tags. The HTML might look something like this: @@ -254,8 +245,8 @@ The HTML might look something like this: ---- ==== -Once the meta tags contained the CSRF token, the JavaScript code would read the meta tags and include the CSRF token as a header. -If you were using jQuery, this could be done with the following: +Once the meta tags contain the CSRF token, the JavaScript code can read the meta tags and include the CSRF token as a header. +If you use jQuery, you can do this with the following code: .AJAX send CSRF Token ==== @@ -274,13 +265,13 @@ $(function () { [[servlet-csrf-include-ajax-meta-tag]] ====== csrfMeta tag -If you are using JSPs a simple way to write the CSRF token to the `meta` tags is by leveraging the <> tag. +If you use JSPs, one way to write the CSRF token to the `meta` tags is by using the <> tag. [[servlet-csrf-include-ajax-meta-attr]] ====== CsrfToken Request Attribute If the <> for including the actual CSRF token in the request do not work, you can take advantage of the fact that the `CsrfToken` <> as an `HttpServletRequest` attribute named `_csrf`. -An example of doing this with a JSP is shown below: +The following example does this with a JSP: .CSRF meta tag JSP ==== @@ -300,31 +291,31 @@ An example of doing this with a JSP is shown below: [[servlet-csrf-considerations]] == CSRF Considerations There are a few special considerations to consider when implementing protection against CSRF attacks. -This section discusses those considerations as it pertains to servlet environments. -Refer to <> for a more general discussion. +This section discusses those considerations as they pertain to servlet environments. +See <> for a more general discussion. [[servlet-considerations-csrf-login]] === Logging In -It is important to <> requests to protect against forging log in attempts. +It is important to <> requests, to protect against forging login attempts. Spring Security's servlet support does this out of the box. [[servlet-considerations-csrf-logout]] === Logging Out -It is important to <> requests to protect against forging log out attempts. -If CSRF protection is enabled (default), Spring Security's `LogoutFilter` to only process HTTP POST. -This ensures that log out requires a CSRF token and that a malicious user cannot forcibly log out your users. +It is important to <> requests to protect against forging logout attempts. +If CSRF protection is enabled (the default), Spring Security's `LogoutFilter` to only process HTTP POST. +This ensures that logging out requires a CSRF token and that a malicious user cannot forcibly log out your users. The easiest approach is to use a form to log out. -If you really want a link, you can use JavaScript to have the link perform a POST (i.e. maybe on a hidden form). -For browsers with JavaScript that is disabled, you can optionally have the link take the user to a log out confirmation page that will perform the POST. +If you really want a link, you can use JavaScript to have the link perform a POST (maybe on a hidden form). +For browsers with JavaScript that is disabled, you can optionally have the link take the user to a log out confirmation page that performs the POST. -If you really want to use HTTP GET with logout you can do so, but remember this is generally not recommended. -For example, the following Java Configuration will perform logout with the URL `/logout` is requested with any HTTP method: +If you really want to use HTTP GET with logout, you can do so. However, remember that this is generally not recommended. +For example, the following Java Configuration logs out when the `/logout` URL is requested with any HTTP method: -.Log out with HTTP GET +.Log out with any HTTP method ==== .Java [source,java,role="primary"] @@ -364,18 +355,18 @@ class SecurityConfig : WebSecurityConfigurerAdapter() { [[servlet-considerations-csrf-timeouts]] === CSRF and Session Timeouts -By default Spring Security stores the CSRF token in the `HttpSession`. -This can lead to a situation where the session expires which means there is not an expected CSRF token to validate against. +By default, Spring Security stores the CSRF token in the `HttpSession`. +This can lead to a situation where the session expires, leaving no CSRF token to validate against. -We've already discussed <> to session timeouts. +We have already discussed <> to session timeouts. This section discusses the specifics of CSRF timeouts as it pertains to the servlet support. -It is simple to change storage of the expected CSRF token to be in a cookie. -For details, refer to the <> section. +You can change the storage of the CSRF token to be in a cookie. +For details, see the <> section. If a token does expire, you might want to customize how it is handled by specifying a custom `AccessDeniedHandler`. The custom `AccessDeniedHandler` can process the `InvalidCsrfTokenException` any way you like. -For an example of how to customize the `AccessDeniedHandler` refer to the provided links for both <> and https://github.com/spring-projects/spring-security/blob/3.2.0.RC1/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpAccessDeniedHandlerTests.java#L64[Java configuration]. +For an example of how to customize the `AccessDeniedHandler`, see the provided links for both <> and https://github.com/spring-projects/spring-security/blob/3.2.0.RC1/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpAccessDeniedHandlerTests.java#L64[Java configuration]. // FIXME: We should add a custom AccessDeniedHandler section in the reference and update the links above @@ -384,25 +375,22 @@ For an example of how to customize the `AccessDeniedHandler` refer to the provid We have <> how protecting multipart requests (file uploads) from CSRF attacks causes a https://en.wikipedia.org/wiki/Chicken_or_the_egg[chicken and the egg] problem. This section discusses how to implement placing the CSRF token in the <> and <> within a servlet application. -[NOTE] -==== -More information about using multipart forms with Spring can be found within the https://docs.spring.io/spring/docs/5.2.x/spring-framework-reference/web.html#mvc-multipart[1.1.11. Multipart Resolver] section of the Spring reference and the https://docs.spring.io/spring/docs/5.2.x/javadoc-api/org/springframework/web/multipart/support/MultipartFilter.html[MultipartFilter javadoc]. -==== +NOTE: You can find more information about using multipart forms with Spring in the https://docs.spring.io/spring/docs/5.2.x/spring-framework-reference/web.html#mvc-multipart[1.1.11. Multipart Resolver] section of the Spring reference and the https://docs.spring.io/spring/docs/5.2.x/javadoc-api/org/springframework/web/multipart/support/MultipartFilter.html[`MultipartFilter` javadoc]. [[servlet-csrf-considerations-multipart-body]] ==== Place CSRF Token in the Body We have <> the tradeoffs of placing the CSRF token in the body. -In this section we will discuss how to configure Spring Security to read the CSRF from the body. +In this section, we discuss how to configure Spring Security to read the CSRF from the body. -In order to read the CSRF token from the body, the `MultipartFilter` is specified before the Spring Security filter. -Specifying the `MultipartFilter` before the Spring Security filter means that there is no authorization for invoking the `MultipartFilter` which means anyone can place temporary files on your server. -However, only authorized users will be able to submit a File that is processed by your application. +To read the CSRF token from the body, the `MultipartFilter` is specified before the Spring Security filter. +Specifying the `MultipartFilter` before the Spring Security filter means that there is no authorization for invoking the `MultipartFilter`, which means anyone can place temporary files on your server. +However, only authorized users can submit a file that is processed by your application. In general, this is the recommended approach because the temporary file upload should have a negligible impact on most servers. // FIXME: Document Spring Boot -To ensure `MultipartFilter` is specified before the Spring Security filter with java configuration, users can override beforeSpringSecurityFilterChain as shown below: +To ensure `MultipartFilter` is specified before the Spring Security filter with Java configuration, you can override `beforeSpringSecurityFilterChain`: .Initializer MultipartFilter ==== @@ -429,7 +417,7 @@ class SecurityApplicationInitializer : AbstractSecurityWebApplicationInitializer ---- ==== -To ensure `MultipartFilter` is specified before the Spring Security filter with XML configuration, users can ensure the element of the `MultipartFilter` is placed before the springSecurityFilterChain within the web.xml as shown below: +To ensure that `MultipartFilter` is specified before the Spring Security filter with XML configuration, you can ensure the `` element of the `MultipartFilter` is placed before the `springSecurityFilterChain` within the `web.xml` file: .web.xml - MultipartFilter ==== @@ -455,11 +443,11 @@ To ensure `MultipartFilter` is specified before the Spring Security filter with ==== [[servlet-csrf-considerations-multipart-url]] -==== Include CSRF Token in URL +==== Include a CSRF Token in a URL -If allowing unauthorized users to upload temporary files is not acceptable, an alternative is to place the `MultipartFilter` after the Spring Security filter and include the CSRF as a query parameter in the action attribute of the form. +If letting unauthorized users upload temporary files is not acceptable, an alternative is to place the `MultipartFilter` after the Spring Security filter and include the CSRF as a query parameter in the action attribute of the form. Since the `CsrfToken` is exposed as an `HttpServletRequest` <>, we can use that to create an `action` with the CSRF token in it. -An example with a jsp is shown below +The following example does this with a JSP: .CSRF Token in Action ==== @@ -475,5 +463,5 @@ An example with a jsp is shown below === HiddenHttpMethodFilter We have <> the trade-offs of placing the CSRF token in the body. -In Spring's Servlet support, overriding the HTTP method is done using https://docs.spring.io/spring-framework/docs/5.2.x/javadoc-api/org/springframework/web/filter/reactive/HiddenHttpMethodFilter.html[HiddenHttpMethodFilter]. -More information can be found in https://docs.spring.io/spring/docs/5.2.x/spring-framework-reference/web.html#mvc-rest-method-conversion[HTTP Method Conversion] section of the reference documentation. +In Spring's Servlet support, overriding the HTTP method is done by using https://docs.spring.io/spring-framework/docs/5.2.x/javadoc-api/org/springframework/web/filter/reactive/HiddenHttpMethodFilter.html[`HiddenHttpMethodFilter`]. +You can find more information in the https://docs.spring.io/spring/docs/5.2.x/spring-framework-reference/web.html#mvc-rest-method-conversion[HTTP Method Conversion] section of the reference documentation. diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/exploits/firewall.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/exploits/firewall.adoc index 71171992b34..618368eef42 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/exploits/firewall.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/exploits/firewall.adoc @@ -1,49 +1,49 @@ [[servlet-httpfirewall]] = HttpFirewall -Spring Security has several areas where patterns you have defined are tested against incoming requests in order to decide how the request should be handled. -This occurs when the `FilterChainProxy` decides which filter chain a request should be passed through and also when the `FilterSecurityInterceptor` decides which security constraints apply to a request. -It's important to understand what the mechanism is and what URL value is used when testing against the patterns that you define. +Spring Security has several areas where patterns you have defined are tested against incoming requests to decide how the request should be handled. +This occurs when the `FilterChainProxy` decides which filter chain a request should be passed through and when the `FilterSecurityInterceptor` decides which security constraints apply to a request. +It is important to understand what the mechanism is and what URL value is used when testing against the patterns that you define. -The Servlet Specification defines several properties for the `HttpServletRequest` which are accessible via getter methods, and which we might want to match against. -These are the `contextPath`, `servletPath`, `pathInfo` and `queryString`. +The servlet specification defines several properties for the `HttpServletRequest` that are accessible via getter methods and that we might want to match against. +These are the `contextPath`, `servletPath`, `pathInfo`, and `queryString`. Spring Security is only interested in securing paths within the application, so the `contextPath` is ignored. -Unfortunately, the servlet spec does not define exactly what the values of `servletPath` and `pathInfo` will contain for a particular request URI. +Unfortunately, the servlet spec does not define exactly what the values of `servletPath` and `pathInfo` contain for a particular request URI. For example, each path segment of a URL may contain parameters, as defined in https://www.ietf.org/rfc/rfc2396.txt[RFC 2396] -footnote:[You have probably seen this when a browser doesn't support cookies and the `jsessionid` parameter is appended to the URL after a semi-colon. -However the RFC allows the presence of these parameters in any path segment of the URL]. -The Specification does not clearly state whether these should be included in the `servletPath` and `pathInfo` values and the behaviour varies between different servlet containers. -There is a danger that when an application is deployed in a container which does not strip path parameters from these values, an attacker could add them to the requested URL in order to cause a pattern match to succeed or fail unexpectedly. -footnote:[The original values will be returned once the request leaves the `FilterChainProxy`, so will still be available to the application.]. +(You have probably seen this when a browser does not support cookies and the `jsessionid` parameter is appended to the URL after a semicolon. +However, the RFC allows the presence of these parameters in any path segment of the URL.) +The Specification does not clearly state whether these should be included in the `servletPath` and `pathInfo` values and the behavior varies between different servlet containers. +There is a danger that, when an application is deployed in a container that does not strip path parameters from these values, an attacker could add them to the requested URL to cause a pattern match to succeed or fail unexpectedly. +(The original values will be returned once the request leaves the `FilterChainProxy`, so will still be available to the application.) Other variations in the incoming URL are also possible. -For example, it could contain path-traversal sequences (like `/../`) or multiple forward slashes (`//`) which could also cause pattern-matches to fail. -Some containers normalize these out before performing the servlet mapping, but others don't. +For example, it could contain path-traversal sequences (such as `/../`) or multiple forward slashes (`//`) that could also cause pattern-matches to fail. +Some containers normalize these out before performing the servlet mapping, but others do not. To protect against issues like these, `FilterChainProxy` uses an `HttpFirewall` strategy to check and wrap the request. -Un-normalized requests are automatically rejected by default, and path parameters and duplicate slashes are removed for matching purposes. -footnote:[So, for example, an original request path `/secure;hack=1/somefile.html;hack=2` will be returned as `/secure/somefile.html`.]. -It is therefore essential that a `FilterChainProxy` is used to manage the security filter chain. -Note that the `servletPath` and `pathInfo` values are decoded by the container, so your application should not have any valid paths which contain semi-colons, as these parts will be removed for matching purposes. +By default, un-normalized requests are automatically rejected, and path parameters and duplicate slashes are removed for matching purposes. +(So, for example, an original request path of `/secure;hack=1/somefile.html;hack=2` is returned as `/secure/somefile.html`.) +It is, therefore, essential that a `FilterChainProxy` is used to manage the security filter chain. +Note that the `servletPath` and `pathInfo` values are decoded by the container, so your application should not have any valid paths that contain semi-colons, as these parts are removed for matching purposes. -As mentioned above, the default strategy is to use Ant-style paths for matching and this is likely to be the best choice for most users. -The strategy is implemented in the class `AntPathRequestMatcher` which uses Spring's `AntPathMatcher` to perform a case-insensitive match of the pattern against the concatenated `servletPath` and `pathInfo`, ignoring the `queryString`. +As mentioned earlier, the default strategy is to use Ant-style paths for matching, and this is likely to be the best choice for most users. +The strategy is implemented in the class `AntPathRequestMatcher`, which uses Spring's `AntPathMatcher` to perform a case-insensitive match of the pattern against the concatenated `servletPath` and `pathInfo`, ignoring the `queryString`. -If for some reason, you need a more powerful matching strategy, you can use regular expressions. +If you need a more powerful matching strategy, you can use regular expressions. The strategy implementation is then `RegexRequestMatcher`. -See the Javadoc for this class for more information. +See the {security-api-url}/org/springframework/security/web/util/matcher/RegexRequestMatcher.html[Javadoc for this class] for more information. -In practice we recommend that you use method security at your service layer, to control access to your application, and do not rely entirely on the use of security constraints defined at the web-application level. -URLs change and it is difficult to take account of all the possible URLs that an application might support and how requests might be manipulated. -You should try and restrict yourself to using a few simple ant paths which are simple to understand. -Always try to use a "deny-by-default" approach where you have a catch-all wildcard ( /** or **) defined last and denying access. +In practice, we recommend that you use method security at your service layer, to control access to your application, rather than rely entirely on the use of security constraints defined at the web-application level. +URLs change, and it is difficult to take into account all the possible URLs that an application might support and how requests might be manipulated. +You should restrict yourself to using a few simple Ant paths that are simple to understand. +Always try to use a "`deny-by-default`" approach, where you have a catch-all wildcard (`/**` or `**`) defined last to deny access. Security defined at the service layer is much more robust and harder to bypass, so you should always take advantage of Spring Security's method security options. The `HttpFirewall` also prevents https://www.owasp.org/index.php/HTTP_Response_Splitting[HTTP Response Splitting] by rejecting new line characters in the HTTP Response headers. -By default the `StrictHttpFirewall` is used. +By default, the `StrictHttpFirewall` implementation is used. This implementation rejects requests that appear to be malicious. -If it is too strict for your needs, then you can customize what types of requests are rejected. +If it is too strict for your needs, you can customize what types of requests are rejected. However, it is important that you do so knowing that this can open your application up to attacks. -For example, if you wish to leverage Spring MVC's Matrix Variables, the following configuration could be used: +For example, if you wish to use Spring MVC's matrix variables, you could use the following configuration: .Allow Matrix Variables ==== @@ -80,11 +80,10 @@ fun httpFirewall(): StrictHttpFirewall { ---- ==== -The `StrictHttpFirewall` provides an allowed list of valid HTTP methods that are allowed to protect against https://www.owasp.org/index.php/Cross_Site_Tracing[Cross Site Tracing (XST)] and https://www.owasp.org/index.php/Test_HTTP_Methods_(OTG-CONFIG-006)[HTTP Verb Tampering]. -The default valid methods are "DELETE", "GET", "HEAD", "OPTIONS", "PATCH", "POST", and "PUT". +To protect against https://www.owasp.org/index.php/Cross_Site_Tracing[Cross Site Tracing (XST)] and https://www.owasp.org/index.php/Test_HTTP_Methods_(OTG-CONFIG-006)[HTTP Verb Tampering], the `StrictHttpFirewall` provides an allowed list of valid HTTP methods that are allowed. +The default valid methods are `DELETE`, `GET`, `HEAD`, `OPTIONS`, `PATCH`, `POST`, and `PUT`. If your application needs to modify the valid methods, you can configure a custom `StrictHttpFirewall` bean. -For example, the following will only allow HTTP "GET" and "POST" methods: - +The following example allows only HTTP `GET` and `POST` methods: .Allow Only GET & POST ==== @@ -121,31 +120,28 @@ fun httpFirewall(): StrictHttpFirewall { ---- ==== -[TIP] -==== -If you are using `new MockHttpServletRequest()` it currently creates an HTTP method as an empty String "". -This is an invalid HTTP method and will be rejected by Spring Security. +TIP: If you use `new MockHttpServletRequest()`, it currently creates an HTTP method as an empty String (`""`). +This is an invalid HTTP method and is rejected by Spring Security. You can resolve this by replacing it with `new MockHttpServletRequest("GET", "")`. -See https://jira.spring.io/browse/SPR-16851[SPR_16851] for an issue requesting to improve this. -==== +See https://jira.spring.io/browse/SPR-16851[SPR_16851] for an issue that requests improving this. If you must allow any HTTP method (not recommended), you can use `StrictHttpFirewall.setUnsafeAllowAnyHttpMethod(true)`. -This will disable validation of the HTTP method entirely. +Doing so entirely disables validation of the HTTP method. [[servlet-httpfirewall-headers-parameters]] `StrictHttpFirewall` also checks header names and values and parameter names. It requires that each character have a defined code point and not be a control character. -This requirement can be relaxed or adjusted as necessary using the following methods: +This requirement can be relaxed or adjusted as necessary by using the following methods: * `StrictHttpFirewall#setAllowedHeaderNames(Predicate)` * `StrictHttpFirewall#setAllowedHeaderValues(Predicate)` * `StrictHttpFirewall#setAllowedParameterNames(Predicate)` -NOTE: Also, parameter values can be controlled with `setAllowedParameterValues(Predicate)`. +NOTE: Parameter values can be also controlled with `setAllowedParameterValues(Predicate)`. -For example, to switch off this check, you can wire your `StrictHttpFirewall` with `Predicate` s that always return `true`, like so: +For example, to switch off this check, you can wire your `StrictHttpFirewall` with `Predicate` instances that always return `true`: .Allow Any Header Name, Header Value, and Parameter Name ==== @@ -176,12 +172,12 @@ fun httpFirewall(): StrictHttpFirewall { ---- ==== -Or, there might be a specific value that you need to allow. +Alternatively, there might be a specific value that you need to allow. -For example, iPhone Xʀ uses a `User-Agent` that includes a character not in the ISO-8859-1 charset. -Due to this fact, some application servers will parse this value into two separate characters, the latter being an undefined character. +For example, iPhone Xʀ uses a `User-Agent` that includes a character that is not in the ISO-8859-1 charset. +Due to this fact, some application servers parse this value into two separate characters, the latter being an undefined character. -You can address this with the `setAllowedHeaderValues` method, as you can see below: +You can address this with the `setAllowedHeaderValues` method: .Allow Certain User Agents ==== @@ -212,7 +208,7 @@ fun httpFirewall(): StrictHttpFirewall { ---- ==== -In the case of header values, you may instead consider parsing them as UTF-8 at verification time like so: +In the case of header values, you may instead consider parsing them as UTF-8 at verification time: .Parse Headers As UTF-8 ==== diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/exploits/headers.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/exploits/headers.adoc index e45c5c96c95..15978085b46 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/exploits/headers.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/exploits/headers.adoc @@ -1,19 +1,19 @@ [[servlet-headers]] = Security HTTP Response Headers -<> can be used to increase the security of web applications. -This section is dedicated to servlet based support for Security HTTP Response Headers. +You can use <> to increase the security of web applications. +This section is dedicated to servlet-based support for Security HTTP Response Headers. [[servlet-headers-default]] == Default Security Headers Spring Security provides a <> to provide secure defaults. -While each of these headers are considered best practice, it should be noted that not all clients utilize the headers, so additional testing is encouraged. +While each of these headers are considered best practice, it should be noted that not all clients use the headers, so additional testing is encouraged. You can customize specific headers. -For example, assume that you want the defaults except you wish to specify `SAMEORIGIN` for <>. +For example, assume that you want the defaults but you wish to specify `SAMEORIGIN` for <>. -You can easily do this with the following Configuration: +You can do so with the following configuration: .Customize Default Security Headers ==== @@ -69,9 +69,9 @@ class SecurityConfig : WebSecurityConfigurerAdapter() { ==== If you do not want the defaults to be added and want explicit control over what should be used, you can disable the defaults. -An example is provided below: +The next code listing shows how to do so. -If you are using Spring Security's Configuration the following will only add <>. +If you use Spring Security's configuration, the following adds only <>: .Customize Cache Control Headers ==== @@ -127,7 +127,7 @@ class SecurityConfig : WebSecurityConfigurerAdapter() { ---- ==== -If necessary, you can disable all of the HTTP Security response headers with the following Configuration: +If necessary, you can disable all of the HTTP Security response headers with the following configuration: .Disable All HTTP Security Headers ==== @@ -179,11 +179,11 @@ class SecurityConfig : WebSecurityConfigurerAdapter() { Spring Security includes <> headers by default. -However, if you actually want to cache specific responses, your application can selectively invoke https://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletResponse.html#setHeader(java.lang.String,java.lang.String)[HttpServletResponse.setHeader(String,String)] to override the header set by Spring Security. -This is useful to ensure things like CSS, JavaScript, and images are properly cached. +However, if you actually want to cache specific responses, your application can selectively invoke https://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletResponse.html#setHeader(java.lang.String,java.lang.String)[`HttpServletResponse.setHeader(String,String)`] to override the header set by Spring Security. +You can use this to ensure that content (such as CSS, JavaScript, and images) is properly cached. -When using Spring Web MVC, this is typically done within your configuration. -Details on how to do this can be found in the https://docs.spring.io/spring/docs/5.0.0.RELEASE/spring-framework-reference/web.html#mvc-config-static-resources[Static Resources] portion of the Spring Reference documentation +When you use Spring Web MVC, this is typically done within your configuration. +You can find details on how to do this in the https://docs.spring.io/spring/docs/5.0.0.RELEASE/spring-framework-reference/web.html#mvc-config-static-resources[Static Resources] portion of the Spring Reference documentation If necessary, you can also disable Spring Security's cache control HTTP response headers. @@ -243,7 +243,7 @@ class SecurityConfig : WebSecurityConfigurerAdapter() { == Content Type Options Spring Security includes <> headers by default. -However, you can disable it with: +However, you can disable it: .Content Type Options Disabled ==== @@ -300,9 +300,9 @@ class SecurityConfig : WebSecurityConfigurerAdapter() { [[servlet-headers-hsts]] == HTTP Strict Transport Security (HSTS) -Spring Security provides the <> header by default. -However, you can customize the results explicitly. -For example, the following is an example of explicitly providing HSTS: +By default, Spring Security provides the <> header. +However, you can explicitly customize the results. +The following example explicitly provides HSTS: .Strict Transport Security ==== @@ -366,9 +366,9 @@ class SecurityConfig : WebSecurityConfigurerAdapter() { [[servlet-headers-hpkp]] == HTTP Public Key Pinning (HPKP) -For passivity reasons, Spring Security provides servlet support for <> but it is <>. +Spring Security provides servlet support for <>, but it is <>. -You can enable HPKP headers with the following Configuration: +You can enable HPKP headers with the following configuration: .HTTP Public Key Pinning ==== @@ -437,9 +437,9 @@ class SecurityConfig : WebSecurityConfigurerAdapter() { [[servlet-headers-frame-options]] == X-Frame-Options -By default, Spring Security disables rendering within an iframe using <>. +By default, Spring Security disables rendering within an iframe by using <>. -You can customize frame options to use the same origin within a Configuration using the following: +You can customize frame options to use the same origin within a configuration by using the following: .X-Frame-Options: SAMEORIGIN ==== @@ -499,9 +499,9 @@ class SecurityConfig : WebSecurityConfigurerAdapter() { [[servlet-headers-xss-protection]] == X-XSS-Protection -By default, Spring Security instructs browsers to block reflected XSS attacks using the <. +By default, Spring Security instructs browsers to block reflected XSS attacks by using the <>. However, you can change this default. -For example, the following Configuration specifies that Spring Security should no longer instruct browsers to block the content: +For example, the following configuration specifies that Spring Security should no longer instruct browsers to block the content: .X-XSS-Protection Customization ==== @@ -560,10 +560,10 @@ class SecurityConfig : WebSecurityConfigurerAdapter() { [[servlet-headers-csp]] == Content Security Policy (CSP) -Spring Security does not add <> by default, because a reasonable default is impossible to know without context of the application. -The web application author must declare the security policy(s) to enforce and/or monitor for the protected resources. +Spring Security does not add <> by default, because a reasonable default is impossible to know without knowing the context of the application. +The web application author must declare the security policy (or policies) to enforce or monitor for the protected resources. -For example, given the following security policy: +Consider the following security policy: .Content Security Policy Example ==== @@ -573,7 +573,7 @@ Content-Security-Policy: script-src 'self' https://trustedscripts.example.com; o ---- ==== -You can enable the CSP header as shown below: +Given the preceding security policy, you can enable the CSP header: .Content Security Policy ==== @@ -694,7 +694,7 @@ class SecurityConfig : WebSecurityConfigurerAdapter() { == Referrer Policy Spring Security does not add <> headers by default. -You can enable the Referrer Policy header using the configuration as shown below: +You can enable the Referrer Policy header by using the configuration: .Referrer Policy ==== @@ -754,7 +754,7 @@ class SecurityConfig : WebSecurityConfigurerAdapter() { == Feature Policy Spring Security does not add <> headers by default. -The following `Feature-Policy` header: +Consider the following `Feature-Policy` header: .Feature-Policy Example ==== @@ -764,7 +764,7 @@ Feature-Policy: geolocation 'self' ---- ==== -can enable the Feature Policy header using the configuration shown below: +You can enable the preceding feature policy header by using the following configuration: .Feature-Policy ==== @@ -820,7 +820,7 @@ class SecurityConfig : WebSecurityConfigurerAdapter() { == Permissions Policy Spring Security does not add <> headers by default. -The following `Permissions-Policy` header: +Consider the following `Permissions-Policy` header: .Permissions-Policy Example ==== @@ -830,7 +830,7 @@ Permissions-Policy: geolocation=(self) ---- ==== -can enable the Permissions Policy header using the configuration shown below: +You can enable the preceding permissions policy header using the following configuration: .Permissions-Policy ==== @@ -890,7 +890,7 @@ class SecurityConfig : WebSecurityConfigurerAdapter() { == Clear Site Data Spring Security does not add <> headers by default. -The following Clear-Site-Data header: +Consider the following Clear-Site-Data header: .Clear-Site-Data Example ==== @@ -899,7 +899,7 @@ Clear-Site-Data: "cache", "cookies" ---- ==== -can be sent on log out with the following configuration: +You can send the preceding header on log out with the following configuration: .Clear-Site-Data ==== @@ -945,15 +945,15 @@ However, it also provides hooks to enable adding custom headers. [[servlet-headers-static]] === Static Headers -There may be times you wish to inject custom security headers into your application that are not supported out of the box. -For example, given the following custom security header: +There may be times when you wish to inject custom security headers that are not supported out of the box into your application. +Consider the following custom security header: [source] ---- X-Custom-Security-Header: header-value ---- -The headers could be added to the response using the following Configuration: +Given the preceding header, you could add the headers to the response by using the following configuration: .StaticHeadersWriter ==== @@ -1009,8 +1009,8 @@ class SecurityConfig : WebSecurityConfigurerAdapter() { === Headers Writer When the namespace or Java configuration does not support the headers you want, you can create a custom `HeadersWriter` instance or even provide a custom implementation of the `HeadersWriter`. -Let's take a look at an example of using an custom instance of `XFrameOptionsHeaderWriter`. -If you wanted to explicitly configure <> it could be done with the following Configuration: +The next example use a custom instance of `XFrameOptionsHeaderWriter`. +If you wanted to explicitly configure <>, you could do so with the following configuration: .Headers Writer ==== @@ -1071,11 +1071,11 @@ class SecurityConfig : WebSecurityConfigurerAdapter() { [[headers-delegatingrequestmatcherheaderwriter]] === DelegatingRequestMatcherHeaderWriter -At times you may want to only write a header for certain requests. -For example, perhaps you want to only protect your log in page from being framed. +At times, you may want to write a header only for certain requests. +For example, perhaps you want to protect only your login page from being framed. You could use the `DelegatingRequestMatcherHeaderWriter` to do so. -An example of using `DelegatingRequestMatcherHeaderWriter` in Java Configuration can be seen below: +The following configuration example uses `DelegatingRequestMatcherHeaderWriter`: .DelegatingRequestMatcherHeaderWriter Java Configuration ==== diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/exploits/http.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/exploits/http.adoc index f9d8c3275b9..c077006a08d 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/exploits/http.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/exploits/http.adoc @@ -1,16 +1,16 @@ [[servlet-http]] = HTTP -All HTTP based communication should be protected <>. +All HTTP-based communication should be protected <>. -Below you can find details around Servlet specific features that assist with HTTPS usage. +This section discusses the details of servlet-specific features that assist with HTTPS usage. [[servlet-http-redirect]] == Redirect to HTTPS -If a client makes a request using HTTP rather than HTTPS, Spring Security can be configured to redirect to HTTPS. +If a client makes a request using HTTP rather than HTTPS, you can configure Spring Security to redirect to HTTPS. -For example, the following Java configuration will redirect any HTTP requests to HTTPS: +For example, the following Java or Kotlin configuration redirects any HTTP requests to HTTPS: .Redirect to HTTPS ==== @@ -52,7 +52,7 @@ class SecurityConfig : WebSecurityConfigurerAdapter() { ---- ==== -The following XML configuration will redirect all HTTP requests to HTTPS +The following XML configuration redirects all HTTP requests to HTTPS .Redirect to HTTPS with XML Configuration ==== diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/exploits/index.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/exploits/index.adoc index bc955238c29..6a8e4b15e7e 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/exploits/index.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/exploits/index.adoc @@ -1,6 +1,8 @@ [[servlet-exploits]] = Protection Against Exploits +This section details how Spring Security provides protection against some of the most common exploits. + include::csrf.adoc[leveloffset=+1] include::headers.adoc[leveloffset=+1] diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/hello/index.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/hello/index.adoc index 57e9f5f1cef..98bd31f5c4b 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/hello/index.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/hello/index.adoc @@ -3,11 +3,8 @@ This section covers the minimum setup for how to use Spring Security with Spring Boot. -[NOTE] -==== -The completed application can be found at {gh-samples-url}/boot/helloworld[samples/boot/helloworld] -For your convenience, you can download a minimal Spring Boot + Spring Security application by https://start.spring.io/starter.zip?type=maven-project&language=java&packaging=jar&jvmVersion=1.8&groupId=example&artifactId=hello-security&name=hello-security&description=Hello%20Security&packageName=example.hello-security&dependencies=web,security[clicking here]. -==== +NOTE: The completed application can be found at {gh-samples-url}/boot/helloworld[samples/boot/helloworld] +For your convenience, you can download https://start.spring.io/starter.zip?type=maven-project&language=java&packaging=jar&jvmVersion=1.8&groupId=example&artifactId=hello-security&name=hello-security&description=Hello%20Security&packageName=example.hello-security&dependencies=web,security[a minimal Spring Boot + Spring Security application]. [[servlet-hello-dependencies]] == Updating Dependencies @@ -40,12 +37,12 @@ Using generated security password: 8e557245-73e2-4286-969a-ff57fe326336 // FIXME: Link to relevant portions of documentation // FIXME: Link to Spring Boot's Security Auto configuration classes -// FIXME: Add a links for what user's should do next +// FIXME: Add links for what user's should do next Spring Boot automatically: * Enables Spring Security's default configuration, which creates a servlet `Filter` as a bean named `springSecurityFilterChain`. -This bean is responsible for all the security (protecting the application URLs, validating submitted username and passwords, redirecting to the log in form, and so on) within your application. +This bean is responsible for all the security (protecting the application URLs, validating submitted username and passwords, redirecting to the login form, and so on) within your application. * Creates a `UserDetailsService` bean with a username of `user` and a randomly generated password that is logged to the console. * Registers the `Filter` with a bean named `springSecurityFilterChain` with the Servlet container for every request. @@ -71,4 +68,3 @@ A summary of the features follows: ** https://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletRequest.html#isUserInRole(java.lang.String)[`HttpServletRequest.html#isUserInRole(java.lang.String)`] ** https://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletRequest.html#login(java.lang.String,%20java.lang.String)[`HttpServletRequest.html#login(java.lang.String, java.lang.String)`] ** https://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletRequest.html#logout()[`HttpServletRequest.html#logout()`] - diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/concurrency.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/concurrency.adoc index 78aeb0b6746..d276815e2d9 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/concurrency.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/concurrency.adoc @@ -1,19 +1,20 @@ [[concurrency]] == Concurrency Support -In most environments, Security is stored on a per `Thread` basis. +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. -Spring Security provides some infrastructure to help make this much easier for users. -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 <> and <>. +Spring Security provides some infrastructure to help make this much easier to manage. +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 integrate with <> and <>. === 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. -It then invokes the delegate Runnable ensuring to clear the `SecurityContextHolder` afterwards. +It wraps a delegate `Runnable` to initialize the `SecurityContextHolder` with a specified `SecurityContext` for the delegate. +It then invokes the delegate `Runnable`, ensuring to clear the `SecurityContextHolder` afterwards. The `DelegatingSecurityContextRunnable` looks something like this: +==== [source,java] ---- public void run() { @@ -25,13 +26,15 @@ try { } } ---- +==== -While very simple, it makes it seamless to transfer the SecurityContext from one Thread to another. -This is important since, in most cases, the SecurityContextHolder acts on a per Thread basis. +While very simple, it makes it seamless to transfer the `SecurityContext` from one `Thread` to another. +This is important since, in most cases, the `SecurityContextHolder` acts on a per-`Thread` basis. For example, you might have used Spring Security's <> support to secure one of your services. -You can now easily transfer the `SecurityContext` of the current `Thread` to the `Thread` that invokes the secured service. -An example of how you might do this can be found below: +You can now transfer the `SecurityContext` of the current `Thread` to the `Thread` that invokes the secured service. +The following example show how you might do so: +==== [source,java] ---- Runnable originalRunnable = new Runnable() { @@ -46,18 +49,18 @@ DelegatingSecurityContextRunnable wrappedRunnable = new Thread(wrappedRunnable).start(); ---- +==== -The code above performs the following steps: +The preceding code: -* Creates a `Runnable` that will be invoking our secured service. -Notice that it is not aware of Spring Security -* Obtains the `SecurityContext` that we wish to use from the `SecurityContextHolder` and initializes the `DelegatingSecurityContextRunnable` -* Use the `DelegatingSecurityContextRunnable` to create a Thread -* Start the Thread we created - -Since it is quite common to create a `DelegatingSecurityContextRunnable` with the `SecurityContext` from the `SecurityContextHolder` there is a shortcut constructor for it. -The following code is the same as the code above: +* Creates a `Runnable` that invokes our secured service. +Note that it is not aware of Spring Security. +* Obtains the `SecurityContext` that we wish to use from the `SecurityContextHolder` and initializes the `DelegatingSecurityContextRunnable`. +* Uses the `DelegatingSecurityContextRunnable` to create a `Thread`. +* Starts the `Thread` we created. +Since it is common to create a `DelegatingSecurityContextRunnable` with the `SecurityContext` from the `SecurityContextHolder`, there is a shortcut constructor for it. +The following code has the same effect as the preceding code: [source,java] ---- @@ -73,18 +76,18 @@ DelegatingSecurityContextRunnable wrappedRunnable = new 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. +This code still requires us to know that we are using Spring Security. +In the next section, we take a look at how we can use `DelegatingSecurityContextExecutor` to hide the fact that we use Spring Security. === 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. - -The design of `DelegatingSecurityContextExecutor` is very similar to that of `DelegatingSecurityContextRunnable` except it accepts a delegate `Executor` instead of a delegate `Runnable`. -You can see an example of how it might be used below: +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 to use it. +Now we look at how `DelegatingSecurityContextExecutor` can shield our code from any knowledge that we are using Spring Security. +The design of `DelegatingSecurityContextExecutor` is similar to that of `DelegatingSecurityContextRunnable`, except that it accepts a delegate `Executor` instead of a delegate `Runnable`. +The following example shows how to use it: +==== [source,java] ---- SecurityContext context = SecurityContextHolder.createEmptyContext(); @@ -105,19 +108,23 @@ public void run() { executor.execute(originalRunnable); ---- +==== -The code performs the following steps: +This code: * Creates the `SecurityContext` to be used for our `DelegatingSecurityContextExecutor`. -Note that in this example we simply create the `SecurityContext` by hand. -However, it does not matter where or how we get the `SecurityContext` (i.e. we could obtain it from the `SecurityContextHolder` if we wanted). -* Creates a delegateExecutor that is in charge of executing submitted ``Runnable``s -* Finally we create a `DelegatingSecurityContextExecutor` which is in charge of wrapping any Runnable that is passed into the execute method with a `DelegatingSecurityContextRunnable`. -It then passes the wrapped Runnable to the delegateExecutor. -In this instance, the same `SecurityContext` will be used for every Runnable submitted to our `DelegatingSecurityContextExecutor`. -This is nice if we are running background tasks that need to be run by a user with elevated privileges. -* At this point you may be asking yourself "How does this shield my code of any knowledge of Spring Security?" Instead of creating the `SecurityContext` and the `DelegatingSecurityContextExecutor` in our own code, we can inject an already initialized instance of `DelegatingSecurityContextExecutor`. - +Note that, in this example, we create the `SecurityContext` by hand. +However, it does not matter where or how we get the `SecurityContext` (for example, we could obtain it from the `SecurityContextHolder`). +* Creates a `delegateExecutor` that is in charge of executing submitted `Runnable` objects. +* Finally, we create a `DelegatingSecurityContextExecutor`, which is in charge of wrapping any `Runnable` that is passed into the `execute` method with a `DelegatingSecurityContextRunnable`. +It then passes the wrapped `Runnable` to the `delegateExecutor`. +In this case, the same `SecurityContext` is used for every `Runnable` submitted to our `DelegatingSecurityContextExecutor`. +This is nice if we run background tasks that need to be run by a user with elevated privileges. +* At this point, you may ask yourself, "`How does this shield my code of any knowledge of Spring Security?`" Instead of creating the `SecurityContext` and the `DelegatingSecurityContextExecutor` in our own code, we can inject an already initialized instance of `DelegatingSecurityContextExecutor`. + +Consider the following example: + +==== [source,java] ---- @Autowired @@ -132,35 +139,36 @@ Runnable originalRunnable = new Runnable() { executor.execute(originalRunnable); } ---- +==== -Now our code is unaware that the `SecurityContext` is being propagated to the `Thread`, then the `originalRunnable` is run, and then the `SecurityContextHolder` is cleared out. +Now our code is unaware that the `SecurityContext` is being propagated to the `Thread`, the `originalRunnable` is run, and the `SecurityContextHolder` is cleared out. In this example, the same user is being used to run each thread. -What if we wanted to use the user from `SecurityContextHolder` at the time we invoked `executor.execute(Runnable)` (i.e. the currently logged in user) to process ``originalRunnable``? -This can be done by removing the `SecurityContext` argument from our `DelegatingSecurityContextExecutor` constructor. -For example: - +What if we wanted to use the user from `SecurityContextHolder` (that is, the currently logged in-user) at the time we invoked `executor.execute(Runnable)` to process `originalRunnable`? +You can do so by removing the `SecurityContext` argument from our `DelegatingSecurityContextExecutor` constructor: +==== [source,java] ---- SimpleAsyncTaskExecutor delegateExecutor = new SimpleAsyncTaskExecutor(); DelegatingSecurityContextExecutor executor = new 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`. +Now, any time `executor.execute(Runnable)` is run, 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 -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. - -* `DelegatingSecurityContextCallable` -* `DelegatingSecurityContextExecutor` -* `DelegatingSecurityContextExecutorService` -* `DelegatingSecurityContextRunnable` -* `DelegatingSecurityContextScheduledExecutorService` -* `DelegatingSecurityContextSchedulingTaskExecutor` -* `DelegatingSecurityContextAsyncTaskExecutor` -* `DelegatingSecurityContextTaskExecutor` -* `DelegatingSecurityContextTaskScheduler` +See the {security-api-url}index.html[Javadoc] for additional integrations with both the Java concurrent APIs and the Spring Task abstractions. +They are self-explanatory once you understand the previous code. + +* {security-api-url}org/springframework/security/concurrent/DelegatingSecurityContextCallable.html[`DelegatingSecurityContextCallable`] +* {security-api-url}org/springframework/security/concurrent/DelegatingSecurityContextExecutor.html[`DelegatingSecurityContextExecutor`] +* {security-api-url}org/springframework/security/concurrent/DelegatingSecurityContextExecutorService.html[`DelegatingSecurityContextExecutorService`] +* {security-api-url}org/springframework/security/concurrent/DelegatingSecurityContextRunnable.html[`DelegatingSecurityContextRunnable`] +* {security-api-url}org/springframework/security/concurrent/DelegatingSecurityContextScheduledExecutorService.html[`DelegatingSecurityContextScheduledExecutorService`] +* {security-api-url}org/springframework/security/scheduling/DelegatingSecurityContextSchedulingTaskExecutor.html[`DelegatingSecurityContextSchedulingTaskExecutor`] +* {security-api-url}org/springframework/security/task/DelegatingSecurityContextAsyncTaskExecutor.html[`DelegatingSecurityContextAsyncTaskExecutor`] +* {security-api-url}org/springframework/security/task/DelegatingSecurityContextTaskExecutor.html[`DelegatingSecurityContextTaskExecutor`] +* {security-api-url}org/springframework/security/scheduling/DelegatingSecurityContextTaskScheduler.html[`DelegatingSecurityContextTaskScheduler`] diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/cors.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/cors.adoc index 188da871c18..ce315decd1b 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/cors.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/cors.adoc @@ -2,12 +2,13 @@ == 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`). -If the request does not contain any cookies and Spring Security is first, the request will determine the user is not authenticated (since there are no cookies in the request) and reject it. +CORS must be processed before Spring Security, because the pre-flight request does not contain any cookies (that is, the `JSESSIONID`). +If the request does not contain any cookies and Spring Security is first, the request determines that the user is not authenticated (since there are no cookies in the request) and rejects it. The easiest way to ensure that CORS is handled first is to use the `CorsFilter`. -Users can integrate the `CorsFilter` with Spring Security by providing a `CorsConfigurationSource` using the following: +Users can integrate the `CorsFilter` with Spring Security by providing a `CorsConfigurationSource` that uses the following: +==== [source,java] ---- @EnableWebSecurity @@ -32,9 +33,11 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter { } } ---- +==== -or in XML +The following listing does the same thing in XML: +==== [source,xml] ---- @@ -45,9 +48,11 @@ or in XML ... ---- +==== -If you are using Spring MVC's CORS support, you can omit specifying the `CorsConfigurationSource` and Spring Security will leverage the CORS configuration provided to Spring MVC. +If you use Spring MVC's CORS support, you can omit specifying the `CorsConfigurationSource` and Spring Security uses the CORS configuration provided to Spring MVC: +==== [source,java] ---- @EnableWebSecurity @@ -63,9 +68,11 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter { } } ---- +==== -or in XML +The following listing does the same thing in XML: +==== [source,xml] ---- @@ -74,3 +81,4 @@ or in XML ... ---- +==== diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/data.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/data.adoc index 07a1decc3f8..04e5a8c7bf1 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/data.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/data.adoc @@ -2,14 +2,15 @@ == 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. +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 -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: +To use this support, add the `org.springframework.security:spring-security-data` dependency and provide a bean of type `SecurityEvaluationContextExtension`. +In Java configuration, this would look like: +==== [source,java] ---- @Bean @@ -17,20 +18,23 @@ public SecurityEvaluationContextExtension securityEvaluationContextExtension() { return new SecurityEvaluationContextExtension(); } ---- +==== In XML Configuration, this would look like: +==== [source,xml] ---- ---- +==== [[data-query]] === Security Expressions within @Query -Now Spring Security can be used within your queries. -For example: +Now you can use Spring Security within your queries: +==== [source,java] ---- @Repository @@ -39,7 +43,8 @@ public interface MessageRepository extends PagingAndSortingRepository findInbox(Pageable pageable); } ---- +==== This checks to see if the `Authentication.getPrincipal().getId()` is equal to the recipient of the `Message`. -Note that this example assumes you have customized the principal to be an Object that has an id property. -By exposing the `SecurityEvaluationContextExtension` bean, all of the <> are available within the Query. +Note that this example assumes you have customized the principal to be an `Object` that has an `id` property. +By exposing the `SecurityEvaluationContextExtension` bean, all of the <> are available within the query. diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/index.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/index.adoc index 90b9783a1f4..8673bae878e 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/index.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/index.adoc @@ -1,5 +1,7 @@ = Integrations +This section describes various integrations that Spring Security has with other technologies: + include::servlet-api.adoc[] include::data.adoc[] diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/jackson.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/jackson.adoc index 9e6418a1757..d7ef8670ca4 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/jackson.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/jackson.adoc @@ -1,11 +1,12 @@ [[jackson]] == 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). +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 (session replication, Spring Session, and so on). To use it, register the `SecurityJackson2Modules.getModules(ClassLoader)` with `ObjectMapper` (https://github.com/FasterXML/jackson-databind[jackson-databind]): +==== [source,java] ---- ObjectMapper mapper = new ObjectMapper(); @@ -18,13 +19,14 @@ SecurityContext context = new SecurityContextImpl(); // ... String json = mapper.writeValueAsString(context); ---- +==== [NOTE] ==== The following Spring Security modules provide Jackson support: -- spring-security-core (`CoreJackson2Module`) -- spring-security-web (`WebJackson2Module`, `WebServletJackson2Module`, `WebServerJackson2Module`) -- <> (`OAuth2ClientJackson2Module`) -- spring-security-cas (`CasJackson2Module`) +- spring-security-core ({security-api-url}org/springframework/security/jackson2/CoreJackson2Module.html[`CoreJackson2Module`]) +- spring-security-web ({security-api-url}org/springframework/security/web/jackson2/WebJackson2Module.html[`WebJackson2Module`], {security-api-url}org/springframework/security/web/jackson2/WebServletJackson2Module.html[`WebServletJackson2Module`], {security-api-url}org/springframework/security/web/server/jackson2/WebServerJackson2Module.html[`WebServerJackson2Module`]) +- <> ({security-api-url}org/springframework/security/oauth2/client/jackson2/OAuth2ClientJackson2Module.html[`OAuth2ClientJackson2Module`]) +- spring-security-cas ({security-api-url}org/springframework/security/cas/jackson2/CasJackson2Module.html[`CasJackson2Module`]) ==== diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/jsp-taglibs.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/jsp-taglibs.adoc index 3f316832582..b0c1e3a5d9e 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/jsp-taglibs.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/jsp-taglibs.adoc @@ -1,26 +1,30 @@ [[taglibs]] == JSP Tag Libraries -Spring Security has its own taglib which provides basic support for accessing security information and applying security constraints in JSPs. +Spring Security has its own taglib, which provides basic support for accessing security information and applying security constraints in JSPs. === Declaring the Taglib To use any of the tags, you must have the security taglib declared in your JSP: +==== [source,xml] ---- <%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags" %> ---- +==== [[taglibs-authorize]] === 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. -]. -The first approach uses a <>, specified in the `access` attribute of the tag. -The expression evaluation will be delegated to the `SecurityExpressionHandler` defined in the application context (you should have web expressions enabled in your `` namespace configuration to make sure this service is available). -So, for example, you might have +In Spring Security 3.0, it can be used in two ways. +NOTE: The legacy options from Spring Security 2.0 are also supported, but discouraged. + +The first approach uses a <>, which is specified in the `access` attribute of the tag. +The expression evaluation is delegated to the `SecurityExpressionHandler` defined in the application context (you should have web expressions enabled in your `` namespace configuration to make sure this service is available). +So, for example, you might have: + +==== [source,xml] ---- @@ -29,10 +33,11 @@ This content will only be visible to users who have the "supervisor" authority i ---- +==== -When used in conjunction with Spring Security's PermissionEvaluator, the tag can also be used to check permissions. -For example: +When used in conjunction with Spring Security's `PermissionEvaluator`, the tag can also be used to check permissions: +==== [source,xml] ---- @@ -41,12 +46,14 @@ This content will only be visible to users who have read or write permission to ---- +==== -A common requirement is to only show a particular link, if the user is actually allowed to click it. -How can we determine in advance whether something will be allowed? This tag can also operate in an alternative mode which allows you to define a particular URL as an attribute. -If the user is allowed to invoke that URL, then the tag body will be evaluated, otherwise it will be skipped. -So you might have something like +A common requirement is to show only a particular link, assuming the user is actually allowed to click it. +How can we determine in advance whether something is allowed? This tag can also operate in an alternative mode that lets you define a particular URL as an attribute. +If the user is allowed to invoke that URL, the tag body is evaluated. Otherwise, it is skipped. +So you might have something like: +==== [source,xml] ---- @@ -55,60 +62,64 @@ This content will only be visible to users who are authorized to send requests t ---- +==== -To use this tag there must also be an instance of `WebInvocationPrivilegeEvaluator` in your application context. -If you are using the namespace, one will automatically be registered. +To use this tag, you must also have an instance of `WebInvocationPrivilegeEvaluator` in your application context. +If you are using the namespace, one is automatically registered. This is an instance of `DefaultWebInvocationPrivilegeEvaluator`, which creates a dummy web request for the supplied URL and invokes the security interceptor to see whether the request would succeed or fail. -This allows you to delegate to the access-control setup you defined using `intercept-url` declarations within the `` namespace configuration and saves having to duplicate the information (such as the required roles) within your JSPs. -This approach can also be combined with a `method` attribute, supplying the HTTP method, for a more specific match. +This lets you delegate to the access-control setup you defined by using `intercept-url` declarations within the `` namespace configuration and saves having to duplicate the information (such as the required roles) within your JSPs. +You can also combine this approach with a `method` attribute (supplying the HTTP method, such as `POST`) for a more specific match. -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. +You can store the Boolean result of evaluating the tag (whether it grants or denies access) 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 -Hiding a link in a page for unauthorized users doesn't prevent them from accessing the URL. +Hiding a link in a page for unauthorized users does not 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. -If you set the system property `spring.security.disableUISecurity` to `true`, the `authorize` tag will still run but will not hide its contents. -By default it will also surround the content with `...` tags. -This allows you to display "hidden" content with a particular CSS style such as a different background colour. -Try running the "tutorial" sample application with this property enabled, for example. +As part of your testing process, you may want to reveal the hidden areas, to check that links really are secured at the back end. +If you set the `spring.security.disableUISecurity` system property to `true`, the `authorize` tag still runs but does not hide its contents. +By default, it also surrounds the content with `...` tags. +This lets you to display "`hidden`" content with a particular CSS style, such as a different background color. +Try running the "`tutorial`" sample application, for example, with this property enabled. -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). +You can also set the `spring.security.securedUIPrefix` and `spring.security.securedUISuffix` properties if you want to change surrounding text from the default `span` tags (or use empty strings to remove it completely). === 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 `` will render the name of the current user. +So, for example, if the `principal` property of the `Authentication` is an instance of Spring Security's `UserDetails` object, then using `` renders the name of the current user. -Of course, it isn't necessary to use JSP tags for this kind of thing and some people prefer to keep as little logic as possible in the view. +Of course, it is not necessary to use JSP tags for this kind of thing, and some people prefer to keep as little logic as possible in the view. 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 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. -If they don't, it will be skipped. -An example might be +If the current user has all of those permissions, the tag body is evaluated. +If they do not, it is skipped. CAUTION: In general this tag should be considered deprecated. Instead use the <>. +The following listing shows an example: + +==== [source,xml] ---- -This will be shown if the user has all of the permissions represented by the values "1" or "2" on the given object. + ---- +==== -The permissions are passed to the `PermissionFactory` defined in the application context, converting them to ACL `Permission` instances, so they may be any format which is supported by the factory - they don't have to be integers, they could be strings like `READ` or `WRITE`. -If no `PermissionFactory` is found, an instance of `DefaultPermissionFactory` will be used. -The `AclService` from the application context will be used to load the `Acl` instance for the supplied object. -The `Acl` will be invoked with the required permissions to check if all of them are granted. +The permissions are passed to the `PermissionFactory` defined in the application context, converting them to ACL `Permission` instances, so they may be any format that is supported by the factory. They do not have to be integers. They could be strings such as `READ` or `WRITE`. +If no `PermissionFactory` is found, an instance of `DefaultPermissionFactory` is used. +The `AclService` from the application context is used to load the `Acl` instance for the supplied object. +The `Acl` is invoked with the required permissions to check if all of them are granted. This tag also supports the `var` attribute, in the same way as the `authorize` tag. @@ -117,12 +128,14 @@ This tag also supports the `var` attribute, in the same way as the `authorize` t 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. -Normally Spring Security automatically inserts a CSRF form field for any `` tags you use, but if for some reason you cannot use ``, `csrfInput` is a handy replacement. +Normally, Spring Security automatically inserts a CSRF form field for any `` tags you use, but if for some reason you cannot use ``, `csrfInput` is a handy replacement. You should place this tag within an HTML `
` block, where you would normally place other input fields. Do NOT place this tag within a Spring `` block. Spring Security handles Spring forms automatically. +The following listing shows an example: +==== [source,xml] ----
@@ -132,16 +145,19 @@ Spring Security handles Spring forms automatically. ...
---- +==== [[taglibs-csrfmeta]] === 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. +If CSRF protection is enabled, this tag inserts meta tags that contain 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. You should place `csrfMetaTags` within an HTML ` ` block, where you would normally place other meta tags. -Once you use this tag, you can access the form field name, header name, and token value easily using JavaScript. +Once you use this tag, you can access the form field name, header name, and token value by using JavaScript. JQuery is used in this example to make the task easier. +The following listing shows an example: +==== [source,xml] ---- @@ -197,6 +213,6 @@ JQuery is used in this example to make the task easier. ---- +==== If CSRF protection is not enabled, `csrfMetaTags` outputs nothing. - diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/localization.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/localization.adoc index 0f8f9b402ee..d7bff6a2796 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/localization.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/localization.adoc @@ -1,17 +1,18 @@ [[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. +If your application is designed for English-speaking users, you need not do anything as, by default, all Security messages are in English. +If you need to support other locales, this section contains everything you need to know. -All exception messages can be localized, including messages related to authentication failures and access being denied (authorization failures). -Exceptions and logging messages that are focused on developers or system deplopers (including incorrect attributes, interface contract violations, using incorrect constructors, startup time validation, debug-level logging) are not localized and instead are hard-coded in English within Spring Security's code. +All exception messages, including messages related to authentication failures and access being denied (authorization failures), can be localized. +Exceptions and logging messages that are focused on developers or system deployers (including incorrect attributes, interface contract violations, using incorrect constructors, startup time validation, debug-level logging) are not localized and instead are hard-coded in English within Spring Security's code. -Shipping in the `spring-security-core-xx.jar` you will find an `org.springframework.security` package that in turn contains a `messages.properties` file, as well as localized versions for some common languages. -This should be referred to by your `ApplicationContext`, as Spring Security classes implement Spring's `MessageSourceAware` interface and expect the message resolver to be dependency injected at application context startup time. -Usually all you need to do is register a bean inside your application context to refer to the messages. -An example is shown below: +In the `spring-security-core-xx.jar`, you find an `org.springframework.security` package that, in turn, contains a `messages.properties` file as well as localized versions for some common languages. +Your `ApplicationContext` should refer to this, as Spring Security classes implement Spring's `MessageSourceAware` interface and expect the message resolver to be dependency injected at application context startup time. +Usually, all you need to do is register a bean inside your application context to refer to the messages. +The following listing shows an example: +==== [source,xml] ---- ---- +==== The `messages.properties` is named in accordance with standard resource bundles and represents the default language supported by Spring Security messages. This default file is in English. -If you wish to customize the `messages.properties` file, or support other languages, you should copy the file, rename it accordingly, and register it inside the above bean definition. +To customize the `messages.properties` file or support other languages, you should copy the file, rename it accordingly, and register it inside the preceding bean definition. There are not a large number of message keys inside this file, so localization should not be considered a major initiative. -If you do perform localization of this file, please consider sharing your work with the community by logging a JIRA task and attaching your appropriately-named localized version of `messages.properties`. +If you do perform localization of this file, consider sharing your work with the community by logging a JIRA task and attaching your appropriately-named localized version of `messages.properties`. -Spring Security relies on Spring's localization support in order to actually lookup the appropriate message. -In order for this to work, you have to make sure that the locale from the incoming request is stored in Spring's `org.springframework.context.i18n.LocaleContextHolder`. -Spring MVC's `DispatcherServlet` does this for your application automatically, but since Spring Security's filters are invoked before this, the `LocaleContextHolder` needs to be set up to contain the correct `Locale` before the filters are called. +Spring Security relies on Spring's localization support in order to actually look up the appropriate message. +For this to work, you have to make sure that the locale from the incoming request is stored in Spring's `org.springframework.context.i18n.LocaleContextHolder`. +Spring MVC's `DispatcherServlet` does this for your application automatically. However, since Spring Security's filters are invoked before this, the `LocaleContextHolder` needs to be set up to contain the correct `Locale` before the filters are called. You can either do this in a filter yourself (which must come before the Spring Security filters in `web.xml`) or you can use Spring's `RequestContextFilter`. -Please refer to the Spring Framework documentation for further details on using localization with Spring. +See the Spring Framework documentation for further details on using localization with Spring. -The "contacts" sample application is set up to use localized messages. +The `contacts` sample application is set up to use localized messages. diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/mvc.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/mvc.adoc index fe34eb8e29f..020e209adff 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/mvc.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/mvc.adoc @@ -8,24 +8,25 @@ This section covers the integration in further detail. === @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. +The replacement is `@EnableWebSecurity`, which adds the Spring MVC features, based upon the classpath. -To enable Spring Security integration with Spring MVC add the `@EnableWebSecurity` annotation to your configuration. +To enable Spring Security integration with Spring MVC, add the `@EnableWebSecurity` annotation to your configuration. -NOTE: Spring Security provides the configuration using Spring MVC's https://docs.spring.io/spring/docs/5.0.0.RELEASE/spring-framework-reference/web.html#mvc-config-customize[WebMvcConfigurer]. -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. +NOTE: Spring Security provides the configuration by using Spring MVC's https://docs.spring.io/spring/docs/5.0.0.RELEASE/spring-framework-reference/web.html#mvc-config-customize[`WebMvcConfigurer`]. +This means that, if you use more advanced options, such as integrating with `WebMvcConfigurationSupport` directly, you need to manually provide the Spring Security configuration. [[mvc-requestmatcher]] === 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. +This is helpful to ensure that your Security rules match the logic used to handle your requests. -In order to use `MvcRequestMatcher` you must place the Spring Security Configuration in the same `ApplicationContext` as your `DispatcherServlet`. +To use `MvcRequestMatcher`, you must place the Spring Security Configuration in the same `ApplicationContext` as your `DispatcherServlet`. This is necessary because Spring Security's `MvcRequestMatcher` expects a `HandlerMappingIntrospector` bean with the name of `mvcHandlerMappingIntrospector` to be registered by your Spring MVC configuration that is used to perform the matching. -For a `web.xml` this means that you should place your configuration in the `DispatcherServlet.xml`. +For a `web.xml` file, this means that you should place your configuration in the `DispatcherServlet.xml`: +==== [source,xml] ---- @@ -53,9 +54,11 @@ For a `web.xml` this means that you should place your configuration in the `Disp / ---- +==== -Below `WebSecurityConfiguration` in placed in the ``DispatcherServlet``s `ApplicationContext`. +The following `WebSecurityConfiguration` in placed in the `ApplicationContext` of the `DispatcherServlet`. +==== [source,java] ---- public class SecurityInitializer extends @@ -78,26 +81,32 @@ public class SecurityInitializer extends } } ---- +==== [NOTE] ==== -It is always recommended to provide authorization rules by matching on the `HttpServletRequest` and method security. +We always recommend that you provide authorization rules by matching on the `HttpServletRequest` and method security. -Providing authorization rules by matching on `HttpServletRequest` is good because it happens very early in the code path and helps reduce the https://en.wikipedia.org/wiki/Attack_surface[attack surface]. -Method security ensures that if someone has bypassed the web authorization rules, that your application is still secured. -This is what is known as https://en.wikipedia.org/wiki/Defense_in_depth_(computing)[Defence in Depth] +Providing authorization rules by matching on `HttpServletRequest` is good, because it happens very early in the code path and helps reduce the https://en.wikipedia.org/wiki/Attack_surface[attack surface]. +Method security ensures that, if someone has bypassed the web authorization rules, your application is still secured. +This is known as https://en.wikipedia.org/wiki/Defense_in_depth_(computing)[Defense in Depth] ==== Consider a controller that is mapped as follows: +==== [source,java] ---- @RequestMapping("/admin") public String admin() { + ... +} ---- +==== -If we wanted to restrict access to this controller method to admin users, a developer can provide authorization rules by matching on the `HttpServletRequest` with the following: +To restrict access to this controller method to admin users, you can provide authorization rules by matching on the `HttpServletRequest` with the following: +==== [source,java] ---- protected configure(HttpSecurity http) throws Exception { @@ -107,27 +116,30 @@ protected configure(HttpSecurity http) throws Exception { ); } ---- +==== -or in XML +The following listing does the same thing in XML: +==== [source,xml] ---- ---- +==== -With either configuration, the URL `/admin` will require the authenticated user to be an admin user. -However, depending on our Spring MVC configuration, the URL `/admin.html` will also map to our `admin()` method. -Additionally, depending on our Spring MVC configuration, the URL `/admin/` will also map to our `admin()` method. +With either configuration, the `/admin` URL requires the authenticated user to be an admin user. +However, depending on our Spring MVC configuration, the `/admin.html` URL also maps to our `admin()` method. +Additionally, depending on our Spring MVC configuration, the `/admin` URL also maps to our `admin()` method. -The problem is that our security rule is only protecting `/admin`. +The problem is that our security rule protects only `/admin`. We could add additional rules for all the permutations of Spring MVC, but this would be quite verbose and tedious. -Instead, we can leverage Spring Security's `MvcRequestMatcher`. -The following configuration will protect the same URLs that Spring MVC will match on by using Spring MVC to match on the URL. - +Instead, we can use Spring Security's `MvcRequestMatcher`. +The following configuration protects the same URLs that Spring MVC matches on by using Spring MVC to match on the URL. +==== [source,java] ---- protected configure(HttpSecurity http) throws Exception { @@ -137,24 +149,27 @@ protected configure(HttpSecurity http) throws Exception { ); } ---- +==== -or in XML +The following XML has the same effect: +==== [source,xml] ---- ---- +==== [[mvc-authentication-principal]] === @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. -If you use XML based configuration, you must add this yourself. -For example: +Spring Security provides `AuthenticationPrincipalArgumentResolver`, which can automatically resolve the current `Authentication.getPrincipal()` for Spring MVC arguments. +By using `@EnableWebSecurity`, you automatically have this added to your Spring MVC configuration. +If you use XML-based configuration, you must add this yourself: +==== [source,xml] ---- @@ -163,11 +178,13 @@ For example: ---- +==== -Once `AuthenticationPrincipalArgumentResolver` is properly configured, you can be entirely decoupled from Spring Security in your Spring MVC layer. +Once you have properly configured `AuthenticationPrincipalArgumentResolver`, you can entirely decouple from Spring Security in your Spring MVC layer. -Consider a situation where a custom `UserDetailsService` that returns an `Object` that implements `UserDetails` and your own `CustomUser` `Object`. The `CustomUser` of the currently authenticated user could be accessed using the following code: +Consider a situation where a custom `UserDetailsService` returns an `Object` that implements `UserDetails` and your own `CustomUser` `Object`. The `CustomUser` of the currently authenticated user could be accessed by using the following code: +==== [source,java] ---- @RequestMapping("/messages/inbox") @@ -179,9 +196,11 @@ public ModelAndView findMessagesForUser() { // .. find messages for this user and return them ... } ---- +==== -As of Spring Security 3.2 we can resolve the argument more directly by adding an annotation. For example: +As of Spring Security 3.2, we can resolve the argument more directly by adding an annotation: +==== [source,java] ---- import org.springframework.security.core.annotation.AuthenticationPrincipal; @@ -194,12 +213,13 @@ public ModelAndView findMessagesForUser(@AuthenticationPrincipal CustomUser cust // .. find messages for this user and return them ... } ---- +==== -Sometimes it may be necessary to transform the principal in some way. -For example, if `CustomUser` needed to be final it could not be extended. -In this situation the `UserDetailsService` might returns an `Object` that implements `UserDetails` and provides a method named `getCustomUser` to access `CustomUser`. -For example, it might look like: +Sometimes, you may need to transform the principal in some way. +For example, if `CustomUser` needed to be final, it could not be extended. +In this situation, the `UserDetailsService` might return an `Object` that implements `UserDetails` and provides a method named `getCustomUser` to access `CustomUser`: +==== [source,java] ---- public class CustomUserUserDetails extends User { @@ -209,9 +229,11 @@ public class CustomUserUserDetails extends User { } } ---- +==== -We could then access the `CustomUser` using a https://docs.spring.io/spring/docs/current/spring-framework-reference/html/expressions.html[SpEL expression] that uses `Authentication.getPrincipal()` as the root object: +We could then access the `CustomUser` by using a https://docs.spring.io/spring/docs/current/spring-framework-reference/html/expressions.html[SpEL expression] that uses `Authentication.getPrincipal()` as the root object: +==== [source,java] ---- import org.springframework.security.core.annotation.AuthenticationPrincipal; @@ -224,10 +246,12 @@ public ModelAndView findMessagesForUser(@AuthenticationPrincipal(expression = "c // .. find messages for this user and return them ... } ---- +==== -We can also refer to Beans in our SpEL expressions. -For example, the following could be used if we were using JPA to manage our Users and we wanted to modify and save a property on the current user. +We can also refer to beans in our SpEL expressions. +For example, we could use the following if we were using JPA to manage our users and if we wanted to modify and save a property on the current user: +==== [source,java] ---- import org.springframework.security.core.annotation.AuthenticationPrincipal; @@ -244,13 +268,15 @@ public ModelAndView updateName(@AuthenticationPrincipal(expression = "@jpaEntity // ... } ---- +==== -We can further remove our dependency on Spring Security by making `@AuthenticationPrincipal` a meta annotation on our own annotation. -Below we demonstrate how we could do this on an annotation named `@CurrentUser`. +We can further remove our dependency on Spring Security by making `@AuthenticationPrincipal` a meta-annotation on our own annotation. +The next example demonstrates how we could do so on an annotation named `@CurrentUser`. -NOTE: It is important to realize that in order to remove the dependency on Spring Security, it is the consuming application that would create `@CurrentUser`. -This step is not strictly required, but assists in isolating your dependency to Spring Security to a more central location. +NOTE: To remove the dependency on Spring Security, it is the consuming application that would create `@CurrentUser`. +This step is not strictly required but assists in isolating your dependency to Spring Security to a more central location. +==== [source,java] ---- @Target({ElementType.PARAMETER, ElementType.TYPE}) @@ -259,10 +285,12 @@ This step is not strictly required, but assists in isolating your dependency to @AuthenticationPrincipal public @interface CurrentUser {} ---- +==== -Now that `@CurrentUser` has been specified, we can use it to signal to resolve our `CustomUser` of the currently authenticated user. -We have also isolated our dependency on Spring Security to a single file. +We have isolated our dependency on Spring Security to a single file. +Now that `@CurrentUser` has been specified, we can use it to signal to resolve our `CustomUser` of the currently authenticated user: +==== [source,java] ---- @RequestMapping("/messages/inbox") @@ -271,15 +299,16 @@ public ModelAndView findMessagesForUser(@CurrentUser CustomUser customUser) { // .. find messages for this user and return them ... } ---- - +==== [[mvc-async]] === 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. -For example, the following method will automatically have its `Callable` invoked with the `SecurityContext` that was available when the `Callable` was created: +With no additional configuration, Spring Security automatically sets up the `SecurityContext` to the `Thread` that invokes a `Callable` returned by your controllers. +For example, the following method automatically has its `Callable` invoked with the `SecurityContext` that was available when the `Callable` was created: +==== [source,java] ---- @RequestMapping(method=RequestMethod.POST) @@ -293,26 +322,27 @@ return new Callable() { }; } ---- +==== -[NOTE] .Associating SecurityContext to Callable's -==== -More technically speaking, Spring Security integrates with `WebAsyncManager`. -The `SecurityContext` that is used to process the `Callable` is the `SecurityContext` that exists on the `SecurityContextHolder` at the time `startCallableProcessing` is invoked. -==== +NOTE: More technically speaking, Spring Security integrates with `WebAsyncManager`. +The `SecurityContext` that is used to process the `Callable` is the `SecurityContext` that exists on the `SecurityContextHolder` when `startCallableProcessing` is invoked. There is no automatic integration with a `DeferredResult` that is returned by controllers. -This is because `DeferredResult` is processed by the users and thus there is no way of automatically integrating with it. +This is because `DeferredResult` is processed by the users and, thus, there is no way of automatically integrating with it. However, you can still use <> to provide transparent integration with Spring Security. [[mvc-csrf]] === Spring MVC and CSRF Integration +Spring Security integrates with Spring MVC to add CSRF protection. + ==== Automatic Token Inclusion -Spring Security will automatically <> 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: +Spring Security automatically <> within forms that use the https://docs.spring.io/spring-framework/docs/current/reference/html/web.html#mvc-view-jsp-formtaglib[Spring MVC form tag]. +Consider the following JSP: +==== [source,xml] ---- ---- +==== -Will output HTML that is similar to the following: +The preceding example output HTMLs that is similar to the following: +==== [source,xml] ---- @@ -350,16 +382,18 @@ Will output HTML that is similar to the following: ---- +==== [[mvc-csrf-resolver]] ==== Resolving the CsrfToken -Spring Security provides `CsrfTokenArgumentResolver` which can automatically resolve the current `CsrfToken` for Spring MVC arguments. -By using <> you will automatically have this added to your Spring MVC configuration. -If you use XML based configuration, you must add this yourself. +Spring Security provides `CsrfTokenArgumentResolver`, which can automatically resolve the current `CsrfToken` for Spring MVC arguments. +By using <>, you automatically have this added to your Spring MVC configuration. +If you use XML-based configuration, you must add this yourself. -Once `CsrfTokenArgumentResolver` is properly configured, you can expose the `CsrfToken` to your static HTML based application. +Once `CsrfTokenArgumentResolver` is properly configured, you can expose the `CsrfToken` to your static HTML based application: +==== [source,java] ---- @RestController @@ -371,6 +405,7 @@ public class CsrfController { } } ---- +==== It is important to keep the `CsrfToken` a secret from other domains. -This means if you are using https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS[Cross Origin Sharing (CORS)], you should **NOT** expose the `CsrfToken` to any external domains. +This means that, if you use https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS[Cross Origin Sharing (CORS)], you should *NOT* expose the `CsrfToken` to any external domains. diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/servlet-api.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/servlet-api.adoc index 5e4077c3f93..c2a4f0a47e9 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/servlet-api.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/servlet-api.adoc @@ -6,24 +6,26 @@ This section describes how Spring Security is integrated with the Servlet API. [[servletapi-25]] === Servlet 2.5+ Integration +This section describes how Spring Security integrates with the Servlet 2.5 specification. + [[servletapi-remote-user]] ==== 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. +https://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletRequest.html#getRemoteUser()[`HttpServletRequest.getRemoteUser()`] returns 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. -Knowing if the user is authenticated or not can be useful for determining if certain UI elements should be shown or not (i.e. a log out link should only be displayed if the user is authenticated). +Additionally, you can check this for null to determine whether a user has authenticated or is anonymous. +Knowing whether the user is authenticated or not can be useful for determining if certain UI elements should be shown or not (for example, a logout link that should be displayed only if the user is authenticated). [[servletapi-user-principal]] ==== 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. +https://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletRequest.html#getUserPrincipal()[`HttpServletRequest.getUserPrincipal()`] returns the result of `SecurityContextHolder.getContext().getAuthentication()`. +This means that 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. For example, you might have created a custom `UserDetailsService` that returns a custom `UserDetails` containing a first and last name for your user. You could obtain this information with the following: - +==== [source,java] ---- Authentication auth = httpServletRequest.getUserPrincipal(); @@ -33,43 +35,44 @@ MyCustomUserDetails userDetails = (MyCustomUserDetails) auth.getPrincipal(); String firstName = userDetails.getFirstName(); String lastName = userDetails.getLastName(); ---- - -[NOTE] -==== -It should be noted that it is typically bad practice to perform so much logic throughout your application. -Instead, one should centralize it to reduce any coupling of Spring Security and the Servlet API's. ==== +NOTE: It is typically bad practice to perform logic throughout your application. +Instead, you should centralize it to reduce any coupling of Spring Security and the Servlet API. + [[servletapi-user-in-role]] ==== 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. +https://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletRequest.html#isUserInRole(java.lang.String)[`HttpServletRequest.isUserInRole(String)`] determines if `SecurityContextHolder.getContext().getAuthentication().getAuthorities()` contains a `GrantedAuthority` with the role passed into `isUserInRole(String)`. +Typically, users should not pass the `ROLE_` prefix to 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: +==== [source,java] ---- boolean isAdmin = httpServletRequest.isUserInRole("ADMIN"); ---- +==== 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 -The following section describes the Servlet 3 methods that Spring Security integrates with. +The following section describes the Servlet 3 methods with which Spring Security integrates. [[servletapi-authenticate]] ==== 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). +You can use the https://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletRequest.html#authenticate%28javax.servlet.http.HttpServletResponse%29[`HttpServletRequest.authenticate(HttpServletRequest,HttpServletResponse)`] method to ensure that a user is authenticated. +If they are not authenticated, the configured `AuthenticationEntryPoint` is used to request the user to authenticate (redirect to the login page). [[servletapi-login]] ==== 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": +You can use 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 to authenticate the user with the current `AuthenticationManager`. +For example, the following would attempt to authenticate with a username of `user` and a password of `password`: +==== [source,java] ---- try { @@ -78,27 +81,26 @@ httpServletRequest.login("user","password"); // fail to authenticate } ---- - -[NOTE] -==== -It is not necessary to catch the ServletException if you want Spring Security to process the failed authentication attempt. ==== +NOTE: You need not catch the `ServletException` if you want Spring Security to process the failed authentication attempt. + [[servletapi-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. +You can use the https://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletRequest.html#logout%28%29[`HttpServletRequest.logout()`] method to log out the current user. -Typically this means that the SecurityContextHolder will be cleared out, the HttpSession will be invalidated, any "Remember Me" authentication will be cleaned up, etc. -However, the configured LogoutHandler implementations will vary depending on your Spring Security configuration. -It is important to note that after HttpServletRequest.logout() has been invoked, you are still in charge of writing a response out. -Typically this would involve a redirect to the welcome page. +Typically, this means that the `SecurityContextHolder` is cleared out, the `HttpSession` is invalidated, any "`Remember Me`" authentication is cleaned up, and so on. +However, the configured `LogoutHandler` implementations vary, depending on your Spring Security configuration. +Note that, after `HttpServletRequest.logout()` has been invoked, you are still in charge of writing out a response. +Typically, this would involve a redirect to the welcome page. [[servletapi-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: +The https://docs.oracle.com/javaee/6/api/javax/servlet/AsyncContext.html#start%28java.lang.Runnable%29[`AsyncContext.start(Runnable)`] method ensures your credentials are propagated to the new `Thread`. +By using Spring Security's concurrency support, Spring Security overrides `AsyncContext.start(Runnable)` to ensure that the current `SecurityContext` is used when processing the Runnable. +The following example outputs the current user's Authentication: +==== [source,java] ---- final AsyncContext async = httpServletRequest.startAsync(); @@ -116,13 +118,15 @@ async.start(new Runnable() { } }); ---- +==== [[servletapi-async]] ==== 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: +If you use Java-based configuration, you are ready to go. +If you use XML configuration, a few updates are necessary. +The first step is to ensure that you have updated your `web.xml` file to use at least the 3.0 schema: +==== [source,xml] ---- ---- +==== -Next you need to ensure that your springSecurityFilterChain is setup for processing asynchronous requests. +Next, you need to ensure that your `springSecurityFilterChain` is set up for processing asynchronous requests: +==== [source,xml] ---- @@ -151,16 +157,17 @@ Next you need to ensure that your springSecurityFilterChain is setup for process ASYNC
---- +==== -That's it! -Now Spring Security will ensure that your SecurityContext is propagated on asynchronous requests too. +Now Spring Security ensures that your `SecurityContext` is propagated on asynchronous requests, too. -So how does it work? If you are not really interested, feel free to skip the remainder of this section, otherwise read on. -Most of this is built into the Servlet specification, but there is a little bit of tweaking that Spring Security does to ensure things work with asynchronous requests properly. -Prior to Spring Security 3.2, the SecurityContext from the SecurityContextHolder was automatically saved as soon as the HttpServletResponse was committed. -This can cause issues in an Async environment. -For example, consider the following: +So how does it work? If you are not really interested, feel free to skip the remainder of this section +Most of this is built into the Servlet specification, but there is a little bit of tweaking that Spring Security does to ensure things work properly with asynchronous requests. +Prior to Spring Security 3.2, the `SecurityContext` from the `SecurityContextHolder` was automatically saved as soon as the `HttpServletResponse` was committed. +This can cause issues in an asynchronous environment. +Consider the following example: +==== [source,java] ---- httpServletRequest.startAsync(); @@ -179,12 +186,13 @@ new Thread("AsyncThread") { } }.start(); ---- +==== -The issue is that this Thread is not known to Spring Security, so the SecurityContext is not propagated to it. -This means when we commit the HttpServletResponse there is no SecurityContext. -When Spring Security automatically saved the SecurityContext on committing the HttpServletResponse it would lose our logged in user. +The issue is that this `Thread` is not known to Spring Security, so the `SecurityContext` is not propagated to it. +This means that, when we commit the `HttpServletResponse`, there is no `SecurityContext`. +When Spring Security automatically saved the `SecurityContext` on committing the `HttpServletResponse`, it would lose a logged in user. -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. +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 @@ -192,4 +200,4 @@ The following section describes the Servlet 3.1 methods that Spring Security int [[servletapi-change-session-id]] ==== 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 <> attacks in Servlet 3.1 and higher. +https://docs.oracle.com/javaee/7/api/javax/servlet/http/HttpServletRequest.html#changeSessionId()[`HttpServletRequest.changeSessionId()`] is the default method for protecting against <> attacks in Servlet 3.1 and higher. diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/websocket.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/websocket.adoc index ffcf46b5a47..b785fe5f8c7 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/websocket.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/websocket.adoc @@ -6,18 +6,18 @@ This section describes how to use Spring Security's WebSocket support. .Direct JSR-356 Support **** -Spring Security does not provide direct JSR-356 support because doing so would provide little value. -This is because the format is unknown, so there is https://docs.spring.io/spring/docs/current/spring-framework-reference/html/websocket.html#websocket-intro-sub-protocol[little Spring can do to secure an unknown format]. -Additionally, JSR-356 does not provide a way to intercept messages, so security would be rather invasive. +Spring Security does not provide direct JSR-356 support, because doing so would provide little value. +This is because the format is unknown, and there is https://docs.spring.io/spring/docs/current/spring-framework-reference/html/websocket.html#websocket-intro-sub-protocol[little Spring can do to secure an unknown format]. +Additionally, JSR-356 does not provide a way to intercept messages, so security would be invasive. **** [[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`. -For example: +To configure authorization by using Java Configuration, extend the `AbstractSecurityWebSocketMessageBrokerConfigurer` and configure the `MessageSecurityMetadataSourceRegistry`: +==== [source,java] ---- @Configuration @@ -30,16 +30,15 @@ public class WebSocketSecurityConfig } } ---- - -This will ensure that: - -<1> Any inbound CONNECT message requires a valid CSRF token to enforce <> -<2> The SecurityContextHolder is populated with the user within the simpUser header attribute for any inbound request. -<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 <> +<1> Any inbound CONNECT message requires a valid CSRF token to enforce the <>. +<2> The `SecurityContextHolder` is populated with the user within the `simpUser` header attribute for any inbound request. +<3> Our messages require the proper authorization. Specifically, any inbound message that starts with `/user/` will requires `ROLE_USER`. You can find additional details on authorization in <> +==== Spring Security also provides <> support for securing WebSockets. A comparable XML based configuration looks like the following: +==== [source,xml] ---- @@ -47,29 +46,27 @@ A comparable XML based configuration looks like the following: ---- - -This will ensure that: - -<1> Any inbound CONNECT message requires a valid CSRF token to enforce <> -<2> The SecurityContextHolder is populated with the user within the simpUser header attribute for any inbound request. -<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 <> +<1> Any inbound CONNECT message requires a valid CSRF token to enforce the <>. +<2> The `SecurityContextHolder` is populated with the user within the `simpUser` header attribute for any inbound request. +<3> Our messages require the proper authorization. Specifically, any inbound message that starts with `/user/` require `ROLE_USER`. You can find additional details on authorization in <>. +==== [[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. -If you are using Spring Security, the `Principal` on the `HttpServletRequest` is overridden automatically. +This means that the `Principal` on the `HttpServletRequest` is handed off to WebSockets. +If you use Spring Security, the `Principal` on the `HttpServletRequest` is overridden automatically. -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. +More concretely, to ensure a user has authenticated to your WebSocket application, all you need to do is ensure that you set up Spring Security to authenticate your HTTP based web application. [[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`. -For example: +To configure authorization by using Java configuration, extend the `AbstractSecurityWebSocketMessageBrokerConfigurer` and configure the `MessageSecurityMetadataSourceRegistry`: +==== [source,java] ---- @Configuration @@ -88,19 +85,18 @@ public class WebSocketSecurityConfig extends AbstractSecurityWebSocketMessageBro } } ---- - -This will ensure that: - -<1> Any message without a destination (i.e. anything other than Message type of MESSAGE or SUBSCRIBE) will require the user to be authenticated -<2> Anyone can subscribe to /user/queue/errors -<3> Any message that has a destination starting with "/app/" will be require the user to have the role ROLE_USER -<4> Any message that starts with "/user/" or "/topic/friends/" that is of type SUBSCRIBE will require ROLE_USER -<5> Any other message of type MESSAGE or SUBSCRIBE is rejected. Due to 6 we do not need this step, but it illustrates how one can match on specific message types. -<6> Any other Message is rejected. This is a good idea to ensure that you do not miss any messages. +<1> Any message without a destination (anything other than message type of `MESSAGE` or `SUBSCRIBE`) requires the user to be authenticated. +<2> Anyone can subscribe to `/user/queue/errors`. +<3> Any message that has a destination starting with `/app/` requires the user to have a role of `ROLE_USER`. +<4> Any message that starts with `/user/` or `/topic/friends/` that is of type `SUBSCRIBE` requires `ROLE_USER`. +<5> Any other message of type `MESSAGE` or `SUBSCRIBE` is rejected. Due to 6, we do not need this step, but it illustrates how you can match on specific message types. +<6> Any other message is rejected. This is a good idea to ensure that you do not miss any messages. +==== Spring Security also provides <> support for securing WebSockets. A comparable XML based configuration looks like the following: +==== [source,xml] ---- @@ -123,115 +119,117 @@ A comparable XML based configuration looks like the following: ---- - -This will ensure that: - -<1> Any message of type CONNECT, UNSUBSCRIBE, or DISCONNECT will require the user to be authenticated +<1> Any message of type `CONNECT`, `UNSUBSCRIBE`, or `DISCONNECT` requires the user to be authenticated. <2> Anyone can subscribe to /user/queue/errors <3> Any message that has a destination starting with "/app/" will be require the user to have the role ROLE_USER <4> Any message that starts with "/user/" or "/topic/friends/" that is of type SUBSCRIBE will require ROLE_USER <5> Any other message of type MESSAGE or SUBSCRIBE is rejected. Due to 6 we do not need this step, but it illustrates how one can match on specific message types. <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 -In order to properly secure your application it is important to understand Spring's WebSocket support. +To properly secure your application, you need to understand Spring's WebSocket support. [[websocket-authorization-notes-messagetypes]] ===== 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. +You need to understand the distinction between `SUBSCRIBE` and `MESSAGE` types of messages and how they work within Spring. -Consider a chat application. +Consider a chat application: -* The system can send notifications MESSAGE to all users through a destination of "/topic/system/notifications" -* Clients can receive notifications by SUBSCRIBE to the "/topic/system/notifications". +* The system can send a notification `MESSAGE` to all users through a destination of `/topic/system/notifications`. +* Clients can receive notifications by `SUBSCRIBE` to the `/topic/system/notifications`. -While we want clients to be able to SUBSCRIBE to "/topic/system/notifications", we do not want to enable them to send a MESSAGE to that destination. -If we allowed sending a MESSAGE to "/topic/system/notifications", then clients could send a message directly to that endpoint and impersonate the system. +While we want clients to be able to `SUBSCRIBE` to `/topic/system/notifications`, we do not want to enable them to send a `MESSAGE` to that destination. +If we allowed sending a `MESSAGE` to `/topic/system/notifications`, clients could send a message directly to that endpoint and impersonate the system. -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/"). +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] (`/topic/` or `/queue/`). [[websocket-authorization-notes-destinations]] ===== WebSocket Authorization on Destinations -It is also is important to understand how destinations are transformed. +You should also understand how destinations are transformed. -Consider a chat application. +Consider a chat application: -* Users can send messages to a specific user by sending a message to the destination of "/app/chat". -* The application sees the message, ensures that the "from" attribute is specified as the current user (we cannot trust the client). -* The application then sends the message to the recipient using `SimpMessageSendingOperations.convertAndSendToUser("toUser", "/queue/messages", message)`. -* The message gets turned into the destination of "/queue/user/messages-" +* Users can send messages to a specific user by sending a message to the `/app/chat` destination. +* The application sees the message, ensures that the `from` attribute is specified as the current user (we cannot trust the client). +* The application then sends the message to the recipient by using `SimpMessageSendingOperations.convertAndSendToUser("toUser", "/queue/messages", message)`. +* The message gets turned into the destination of `/queue/user/messages-`. -With the application above, we want to allow our client to listen to "/user/queue" which is transformed into "/queue/user/messages-". -However, we do not want the client to be able to listen to "/queue/*" because that would allow the client to see messages for every user. +With this chat application, we want to let our client to listen `/user/queue`, which is transformed into `/queue/user/messages-`. +However, we do not want the client to be able to listen to `/queue/*`, because that would let the client see messages for every user. -In general, it is common for applications to deny any SUBSCRIBE sent to a message 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/"). -Of course we may provide exceptions to account for things like +In general, it is common for applications to deny any `SUBSCRIBE` sent to a message that starts with the https://docs.spring.io/spring/docs/current/spring-framework-reference/html/websocket.html#websocket-stomp[broker prefix] (`/topic/` or `/queue/`). +We may provide exceptions to account for things like +//FIXME: Like what? [[websocket-authorization-notes-outbound]] ==== 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`. +The Spring Framework reference documentation 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. +Note that Spring Security secures only the `clientInboundChannel`. Spring Security does not attempt to secure the `clientOutboundChannel`. The most important reason for this is performance. -For every message that goes in, there are typically many more that go out. +For every message that goes in, typically many more go out. Instead of securing the outbound messages, we encourage securing the subscription to the endpoints. [[websocket-sameorigin]] === 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. +Note 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? Consider the following scenario. -A user visits bank.com and authenticates to their account. -The same user opens another tab in their browser and visits evil.com. -The Same Origin Policy ensures that evil.com cannot read or write data to bank.com. +A user visits `bank.com` and authenticates to their account. +The same user opens another tab in their browser and visits `evil.com`. +The Same Origin Policy ensures that `evil.com` cannot read data from or write data to `bank.com`. -With WebSockets the Same Origin Policy does not apply. -In fact, unless bank.com explicitly forbids it, evil.com can read and write data on behalf of the user. -This means that anything the user can do over the webSocket (i.e. transfer money), evil.com can do on that users behalf. +With WebSockets, the Same Origin Policy does not apply. +In fact, unless `bank.com` explicitly forbids it, `evil.com` can read and write data on behalf of the user. +This means that anything the user can do over the webSocket (such as transferring money), `evil.com` can do on that user's behalf. -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. +Since SockJS tries to emulate WebSockets, it also bypasses the Same Origin Policy. +This means that developers need to explicitly protect their applications from external domains when they use SockJS. [[websocket-sameorigin-spring]] ==== 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_%2528computing%2529[defence in depth]. +Spring Security adds an additional layer of protection to provide https://en.wikipedia.org/wiki/Defence_in_depth_(non-military)#Information_security[defense in depth]. [[websocket-sameorigin-csrf]] ==== Adding CSRF to Stomp Headers -By default Spring Security requires the <> in any CONNECT message type. +By default, Spring Security requires the <> in any `CONNECT` message type. This ensures that only a site that has access to the CSRF token can connect. -Since only the *Same Origin* can access the CSRF token, external domains are not allowed to make a connection. +Since only the *same origin* can access the CSRF token, external domains are not allowed to make a connection. Typically we need to include the CSRF token in an HTTP header or an HTTP parameter. However, SockJS does not allow for these options. -Instead, we must include the token in the Stomp headers +Instead, we must include the token in the Stomp headers. -Applications can <> by accessing the request attribute named _csrf. -For example, the following will allow accessing the `CsrfToken` in a JSP: +Applications can <> by accessing the request attribute named `_csrf`. +For example, the following allows accessing the `CsrfToken` in a JSP: +==== [source,javascript] ---- var headerName = "${_csrf.headerName}"; var token = "${_csrf.token}"; ---- +==== -If you are using static HTML, you can expose the `CsrfToken` on a REST endpoint. -For example, the following would expose the `CsrfToken` on the URL /csrf +If you use static HTML, you can expose the `CsrfToken` on a REST endpoint. +For example, the following would expose the `CsrfToken` on the `/csrf` URL: +==== [source,java] ---- @RestController @@ -243,29 +241,30 @@ public class CsrfController { } } ---- +==== -The JavaScript can make a REST call to the endpoint and use the response to populate the headerName and the token. +The JavaScript can make a REST call to the endpoint and use the response to populate the `headerName` and the token. -We can now include the token in our Stomp client. -For example: +We can now include the token in our Stomp client: +==== [source,javascript] ---- -... var headers = {}; headers[headerName] = token; stompClient.connect(headers, function(frame) { ... - -} +}) ---- +==== [[websocket-sameorigin-disable]] ==== 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: +If you want to let other domains access your site, you can disable Spring Security's protection. +For example, in Java configuration you can use the following: +==== [source,java] ---- @Configuration @@ -279,24 +278,25 @@ public class WebSocketSecurityConfig extends AbstractSecurityWebSocketMessageBro } } ---- - +==== [[websocket-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. +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 may use an https://github.com/sockjs/sockjs-client/tree/v0.3.4[transport that leverages an iframe]. -By default Spring Security will <> the site from being framed to prevent Clickjacking attacks. -To allow SockJS frame based transports to work, we need to configure Spring Security to allow the same origin to frame the content. +SockJS may use a https://github.com/sockjs/sockjs-client/tree/v0.3.4[transport that leverages an iframe]. +By default, Spring Security <> the site from being framed to prevent clickjacking attacks. +To allow SockJS frame-based transports to work, we need to configure Spring Security to let the same origin frame the content. -You can customize X-Frame-Options with the <> element. -For example, the following will instruct Spring Security to use "X-Frame-Options: SAMEORIGIN" which allows iframes within the same domain: +You can customize `X-Frame-Options` with the <> element. +For example, the following instructs Spring Security to use `X-Frame-Options: SAMEORIGIN`, which allows iframes within the same domain: +==== [source,xml] ---- @@ -308,9 +308,11 @@ For example, the following will instruct Spring Security to use "X-Frame-Options ---- +==== -Similarly, you can customize frame options to use the same origin within Java Configuration using the following: +Similarly, you can customize frame options to use the same origin within Java Configuration by using the following: +==== [source,java] ---- @EnableWebSecurity @@ -329,24 +331,26 @@ public class WebSecurityConfig extends } } ---- +==== [[websocket-sockjs-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. +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. However, SockJS does not allow for these options. Instead, we must include the token in the Stomp headers as described in <>. -It also means we need to relax our CSRF protection with the web layer. +It also means that we need to relax our CSRF protection with the web layer. Specifically, we want to disable CSRF protection for our connect URLs. We do NOT want to disable CSRF protection for every URL. -Otherwise our site will be vulnerable to CSRF attacks. +Otherwise, our site is vulnerable to CSRF attacks. -We can easily achieve this by providing a CSRF RequestMatcher. -Our Java Configuration makes this extremely easy. -For example, if our stomp endpoint is "/chat" we can disable CSRF protection for only URLs that start with "/chat/" using the following configuration: +We can easily achieve this by providing a CSRF `RequestMatcher`. +Our Java configuration makes this easy. +For example, if our stomp endpoint is `/chat`, we can disable CSRF protection only for URLs that start with `/chat/` by using the following configuration: +==== [source,java] ---- @Configuration @@ -371,11 +375,14 @@ public class WebSecurityConfig ... ) ... + } + } ---- +==== -If we are using XML based configuration, we can use the <>. -For example: +If we use XML-based configuration, we can use the <>: +==== [source,xml] ---- @@ -400,3 +407,4 @@ For example: ---- +==== diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/java-configuration/index.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/java-configuration/index.adoc index 3ba5432ddcf..56cff5437a7 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/java-configuration/index.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/java-configuration/index.adoc @@ -1,21 +1,21 @@ - [[jc]] = Java Configuration -General support for https://docs.spring.io/spring/docs/3.1.x/spring-framework-reference/html/beans.html#beans-java[Java Configuration] was added to Spring Framework in Spring 3.1. -Since Spring Security 3.2 there has been Spring Security Java Configuration support which enables users to easily configure Spring Security without the use of any XML. +General support for https://docs.spring.io/spring/docs/3.1.x/spring-framework-reference/html/beans.html#beans-java[Java configuration] was added to Spring Framework in Spring 3.1. +Spring Security 3.2 introduced Java configuration to let users configure Spring Security without the use of any XML. -If you are familiar with the <> then you should find quite a few similarities between it and the Security Java Configuration support. +If you are familiar with the <>, you should find quite a few similarities between it and Spring Security Java configuration. NOTE: Spring Security provides https://github.com/spring-projects/spring-security-samples/tree/main/servlet/java-configuration[lots of sample applications] which demonstrate the use of Spring Security Java Configuration. == Hello Web Security Java Configuration The first step is to create our Spring Security Java Configuration. -The configuration creates a Servlet Filter known as the `springSecurityFilterChain` which is responsible for all the security (protecting the application URLs, validating submitted username and passwords, redirecting to the log in form, etc) within your application. -You can find the most basic example of a Spring Security Java Configuration below: +The configuration creates a Servlet Filter known as the `springSecurityFilterChain`, which is responsible for all the security (protecting the application URLs, validating submitted username and passwords, redirecting to the log in form, and so on) within your application. +The following example shows the most basic example of a Spring Security Java Configuration: [[jc-hello-wsca]] +==== [source,java] ---- import org.springframework.beans.factory.annotation.Autowired; @@ -35,44 +35,44 @@ public class WebSecurityConfig { } } ---- +==== -There really isn't much to this configuration, but it does a lot. -You can find a summary of the features below: +This configuration is not complex or extensive, but it does a lot: * Require authentication to every URL in your application * Generate a login form for you -* Allow the user with the *Username* _user_ and the *Password* _password_ to authenticate with form based authentication -* Allow the user to logout +* Let the user with a *Username* of `user` and a *Password* of `password` authenticate with form based authentication +* Let the user logout * https://en.wikipedia.org/wiki/Cross-site_request_forgery[CSRF attack] prevention * https://en.wikipedia.org/wiki/Session_fixation[Session Fixation] protection -* Security Header integration +* Security Header integration: ** https://en.wikipedia.org/wiki/HTTP_Strict_Transport_Security[HTTP Strict Transport Security] for secure requests ** https://msdn.microsoft.com/en-us/library/ie/gg622941(v=vs.85).aspx[X-Content-Type-Options] integration -** Cache Control (can be overridden later by your application to allow caching of your static resources) +** Cache Control (which you can override later in your application to allow caching of your static resources) ** https://msdn.microsoft.com/en-us/library/dd565647(v=vs.85).aspx[X-XSS-Protection] integration ** X-Frame-Options integration to help prevent https://en.wikipedia.org/wiki/Clickjacking[Clickjacking] -* Integrate with the following Servlet API methods -** https://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletRequest.html#getRemoteUser()[HttpServletRequest#getRemoteUser()] -** https://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletRequest.html#getUserPrincipal()[HttpServletRequest#getUserPrincipal()] -** https://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletRequest.html#isUserInRole(java.lang.String)[HttpServletRequest#isUserInRole(java.lang.String)] -** https://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletRequest.html#login(java.lang.String,%20java.lang.String)[HttpServletRequest#login(java.lang.String, java.lang.String)] -** https://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletRequest.html#logout()[HttpServletRequest#logout()] +* Integration with the following Servlet API methods: +** https://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletRequest.html#getRemoteUser()[`HttpServletRequest#getRemoteUser()`] +** https://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletRequest.html#getUserPrincipal()[`HttpServletRequest#getUserPrincipal()`] +** https://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletRequest.html#isUserInRole(java.lang.String)[`HttpServletRequest#isUserInRole(java.lang.String)`] +** https://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletRequest.html#login(java.lang.String,%20java.lang.String)[`HttpServletRequest#login(java.lang.String, java.lang.String)`] +** https://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletRequest.html#logout()[`HttpServletRequest#logout()`] === AbstractSecurityWebApplicationInitializer -The next step is to register the `springSecurityFilterChain` with the war. -This can be done in Java Configuration with https://docs.spring.io/spring/docs/3.2.x/spring-framework-reference/html/mvc.html#mvc-container-config[Spring's WebApplicationInitializer support] in a Servlet 3.0+ environment. -Not suprisingly, Spring Security provides a base class `AbstractSecurityWebApplicationInitializer` that will ensure the `springSecurityFilterChain` gets registered for you. +The next step is to register the `springSecurityFilterChain` with the WAR file. +You can do so in Java configuration with https://docs.spring.io/spring/docs/3.2.x/spring-framework-reference/html/mvc.html#mvc-container-config[Spring's `WebApplicationInitializer` support] in a Servlet 3.0+ environment. +Not surprisingly, Spring Security provides a base class (`AbstractSecurityWebApplicationInitializer`) to ensure that the `springSecurityFilterChain` gets registered for you. The way in which we use `AbstractSecurityWebApplicationInitializer` differs depending on if we are already using Spring or if Spring Security is the only Spring component in our application. -* <> - Use these instructions if you are not using Spring already +* <> - Use these instructions if you are not already using Spring * <> - Use these instructions if you are already using Spring === AbstractSecurityWebApplicationInitializer without Existing Spring -If you are not using Spring or Spring MVC, you will need to pass in the `WebSecurityConfig` into the superclass to ensure the configuration is picked up. -You can find an example below: +If you are not using Spring or Spring MVC, you need to pass the `WebSecurityConfig` to the superclass to ensure the configuration is picked up: +==== [source,java] ---- import org.springframework.security.web.context.*; @@ -85,19 +85,21 @@ public class SecurityWebApplicationInitializer } } ---- +==== -The `SecurityWebApplicationInitializer` will do the following things: +The `SecurityWebApplicationInitializer`: -* Automatically register the springSecurityFilterChain Filter for every URL in your application -* Add a ContextLoaderListener that loads the <>. +* Automatically registers the `springSecurityFilterChain` Filter for every URL in your application. +* Add a `ContextLoaderListener` that loads the <>. === AbstractSecurityWebApplicationInitializer with Spring MVC -If we were using Spring elsewhere in our application we probably already had a `WebApplicationInitializer` that is loading our Spring Configuration. -If we use the previous configuration we would get an error. +If we use Spring elsewhere in our application, we probably already have a `WebApplicationInitializer` that is loading our Spring Configuration. +If we use the previous configuration, we would get an error. Instead, we should register Spring Security with the existing `ApplicationContext`. -For example, if we were using Spring MVC our `SecurityWebApplicationInitializer` would look something like the following: +For example, if we use Spring MVC, our `SecurityWebApplicationInitializer` could look something like the following: +==== [source,java] ---- import org.springframework.security.web.context.*; @@ -107,12 +109,14 @@ public class SecurityWebApplicationInitializer } ---- +==== -This would simply only register the springSecurityFilterChain Filter for every URL in your application. -After that we would ensure that `WebSecurityConfig` was loaded in our existing ApplicationInitializer. -For example, if we were using Spring MVC it would be added in the `getRootConfigClasses()` +This onlys register the `springSecurityFilterChain` for every URL in your application. +After that, we need to ensure that `WebSecurityConfig` was loaded in our existing `ApplicationInitializer`. +For example, if we use Spring MVC it is added in the `getRootConfigClasses()`: [[message-web-application-inititializer-java]] +==== [source,java] ---- public class MvcWebApplicationInitializer extends @@ -126,16 +130,18 @@ public class MvcWebApplicationInitializer extends // ... other overrides ... } ---- +==== [[jc-httpsecurity]] == HttpSecurity -Thus far our <> only contains information about how to authenticate our users. +Thus far, our <> contains only information about how to authenticate our users. How does Spring Security know that we want to require all users to be authenticated? -How does Spring Security know we want to support form based authentication? -Actually, there is a configuration class that is being invoked behind the scenes called `WebSecurityConfigurerAdapter`. +How does Spring Security know we want to support form-based authentication? +Actually, there is a configuration class (called `WebSecurityConfigurerAdapter`) that is being invoked behind the scenes. It has a method called `configure` with the following default implementation: +==== [source,java] ---- protected void configure(HttpSecurity http) throws Exception { @@ -147,15 +153,17 @@ protected void configure(HttpSecurity http) throws Exception { .httpBasic(withDefaults()); } ---- +==== -The default configuration above: +The default configuration (shown in the preceding example): * Ensures that any request to our application requires the user to be authenticated -* Allows users to authenticate with form based login -* Allows users to authenticate with HTTP Basic authentication +* Lets users authenticate with form based login +* Lets users authenticate with HTTP Basic authentication -You will notice that this configuration is quite similar the XML Namespace configuration: +Note that this configuration is parallels the XML Namespace configuration: +==== [source,xml] ---- @@ -164,13 +172,15 @@ You will notice that this configuration is quite similar the XML Namespace confi ---- +==== -== Multiple HttpSecurity +== Multiple HttpSecurity Instances -We can configure multiple HttpSecurity instances just as we can have multiple `` blocks. +We can configure multiple `HttpSecurity` instances just as we can have multiple `` blocks in XML. The key is to extend the `WebSecurityConfigurerAdapter` multiple times. -For example, the following is an example of having a different configuration for URL's that start with `/api/`. +The following example has a different configuration for URL's that start with `/api/`. +==== [source,java] ---- @EnableWebSecurity @@ -213,19 +223,20 @@ public class MultiHttpSecurityConfig { } ---- -<1> Configure Authentication as normal +<1> Configure Authentication as usual. <2> Create an instance of `WebSecurityConfigurerAdapter` that contains `@Order` to specify which `WebSecurityConfigurerAdapter` should be considered first. -<3> The `http.antMatcher` states that this `HttpSecurity` will only be applicable to URLs that start with `/api/` +<3> The `http.antMatcher` states that this `HttpSecurity` is applicable only to URLs that start with `/api/`. <4> Create another instance of `WebSecurityConfigurerAdapter`. -If the URL does not start with `/api/` this configuration will be used. -This configuration is considered after `ApiWebSecurityConfigurationAdapter` since it has an `@Order` value after `1` (no `@Order` defaults to last). +If the URL does not start with `/api/`, this configuration is used. +This configuration is considered after `ApiWebSecurityConfigurationAdapter`, since it has an `@Order` value after `1` (no `@Order` defaults to last). +==== [[jc-custom-dsls]] == Custom DSLs -You can provide your own custom DSLs in Spring Security. -For example, you might have something that looks like this: +You can provide your own custom DSLs in Spring Security: +==== [source,java] ---- public class MyCustomDsl extends AbstractHttpConfigurer { @@ -258,11 +269,13 @@ public class MyCustomDsl extends AbstractHttpConfigurer @@ -43,14 +46,17 @@ You will notice that this configuration is quite similar the XML Namespace confi ---- +==== -== Multiple HttpSecurity +== Multiple HttpSecurity Instances -We can configure multiple HttpSecurity instances just as we can have multiple `` blocks. +We can configure multiple HttpSecurity instances, just as we can have multiple `` blocks. The key is to extend the `WebSecurityConfigurerAdapter` multiple times. -For example, the following is an example of having a different configuration for URL's that start with `/api/`. +The following example has a different configuration for URL's that start with `/api/`: -[source,kotlin] +// The source is Kotlin, but we specify Java to get code formatting. At present, Asciidoctor doesnt' have a Kotlin formatter. +==== +[source,java] ---- @EnableWebSecurity class MultiHttpSecurityConfig { @@ -91,9 +97,10 @@ class MultiHttpSecurityConfig { } ---- -<1> Configure Authentication as normal +<1> Configure Authentication as usual. <2> Create an instance of `WebSecurityConfigurerAdapter` that contains `@Order` to specify which `WebSecurityConfigurerAdapter` should be considered first. -<3> The `http.antMatcher` states that this `HttpSecurity` will only be applicable to URLs that start with `/api/` +<3> The `http.antMatcher` states that this `HttpSecurity` is applicable only to URLs that start with `/api/` <4> Create another instance of `WebSecurityConfigurerAdapter`. -If the URL does not start with `/api/` this configuration will be used. -This configuration is considered after `ApiWebSecurityConfigurationAdapter` since it has an `@Order` value after `1` (no `@Order` defaults to last). +If the URL does not start with `/api/`, this configuration is used. +This configuration is considered after `ApiWebSecurityConfigurationAdapter`, since it has an `@Order` value after `1` (no `@Order` defaults to last). +==== diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/namespace/index.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/namespace/index.adoc index 58c7687cc91..fc427d14ccf 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/namespace/index.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/namespace/index.adoc @@ -2,30 +2,30 @@ [[ns-config]] = Security Namespace Configuration - -== Introduction Namespace configuration has been available since version 2.0 of the Spring Framework. -It allows you to supplement the traditional Spring beans application context syntax with elements from additional XML schema. +It lets you supplement the traditional Spring beans application context syntax with elements from additional XML schema. You can find more information in the Spring https://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/[Reference Documentation]. -A namespace element can be used simply to allow a more concise way of configuring an individual bean or, more powerfully, to define an alternative configuration syntax which more closely matches the problem domain and hides the underlying complexity from the user. -A simple element may conceal the fact that multiple beans and processing steps are being added to the application context. -For example, adding the following element from the security namespace to an application context will start up an embedded LDAP server for testing use within the application: +You can use a namespace element to more concisely configure an individual bean or, more powerfully, to define an alternative configuration syntax that more closely matches the problem domain and hides the underlying complexity from the user. +A simple element can conceal the fact that multiple beans and processing steps are being added to the application context. +For example, adding the following element from the `security` namespace to an application context starts up an embedded LDAP server for testing use within the application: +==== [source,xml] ---- ---- +==== This is much simpler than wiring up the equivalent Apache Directory Server beans. -The most common alternative configuration requirements are supported by attributes on the `ldap-server` element and the user is isolated from worrying about which beans they need to create and what the bean property names are. -footnote:[You can find out more about the use of the `ldap-server` element in the chapter on pass:specialcharacters,macros[<>].]. -Use of a good XML editor while editing the application context file should provide information on the attributes and elements that are available. -We would recommend that you try out the https://spring.io/tools/sts[Spring Tool Suite] as it has special features for working with standard Spring namespaces. +The most common alternative configuration requirements are supported by attributes on the `ldap-server` element, and the user is isolated from worrying about which beans they need to create and what the bean property names are. +You can find out more about the use of the `ldap-server` element in the chapter on <>. +A good XML editor while editing the application context file should provide information on the attributes and elements that are available. +We recommend that you try the https://spring.io/tools/sts[Spring Tool Suite], as it has special features for working with standard Spring namespaces. +To start using the `security` namespace in your application context, add the `spring-security-config` jar to your classpath. +Then, all you need to do is add the schema declaration to your application context file: -To start using the security namespace in your application context, you need to have the `spring-security-config` jar on your classpath. -Then all you need to do is add the schema declaration to your application context file: - +==== [source,xml] ---- ` element. +Once you have added this bean to your `web.xml`, you are ready to start editing your application context file. +Web security services are configured by the `` element. [[ns-minimal]] === A Minimal Configuration -All you need to enable web security to begin with is +To enable web security, you need the following configuration: + +==== [source,xml] ---- @@ -123,31 +130,33 @@ All you need to enable web security to begin with is ---- +==== + +That listing says that we want: + +* All URLs within our application to be secured, requiring the role `ROLE_USER` to access them +* To log in to the application using a form with username and password +* A logout URL registered which will allow us to log out of the application -Which says that we want all URLs within our application to be secured, requiring the role `ROLE_USER` to access them, we want to log in to the application using a form with username and password, and that we want a logout URL registered which will allow us to log out of the application. -`` element is the parent for all web-related namespace functionality. -The `` element defines a `pattern` which is matched against the URLs of incoming requests using an ant path style syntax footnote:[See the section on pass:specialcharacters,macros[<>] for more details on how matches are actually performed.]. +The `` element is the parent for all web-related namespace functionality. +The `` element defines a `pattern`, which is matched against the URLs of incoming requests using Ant path syntax. See the section on <> for more details on how matches are actually performed. You can also use regular-expression matching as an alternative (see the namespace appendix for more details). -The `access` attribute defines the access requirements for requests matching the given pattern. +The `access` attribute defines the access requirements for requests that match the given pattern. With the default configuration, this is typically a comma-separated list of roles, one of which a user must have to be allowed to make the request. -The prefix "ROLE_" is a marker which indicates that a simple comparison with the user's authorities should be made. +The `ROLE_` prefix is a marker that indicates that a simple comparison with the user's authorities should be made. In other words, a normal role-based check should be used. Access-control in Spring Security is not limited to the use of simple roles (hence the use of the prefix to differentiate between different types of security attributes). -We'll see later how the interpretation can vary footnote:[The interpretation of the comma-separated values in the `access` attribute depends on the implementation of the <> which is used.]. -In Spring Security 3.0, the attribute can also be populated with an <>. +We see later how the interpretation can vary. The interpretation of the comma-separated values in the `access` attribute depends on the which implementation of the <> is used. +Since Spring Security 3.0, you can also populate the attribute with an <>. -[NOTE] -==== - -You can use multiple `` elements to define different access requirements for different sets of URLs, but they will be evaluated in the order listed and the first match will be used. +NOTE: You can use multiple `` elements to define different access requirements for different sets of URLs, but they are evaluated in the order listed and the first match is used. So you must put the most specific matches at the top. -You can also add a `method` attribute to limit the match to a particular HTTP method (`GET`, `POST`, `PUT` etc.). - -==== +You can also add a `method` attribute to limit the match to a particular HTTP method (`GET`, `POST`, `PUT`, and so on). -To add some users, you can define a set of test data directly in the namespace: +To add users, you can define a set of test data directly in the namespace: +==== [source,xml,attrs="-attributes"] ---- @@ -162,10 +171,12 @@ To add some users, you can define a set of test data directly in the namespace: ---- +==== -This is an example of a secure way of storing the same passwords. +The preceding listing shows an example of a secure way to store the same passwords. The password is prefixed with `+{bcrypt}+` to instruct `DelegatingPasswordEncoder`, which supports any configured `PasswordEncoder` for matching, that the passwords are hashed using BCrypt: +==== [source,xml,attrs="-attributes"] ---- @@ -181,37 +192,36 @@ The password is prefixed with `+{bcrypt}+` to instruct `DelegatingPasswordEncode ---- - - +==== [subs="quotes"] **** -If you are familiar with pre-namespace versions of the framework, you can probably already guess roughly what's going on here. -The `` element is responsible for creating a `FilterChainProxy` and the filter beans which it uses. -Common problems like incorrect filter ordering are no longer an issue as the filter positions are predefined. +The `` element is responsible for creating a `FilterChainProxy` and the filter beans that it uses. +Previously common problems, such as incorrect filter ordering, are no longer an issue, as the filter positions are predefined. -The `` element creates a `DaoAuthenticationProvider` bean and the `` element creates an `InMemoryDaoImpl`. +The `` element creates a `DaoAuthenticationProvider` bean, and the `` element creates an `InMemoryDaoImpl`. All `authentication-provider` elements must be children of the `` element, which creates a `ProviderManager` and registers the authentication providers with it. You can find more detailed information on the beans that are created in the <>. -It's worth cross-checking this if you want to start understanding what the important classes in the framework are and how they are used, particularly if you want to customise things later. +You should cross-check this appendix if you want to start understanding what the important classes in the framework are and how they are used, particularly if you want to customize things later. **** -The configuration above defines two users, their passwords and their roles within the application (which will be used for access control). -It is also possible to load user information from a standard properties file using the `properties` attribute on `user-service`. +The preceding configuration defines two users, their passwords, and their roles within the application (which are used for access control). +You can also possible load user information from a standard properties file by setting the `properties` attribute on the `user-service` element. See the section on <> for more details on the file format. -Using the `` element means that the user information will be used by the authentication manager to process authentication requests. -You can have multiple `` elements to define different authentication sources and each will be consulted in turn. +Using the `` element means that the user information is used by the authentication manager to process authentication requests. +You can have multiple `` elements to define different authentication sources. Each is consulted in turn. -At this point you should be able to start up your application and you will be required to log in to proceed. -Try it out, or try experimenting with the "tutorial" sample application that comes with the project. +At this point, you should be able to start up your application, and you should be required to log in to proceed. +Try it out, or try experimenting with the "`tutorial`" sample application that comes with the project. [[ns-form-target]] ==== Setting a Default Post-Login Destination -If a form login isn't prompted by an attempt to access a protected resource, the `default-target-url` option comes into play. -This is the URL the user will be taken to after successfully logging in, and defaults to "/". -You can also configure things so that the user __always__ ends up at this page (regardless of whether the login was "on-demand" or they explicitly chose to log in) by setting the `always-use-default-target` attribute to "true". -This is useful if your application always requires that the user starts at a "home" page, for example: +If a form login is not prompted by an attempt to access a protected resource, the `default-target-url` option comes into play. +This is the URL to which the user is taken after successfully logging in. it defaults to `/`. +You can also configure things so that the user _always_ ends up at this page (regardless of whether the login was "`on-demand`" or they explicitly chose to log in) by setting the `always-use-default-target` attribute to `true`. +This is useful if your application always requires that the user starts at a "`home`" page, for example: +==== [source,xml] ---- @@ -221,6 +231,7 @@ This is useful if your application always requires that the user starts at a "ho always-use-default-target='true' /> ---- +==== For even more control over the destination, you can use the `authentication-success-handler-ref` attribute as an alternative to `default-target-url`. The referenced bean should be an instance of `AuthenticationSuccessHandler`. @@ -228,25 +239,24 @@ The referenced bean should be an instance of `AuthenticationSuccessHandler`. [[ns-web-advanced]] == Advanced Web Features +This section covers various features that go beyond the basics. + [[ns-custom-filters]] -=== Adding in Your Own Filters -If you've used Spring Security before, you'll know that the framework maintains a chain of filters in order to apply its services. -You may want to add your own filters to the stack at particular locations or use a Spring Security filter for which there isn't currently a namespace configuration option (CAS, for example). -Or you might want to use a customized version of a standard namespace filter, such as the `UsernamePasswordAuthenticationFilter` which is created by the `` element, taking advantage of some of the extra configuration options which are available by using the bean explicitly. +=== Adding Your Own Filters +If you have used Spring Security before, you know that the framework maintains a chain of filters that it uses to apply its services. +You may want to add your own filters to the stack at particular locations or use a Spring Security filter for which there is not currently a namespace configuration option (CAS, for example). +// FIXME: Is it still true that there is no CAS filter? +Alternatively, you might want to use a customized version of a standard namespace filter, such as the `UsernamePasswordAuthenticationFilter` (which is created by the `` element) to take advantage of some of the extra configuration options that are available when you use the bean explicitly. How can you do this with namespace configuration, since the filter chain is not directly exposed? -The order of the filters is always strictly enforced when using the namespace. -When the application context is being created, the filter beans are sorted by the namespace handling code and the standard Spring Security filters each have an alias in the namespace and a well-known position. +The order of the filters is always strictly enforced when you use the namespace. +When the application context is being created, the filter beans are sorted by the namespace handling code, and the standard Spring Security filters each have an alias in the namespace and a well-known position. -[NOTE] -==== -In previous versions, the sorting took place after the filter instances had been created, during post-processing of the application context. -In version 3.0+ the sorting is now done at the bean metadata level, before the classes have been instantiated. -This has implications for how you add your own filters to the stack as the entire filter list must be known during the parsing of the `` element, so the syntax has changed slightly in 3.0. -==== +NOTE: In previous versions, the sorting took place after the filter instances had been created, during post-processing of the application context. +In version 3.0+, the sorting is now done at the bean metadata level, before the classes have been instantiated. +This has implications for how you add your own filters to the stack, as the entire filter list must be known during the parsing of the `` element. As a result, the syntax changed slightly in version 3.0. -The filters, aliases and namespace elements/attributes which create the filters are shown in <>. -The filters are listed in the order in which they occur in the filter chain. +The filters, aliases, and namespace elements and attributes that create the filters are shown in the following table, in the order in which they occur in the filter chain: [[filter-stack]] .Standard Filter Aliases and Ordering @@ -330,8 +340,9 @@ The filters are listed in the order in which they occur in the filter chain. | N/A |=== -You can add your own filter to the stack, using the `custom-filter` element and one of these names to specify the position your filter should appear at: +You can add your own filter to the stack by using the `custom-filter` element and one of these names to specify the position at which your filter should appear: +==== [source,xml] ---- @@ -340,40 +351,39 @@ You can add your own filter to the stack, using the `custom-filter` element and ---- +==== You can also use the `after` or `before` attributes if you want your filter to be inserted before or after another filter in the stack. -The names "FIRST" and "LAST" can be used with the `position` attribute to indicate that you want your filter to appear before or after the entire stack, respectively. +You can use `FIRST` and `LAST` with the `position` attribute to indicate that you want your filter to appear before or after the entire stack, respectively. .Avoiding filter position conflicts [TIP] ==== +If you insert a custom filter that may occupy the same position as one of the standard filters created by the namespace, you should not include the namespace versions by mistake. +Remove any elements that create filters whose functionality you want to replace. -If you are inserting a custom filter which may occupy the same position as one of the standard filters created by the namespace then it's important that you don't include the namespace versions by mistake. -Remove any elements which create filters whose functionality you want to replace. - -Note that you can't replace filters which are created by the use of the `` element itself - `SecurityContextPersistenceFilter`, `ExceptionTranslationFilter` or `FilterSecurityInterceptor`. +Note that you cannot replace filters that are created by the use of the `` element itself: `SecurityContextPersistenceFilter`, `ExceptionTranslationFilter`, or `FilterSecurityInterceptor`. Some other filters are added by default, but you can disable them. -An `AnonymousAuthenticationFilter` is added by default and unless you have <> disabled, a `SessionManagementFilter` will also be added to the filter chain. +By default, an `AnonymousAuthenticationFilter` is added and unless you have <> disabled, a `SessionManagementFilter` is also added to the filter chain. ==== -If you're replacing a namespace filter which requires an authentication entry point (i.e. where the authentication process is triggered by an attempt by an unauthenticated user to access to a secured resource), you will need to add a custom entry point bean too. - +If you replace a namespace filter that requires an authentication entry point (that is, where the authentication process is triggered by an unauthenticated user's attempt to access to a secured resource), you need to add a custom entry-point bean too. [[ns-method-security]] == Method Security -From version 2.0 onwards Spring Security has improved support substantially for adding security to your service layer methods. +Since version 2.0, Spring Security has substantial support 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 <>. -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. +Since version 3.0, you can also make use of <>. +You can apply security to a single bean (by 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. [[ns-access-manager]] == The Default AccessDecisionManager -This section assumes you have some knowledge of the underlying architecture for access-control within Spring Security. -If you don't you can skip it and come back to it later, as this section is only really relevant for people who need to do some customization in order to use more than simple role-based security. +This section assumes that you have some knowledge of the underlying architecture for access-control within Spring Security. +If you do not, you can skip it and come back to it later, as this section is relevant only for people who need to do some customization to use more than simple role-based security. -When you use a namespace configuration, a default instance of `AccessDecisionManager` is automatically registered for you and will be used for making access decisions for method invocations and web URL access, based on the access attributes you specify in your `intercept-url` and `protect-pointcut` declarations (and in annotations if you are using annotation secured methods). +When you use a namespace configuration, a default instance of `AccessDecisionManager` is automatically registered for you and is used to make access decisions for method invocations and web URL access, based on the access attributes you specify in your `intercept-url` and `protect-pointcut` declarations (and in annotations, if you use annotations to secure methods). The default strategy is to use an `AffirmativeBased` `AccessDecisionManager` with a `RoleVoter` and an `AuthenticatedVoter`. You can find out more about these in the chapter on <>. @@ -381,22 +391,26 @@ You can find out more about these in the chapter on <> [[ns-custom-access-mgr]] === Customizing the AccessDecisionManager -If you need to use a more complicated access control strategy then it is easy to set an alternative for both method and web security. +If you need to use a more complicated access control strategy, you can set an alternative for both method and web security. -For method security, you do this by setting the `access-decision-manager-ref` attribute on `global-method-security` to the `id` of the appropriate `AccessDecisionManager` bean in the application context: +For method security, you do so by setting the `access-decision-manager-ref` attribute on `global-method-security` to the `id` of the appropriate `AccessDecisionManager` bean in the application context: +==== [source,xml] ---- ... ---- +==== -The syntax for web security is the same, but on the `http` element: +The syntax for web security is the same, but the attribute is on the `http` element: +==== [source,xml] ---- ... ---- +==== diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/oauth2/index.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/oauth2/index.adoc index 99ed0947d99..a26601205d5 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/oauth2/index.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/oauth2/index.adoc @@ -1,5 +1,7 @@ = OAuth2 +This section describes how Spring Security enables OAuth2. + include::oauth2-login.adoc[] include::oauth2-client.adoc[] diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/oauth2/oauth2-client.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/oauth2/oauth2-client.adoc index 12ba7f397d0..c126a830203 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/oauth2/oauth2-client.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/oauth2/oauth2-client.adoc @@ -95,7 +95,7 @@ The following code shows the complete configuration options available in the <> -** <> -** <> -** <> -** <> -** <> +** <> +** <> +** <> +** <> +** <> * <> ** <> ** <> @@ -161,12 +161,14 @@ The following sections will go into more detail on the core components used by O * <> ** <> * <> -** <> +** <> * <> [[oauth2Client-core-interface-class]] -=== Core Interfaces / Classes +=== Core Interfaces and Classes + +This section describes the OAuth2 core interfaces and classes that Spring Security offers. [[oauth2Client-client-registration]] @@ -174,10 +176,11 @@ The following sections will go into more detail on the core components used by O `ClientRegistration` is a representation of a client registered with an OAuth 2.0 or OpenID Connect 1.0 Provider. -A client registration holds information, such as client id, client secret, authorization grant type, redirect URI, scope(s), authorization URI, token URI, and other details. +A `ClientRegistration` object holds information, such as client id, client secret, authorization grant type, redirect URI, scope(s), authorization URI, token URI, and other details. `ClientRegistration` and its properties are defined as follows: +==== [source,java] ---- public final class ClientRegistration { @@ -223,18 +226,19 @@ The name may be used in certain scenarios, such as when displaying the name of t <9> `authorizationUri`: The Authorization Endpoint URI for the Authorization Server. <10> `tokenUri`: The Token Endpoint URI for the Authorization Server. <11> `jwkSetUri`: The URI used to retrieve the https://tools.ietf.org/html/rfc7517[JSON Web Key (JWK)] Set from the Authorization Server, - which contains the cryptographic key(s) used to verify the https://tools.ietf.org/html/rfc7515[JSON Web Signature (JWS)] of the ID Token and optionally the UserInfo Response. -<12> `issuerUri`: Returns the issuer identifier uri for the OpenID Connect 1.0 provider or the OAuth 2.0 Authorization Server. +which contains the cryptographic key(s) used to verify the https://tools.ietf.org/html/rfc7515[JSON Web Signature (JWS)] of the ID Token and (optionally) the UserInfo Response. +<12> `issuerUri`: Returns the issuer identifier URI for the OpenID Connect 1.0 provider or the OAuth 2.0 Authorization Server. <13> `configurationMetadata`: The https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfig[OpenID Provider Configuration Information]. - This information will only be available if the Spring Boot 2.x property `spring.security.oauth2.client.provider.[providerId].issuerUri` is configured. -<14> `(userInfoEndpoint)uri`: The UserInfo Endpoint URI used to access the claims/attributes of the authenticated end-user. + This information is available only if the Spring Boot 2.x property `spring.security.oauth2.client.provider.[providerId].issuerUri` is configured. +<14> `(userInfoEndpoint)uri`: The UserInfo Endpoint URI used to access the claims and attributes of the authenticated end-user. <15> `(userInfoEndpoint)authenticationMethod`: The authentication method used when sending the access token to the UserInfo Endpoint. -The supported values are *header*, *form* and *query*. +The supported values are *header*, *form*, and *query*. <16> `userNameAttributeName`: The name of the attribute returned in the UserInfo Response that references the Name or Identifier of the end-user. +==== -A `ClientRegistration` can be initially configured using discovery of an OpenID Connect Provider's https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfig[Configuration endpoint] or an Authorization Server's https://tools.ietf.org/html/rfc8414#section-3[Metadata endpoint]. +You can initially configure a `ClientRegistration` by using discovery of an OpenID Connect Provider's https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfig[Configuration endpoint] or an Authorization Server's https://tools.ietf.org/html/rfc8414#section-3[Metadata endpoint]. -`ClientRegistrations` provides convenience methods for configuring a `ClientRegistration` in this way, as can be seen in the following example: +`ClientRegistrations` provides convenience methods for configuring a `ClientRegistration` in this way, as follows: ==== .Java @@ -251,25 +255,23 @@ val clientRegistration = ClientRegistrations.fromIssuerLocation("https://idp.exa ---- ==== -The above code will query in series `https://idp.example.com/issuer/.well-known/openid-configuration`, and then `https://idp.example.com/.well-known/openid-configuration/issuer`, and finally `https://idp.example.com/.well-known/oauth-authorization-server/issuer`, stopping at the first to return a 200 response. +The preceding code queries, in series, `https://idp.example.com/issuer/.well-known/openid-configuration`, `https://idp.example.com/.well-known/openid-configuration/issuer`, and `https://idp.example.com/.well-known/oauth-authorization-server/issuer`, stopping at the first to return a 200 response. -As an alternative, you can use `ClientRegistrations.fromOidcIssuerLocation()` to only query the OpenID Connect Provider's Configuration endpoint. +As an alternative, you can use `ClientRegistrations.fromOidcIssuerLocation()` to query only the OpenID Connect Provider's Configuration endpoint. [[oauth2Client-client-registration-repo]] ==== ClientRegistrationRepository The `ClientRegistrationRepository` serves as a repository for OAuth 2.0 / OpenID Connect 1.0 `ClientRegistration`(s). -[NOTE] -Client registration information is ultimately stored and owned by the associated Authorization Server. -This repository provides the ability to retrieve a sub-set of the primary client registration information, which is stored with the Authorization Server. +NOTE: Client registration information is ultimately stored and owned by the associated Authorization Server. +This repository provides the ability to retrieve a subset of the primary client registration information, which is stored with the Authorization Server. Spring Boot 2.x auto-configuration binds each of the properties under `spring.security.oauth2.client.registration._[registrationId]_` to an instance of `ClientRegistration` and then composes each of the `ClientRegistration` instance(s) within a `ClientRegistrationRepository`. -[NOTE] -The default implementation of `ClientRegistrationRepository` is `InMemoryClientRegistrationRepository`. +NOTE: The default implementation of `ClientRegistrationRepository` is `InMemoryClientRegistrationRepository`. -The auto-configuration also registers the `ClientRegistrationRepository` as a `@Bean` in the `ApplicationContext` so that it is available for dependency-injection, if needed by the application. +The auto-configuration also registers the `ClientRegistrationRepository` as a `@Bean` in the `ApplicationContext` so that it is available for dependency injection, if needed by the application. The following listing shows an example: @@ -321,18 +323,18 @@ class OAuth2ClientController { ==== OAuth2AuthorizedClient `OAuth2AuthorizedClient` is a representation of an Authorized Client. -A client is considered to be authorized when the end-user (Resource Owner) has granted authorization to the client to access its protected resources. +A client is considered to be authorized when the end-user (the Resource Owner) has granted authorization to the client to access its protected resources. `OAuth2AuthorizedClient` serves the purpose of associating an `OAuth2AccessToken` (and optional `OAuth2RefreshToken`) to a `ClientRegistration` (client) and resource owner, who is the `Principal` end-user that granted the authorization. [[oauth2Client-authorized-repo-service]] -==== OAuth2AuthorizedClientRepository / OAuth2AuthorizedClientService +==== OAuth2AuthorizedClientRepository and OAuth2AuthorizedClientService -`OAuth2AuthorizedClientRepository` is responsible for persisting `OAuth2AuthorizedClient`(s) between web requests. -Whereas, the primary role of `OAuth2AuthorizedClientService` is to manage `OAuth2AuthorizedClient`(s) at the application-level. +`OAuth2AuthorizedClientRepository` is responsible for persisting `OAuth2AuthorizedClient`(s) between web requests, +whereas the primary role of `OAuth2AuthorizedClientService` is to manage `OAuth2AuthorizedClient`(s) at the application-level. -From a developer perspective, the `OAuth2AuthorizedClientRepository` or `OAuth2AuthorizedClientService` provides the capability to lookup an `OAuth2AccessToken` associated with a client so that it may be used to initiate a protected resource request. +From a developer perspective, the `OAuth2AuthorizedClientRepository` or `OAuth2AuthorizedClientService` provides the ability to look up an `OAuth2AccessToken` associated with a client so that it can be used to initiate a protected resource request. The following listing shows an example: @@ -383,37 +385,35 @@ class OAuth2ClientController { ---- ==== -[NOTE] -Spring Boot 2.x auto-configuration registers an `OAuth2AuthorizedClientRepository` and/or `OAuth2AuthorizedClientService` `@Bean` in the `ApplicationContext`. -However, the application may choose to override and register a custom `OAuth2AuthorizedClientRepository` or `OAuth2AuthorizedClientService` `@Bean`. +NOTE: Spring Boot 2.x auto-configuration registers an `OAuth2AuthorizedClientRepository` or an `OAuth2AuthorizedClientService` `@Bean` in the `ApplicationContext`. +However, the application can override and register a custom `OAuth2AuthorizedClientRepository` or `OAuth2AuthorizedClientService` `@Bean`. -The default implementation of `OAuth2AuthorizedClientService` is `InMemoryOAuth2AuthorizedClientService`, which stores `OAuth2AuthorizedClient`(s) in-memory. +The default implementation of `OAuth2AuthorizedClientService` is `InMemoryOAuth2AuthorizedClientService`, which stores `OAuth2AuthorizedClient` objects in-memory. -Alternatively, the JDBC implementation `JdbcOAuth2AuthorizedClientService` may be configured for persisting `OAuth2AuthorizedClient`(s) in a database. +Alternatively, you can configure the JDBC implementation `JdbcOAuth2AuthorizedClientService` to persist `OAuth2AuthorizedClient` instances in a database. -[NOTE] -`JdbcOAuth2AuthorizedClientService` depends on the table definition described in <>. +NOTE: `JdbcOAuth2AuthorizedClientService` depends on the table definition described in <>. [[oauth2Client-authorized-manager-provider]] -==== OAuth2AuthorizedClientManager / OAuth2AuthorizedClientProvider +==== OAuth2AuthorizedClientManager and OAuth2AuthorizedClientProvider The `OAuth2AuthorizedClientManager` is responsible for the overall management of `OAuth2AuthorizedClient`(s). The primary responsibilities include: -* Authorizing (or re-authorizing) an OAuth 2.0 Client, using an `OAuth2AuthorizedClientProvider`. -* Delegating the persistence of an `OAuth2AuthorizedClient`, typically using an `OAuth2AuthorizedClientService` or `OAuth2AuthorizedClientRepository`. +* Authorizing (or re-authorizing) an OAuth 2.0 Client, by using an `OAuth2AuthorizedClientProvider`. +* Delegating the persistence of an `OAuth2AuthorizedClient`, typically by using an `OAuth2AuthorizedClientService` or `OAuth2AuthorizedClientRepository`. * Delegating to an `OAuth2AuthorizationSuccessHandler` when an OAuth 2.0 Client has been successfully authorized (or re-authorized). * Delegating to an `OAuth2AuthorizationFailureHandler` when an OAuth 2.0 Client fails to authorize (or re-authorize). An `OAuth2AuthorizedClientProvider` implements a strategy for authorizing (or re-authorizing) an OAuth 2.0 Client. -Implementations will typically implement an authorization grant type, eg. `authorization_code`, `client_credentials`, etc. +Implementations typically implement an authorization grant type, such as `authorization_code`, `client_credentials`, and others. The default implementation of `OAuth2AuthorizedClientManager` is `DefaultOAuth2AuthorizedClientManager`, which is associated with an `OAuth2AuthorizedClientProvider` that may support multiple authorization grant types using a delegation-based composite. -The `OAuth2AuthorizedClientProviderBuilder` may be used to configure and build the delegation-based composite. +You can use `OAuth2AuthorizedClientProviderBuilder` to configure and build the delegation-based composite. -The following code shows an example of how to configure and build an `OAuth2AuthorizedClientProvider` composite that provides support for the `authorization_code`, `refresh_token`, `client_credentials` and `password` authorization grant types: +The following code shows an example of how to configure and build an `OAuth2AuthorizedClientProvider` composite that provides support for the `authorization_code`, `refresh_token`, `client_credentials`, and `password` authorization grant types: ==== .Java @@ -462,12 +462,12 @@ fun authorizedClientManager( ---- ==== -When an authorization attempt succeeds, the `DefaultOAuth2AuthorizedClientManager` will delegate to the `OAuth2AuthorizationSuccessHandler`, which (by default) will save the `OAuth2AuthorizedClient` via the `OAuth2AuthorizedClientRepository`. -In the case of a re-authorization failure, eg. a refresh token is no longer valid, the previously saved `OAuth2AuthorizedClient` will be removed from the `OAuth2AuthorizedClientRepository` via the `RemoveAuthorizedClientOAuth2AuthorizationFailureHandler`. -The default behaviour may be customized via `setAuthorizationSuccessHandler(OAuth2AuthorizationSuccessHandler)` and `setAuthorizationFailureHandler(OAuth2AuthorizationFailureHandler)`. +When an authorization attempt succeeds, the `DefaultOAuth2AuthorizedClientManager` delegates to the `OAuth2AuthorizationSuccessHandler`, which (by default) saves the `OAuth2AuthorizedClient` through the `OAuth2AuthorizedClientRepository`. +In the case of a re-authorization failure (for example, a refresh token is no longer valid), the previously saved `OAuth2AuthorizedClient` is removed from the `OAuth2AuthorizedClientRepository` through the `RemoveAuthorizedClientOAuth2AuthorizationFailureHandler`. +You can customize the default behavior through `setAuthorizationSuccessHandler(OAuth2AuthorizationSuccessHandler)` and `setAuthorizationFailureHandler(OAuth2AuthorizationFailureHandler)`. The `DefaultOAuth2AuthorizedClientManager` is also associated with a `contextAttributesMapper` of type `Function>`, which is responsible for mapping attribute(s) from the `OAuth2AuthorizeRequest` to a `Map` of attributes to be associated to the `OAuth2AuthorizationContext`. -This can be useful when you need to supply an `OAuth2AuthorizedClientProvider` with required (supported) attribute(s), eg. the `PasswordOAuth2AuthorizedClientProvider` requires the resource owner's `username` and `password` to be available in `OAuth2AuthorizationContext.getAttributes()`. +This can be useful when you need to supply an `OAuth2AuthorizedClientProvider` with required (supported) attribute(s). For example, the `PasswordOAuth2AuthorizedClientProvider` requires the resource owner's `username` and `password` to be available in `OAuth2AuthorizationContext.getAttributes()`. The following code shows an example of the `contextAttributesMapper`: @@ -556,10 +556,10 @@ private fun contextAttributesMapper(): Function>. -This ensures that the `X-Forwarded-*` headers are used when expanding the `redirect-uri`. +Doing so ensures that the `X-Forwarded-*` headers are used when expanding the `redirect-uri`. ===== Customizing the Authorization Request @@ -712,8 +716,7 @@ One of the primary use cases an `OAuth2AuthorizationRequestResolver` can realize For example, OpenID Connect defines additional OAuth 2.0 request parameters for the https://openid.net/specs/openid-connect-core-1_0.html#AuthRequest[Authorization Code Flow] extending from the standard parameters defined in the https://tools.ietf.org/html/rfc6749#section-4.1.1[OAuth 2.0 Authorization Framework]. One of those extended parameters is the `prompt` parameter. -[NOTE] -OPTIONAL. Space delimited, case sensitive list of ASCII string values that specifies whether the Authorization Server prompts the End-User for reauthentication and consent. The defined values are: none, login, consent, select_account +NOTE: The `prompt` parameter is optional. Space delimited, case sensitive list of ASCII string values that specifies whether the Authorization Server prompts the End-User for re-authentication and consent. The defined values are: `none`, `login`, `consent`, and `select_account`. The following example shows how to configure the `DefaultOAuth2AuthorizationRequestResolver` with a `Consumer` that customizes the Authorization Request for `oauth2Login()`, by including the request parameter `prompt=consent`. @@ -802,10 +805,11 @@ class SecurityConfig : WebSecurityConfigurerAdapter() { ---- ==== -For the simple use case, where the additional request parameter is always the same for a specific provider, it may be added directly in the `authorization-uri` property. +For the simple use case where the additional request parameter is always the same for a specific provider, you can add it directly in the `authorization-uri` property. -For example, if the value for the request parameter `prompt` is always `consent` for the provider `okta`, than simply configure as follows: +For example, if the value for the request parameter `prompt` is always `consent` for the provider `okta`, you can configure it as follows: +==== [source,yaml] ---- spring: @@ -816,14 +820,14 @@ spring: okta: authorization-uri: https://dev-1234.oktapreview.com/oauth2/v1/authorize?prompt=consent ---- +==== The preceding example shows the common use case of adding a custom parameter on top of the standard parameters. -Alternatively, if your requirements are more advanced, you can take full control in building the Authorization Request URI by simply overriding the `OAuth2AuthorizationRequest.authorizationRequestUri` property. +Alternatively, if your requirements are more advanced, you can take full control in building the Authorization Request URI by overriding the `OAuth2AuthorizationRequest.authorizationRequestUri` property. -[TIP] -`OAuth2AuthorizationRequest.Builder.build()` constructs the `OAuth2AuthorizationRequest.authorizationRequestUri`, which represents the Authorization Request URI including all query parameters using the `application/x-www-form-urlencoded` format. +TIP: `OAuth2AuthorizationRequest.Builder.build()` constructs the `OAuth2AuthorizationRequest.authorizationRequestUri`, which represents the Authorization Request URI that includes all query parameters that use the `application/x-www-form-urlencoded` format. -The following example shows a variation of `authorizationRequestCustomizer()` from the preceding example, and instead overrides the `OAuth2AuthorizationRequest.authorizationRequestUri` property. +The following example shows a variation of `authorizationRequestCustomizer()` from the preceding example and instead overrides the `OAuth2AuthorizationRequest.authorizationRequestUri` property: ==== .Java @@ -856,12 +860,11 @@ private fun authorizationRequestCustomizer(): Consumer>`. -The default implementation `OAuth2AuthorizationCodeGrantRequestEntityConverter` builds a `RequestEntity` representation of a standard https://tools.ietf.org/html/rfc6749#section-4.1.3[OAuth 2.0 Access Token Request]. -However, providing a custom `Converter`, would allow you to extend the standard Token Request and add custom parameter(s). +The default implementation (`OAuth2AuthorizationCodeGrantRequestEntityConverter`) builds a `RequestEntity` representation of a standard https://tools.ietf.org/html/rfc6749#section-4.1.3[OAuth 2.0 Access Token Request]. +However, providing a custom `Converter` would let you extend the standard Token Request and add custom parameter(s). IMPORTANT: The custom `Converter` must return a valid `RequestEntity` representation of an OAuth 2.0 Access Token Request that is understood by the intended OAuth 2.0 Provider. ===== Customizing the Access Token Response -On the other end, if you need to customize the post-handling of the Token Response, you will need to provide `DefaultAuthorizationCodeTokenResponseClient.setRestOperations()` with a custom configured `RestOperations`. +On the other end, if you need to customize the post-handling of the Token Response, you need to provide `DefaultAuthorizationCodeTokenResponseClient.setRestOperations()` with a custom configured `RestOperations`. The default `RestOperations` is configured as follows: ==== @@ -959,15 +961,15 @@ restTemplate.errorHandler = OAuth2ErrorResponseErrorHandler() ---- ==== -TIP: Spring MVC `FormHttpMessageConverter` is required as it's used when sending the OAuth 2.0 Access Token Request. +TIP: Spring MVC `FormHttpMessageConverter` is required, as it is used when sending the OAuth 2.0 Access Token Request. -`OAuth2AccessTokenResponseHttpMessageConverter` is a `HttpMessageConverter` for an OAuth 2.0 Access Token Response. +`OAuth2AccessTokenResponseHttpMessageConverter` is an `HttpMessageConverter` for an OAuth 2.0 Access Token Response. You can provide `OAuth2AccessTokenResponseHttpMessageConverter.setTokenResponseConverter()` with a custom `Converter, OAuth2AccessTokenResponse>` that is used for converting the OAuth 2.0 Access Token Response parameters to an `OAuth2AccessTokenResponse`. -`OAuth2ErrorResponseErrorHandler` is a `ResponseErrorHandler` that can handle an OAuth 2.0 Error, eg. 400 Bad Request. +`OAuth2ErrorResponseErrorHandler` is a `ResponseErrorHandler` that can handle an OAuth 2.0 Error, such as `400 Bad Request`. It uses an `OAuth2ErrorHttpMessageConverter` for converting the OAuth 2.0 Error parameters to an `OAuth2Error`. -Whether you customize `DefaultAuthorizationCodeTokenResponseClient` or provide your own implementation of `OAuth2AccessTokenResponseClient`, you'll need to configure it as shown in the following example: +Whether you customize `DefaultAuthorizationCodeTokenResponseClient` or provide your own implementation of `OAuth2AccessTokenResponseClient`, you need to configure it as follows: .Access Token Response Configuration ==== @@ -1023,32 +1025,30 @@ class OAuth2ClientSecurityConfig : WebSecurityConfigurerAdapter() { [[oauth2Client-refresh-token-grant]] ==== Refresh Token -[NOTE] -Please refer to the OAuth 2.0 Authorization Framework for further details on the https://tools.ietf.org/html/rfc6749#section-1.5[Refresh Token]. +NOTE: See the OAuth 2.0 Authorization Framework for further details on the https://tools.ietf.org/html/rfc6749#section-1.5[Refresh Token]. ===== Refreshing an Access Token -[NOTE] -Please refer to the https://tools.ietf.org/html/rfc6749#section-6[Access Token Request/Response] protocol flow for the Refresh Token grant. +NOTE: See the https://tools.ietf.org/html/rfc6749#section-6[Access Token Request/Response] protocol flow for the Refresh Token grant. The default implementation of `OAuth2AccessTokenResponseClient` for the Refresh Token grant is `DefaultRefreshTokenTokenResponseClient`, which uses a `RestOperations` when refreshing an access token at the Authorization Server’s Token Endpoint. -The `DefaultRefreshTokenTokenResponseClient` is quite flexible as it allows you to customize the pre-processing of the Token Request and/or post-handling of the Token Response. +The `DefaultRefreshTokenTokenResponseClient` is flexible, as it lets you customize the pre-processing of the Token Request or post-handling of the Token Response. ===== Customizing the Access Token Request If you need to customize the pre-processing of the Token Request, you can provide `DefaultRefreshTokenTokenResponseClient.setRequestEntityConverter()` with a custom `Converter>`. -The default implementation `OAuth2RefreshTokenGrantRequestEntityConverter` builds a `RequestEntity` representation of a standard https://tools.ietf.org/html/rfc6749#section-6[OAuth 2.0 Access Token Request]. -However, providing a custom `Converter`, would allow you to extend the standard Token Request and add custom parameter(s). +The default implementation (`OAuth2RefreshTokenGrantRequestEntityConverter`) builds a `RequestEntity` representation of a standard https://tools.ietf.org/html/rfc6749#section-6[OAuth 2.0 Access Token Request]. +However, providing a custom `Converter` would let you extend the standard Token Request and add custom parameter(s). IMPORTANT: The custom `Converter` must return a valid `RequestEntity` representation of an OAuth 2.0 Access Token Request that is understood by the intended OAuth 2.0 Provider. ===== Customizing the Access Token Response -On the other end, if you need to customize the post-handling of the Token Response, you will need to provide `DefaultRefreshTokenTokenResponseClient.setRestOperations()` with a custom configured `RestOperations`. +On the other end, if you need to customize the post-handling of the Token Response, you need to provide `DefaultRefreshTokenTokenResponseClient.setRestOperations()` with a custom configured `RestOperations`. The default `RestOperations` is configured as follows: ==== @@ -1073,15 +1073,15 @@ restTemplate.errorHandler = OAuth2ErrorResponseErrorHandler() ---- ==== -TIP: Spring MVC `FormHttpMessageConverter` is required as it's used when sending the OAuth 2.0 Access Token Request. +TIP: Spring MVC `FormHttpMessageConverter` is required, as it is used when sending the OAuth 2.0 Access Token Request. `OAuth2AccessTokenResponseHttpMessageConverter` is a `HttpMessageConverter` for an OAuth 2.0 Access Token Response. You can provide `OAuth2AccessTokenResponseHttpMessageConverter.setTokenResponseConverter()` with a custom `Converter, OAuth2AccessTokenResponse>` that is used for converting the OAuth 2.0 Access Token Response parameters to an `OAuth2AccessTokenResponse`. -`OAuth2ErrorResponseErrorHandler` is a `ResponseErrorHandler` that can handle an OAuth 2.0 Error, eg. 400 Bad Request. +`OAuth2ErrorResponseErrorHandler` is a `ResponseErrorHandler` that can handle an OAuth 2.0 Error, such as `400 Bad Request`. It uses an `OAuth2ErrorHttpMessageConverter` for converting the OAuth 2.0 Error parameters to an `OAuth2Error`. -Whether you customize `DefaultRefreshTokenTokenResponseClient` or provide your own implementation of `OAuth2AccessTokenResponseClient`, you'll need to configure it as shown in the following example: +Whether you customize `DefaultRefreshTokenTokenResponseClient` or provide your own implementation of `OAuth2AccessTokenResponseClient`, you need to configure it as follows: ==== .Java @@ -1122,39 +1122,37 @@ authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider) `OAuth2AuthorizedClientProviderBuilder.builder().refreshToken()` configures a `RefreshTokenOAuth2AuthorizedClientProvider`, which is an implementation of an `OAuth2AuthorizedClientProvider` for the Refresh Token grant. -The `OAuth2RefreshToken` may optionally be returned in the Access Token Response for the `authorization_code` and `password` grant types. -If the `OAuth2AuthorizedClient.getRefreshToken()` is available and the `OAuth2AuthorizedClient.getAccessToken()` is expired, it will automatically be refreshed by the `RefreshTokenOAuth2AuthorizedClientProvider`. +The `OAuth2RefreshToken` can optionally be returned in the Access Token Response for the `authorization_code` and `password` grant types. +If the `OAuth2AuthorizedClient.getRefreshToken()` is available and the `OAuth2AuthorizedClient.getAccessToken()` is expired, it is automatically refreshed by the `RefreshTokenOAuth2AuthorizedClientProvider`. [[oauth2Client-client-creds-grant]] ==== Client Credentials -[NOTE] -Please refer to the OAuth 2.0 Authorization Framework for further details on the https://tools.ietf.org/html/rfc6749#section-1.3.4[Client Credentials] grant. +NOTE: See the OAuth 2.0 Authorization Framework for further details on the https://tools.ietf.org/html/rfc6749#section-1.3.4[Client Credentials] grant. ===== Requesting an Access Token -[NOTE] -Please refer to the https://tools.ietf.org/html/rfc6749#section-4.4.2[Access Token Request/Response] protocol flow for the Client Credentials grant. +NOTE: See the https://tools.ietf.org/html/rfc6749#section-4.4.2[Access Token Request/Response] protocol flow for the Client Credentials grant. The default implementation of `OAuth2AccessTokenResponseClient` for the Client Credentials grant is `DefaultClientCredentialsTokenResponseClient`, which uses a `RestOperations` when requesting an access token at the Authorization Server’s Token Endpoint. -The `DefaultClientCredentialsTokenResponseClient` is quite flexible as it allows you to customize the pre-processing of the Token Request and/or post-handling of the Token Response. +The `DefaultClientCredentialsTokenResponseClient` is flexible, as it lets you customize the pre-processing of the Token Request or post-handling of the Token Response. ===== Customizing the Access Token Request If you need to customize the pre-processing of the Token Request, you can provide `DefaultClientCredentialsTokenResponseClient.setRequestEntityConverter()` with a custom `Converter>`. -The default implementation `OAuth2ClientCredentialsGrantRequestEntityConverter` builds a `RequestEntity` representation of a standard https://tools.ietf.org/html/rfc6749#section-4.4.2[OAuth 2.0 Access Token Request]. -However, providing a custom `Converter`, would allow you to extend the standard Token Request and add custom parameter(s). +The default implementation (`OAuth2ClientCredentialsGrantRequestEntityConverter`) builds a `RequestEntity` representation of a standard https://tools.ietf.org/html/rfc6749#section-4.4.2[OAuth 2.0 Access Token Request]. +However, providing a custom `Converter` would let you extend the standard Token Request and add custom parameter(s). IMPORTANT: The custom `Converter` must return a valid `RequestEntity` representation of an OAuth 2.0 Access Token Request that is understood by the intended OAuth 2.0 Provider. ===== Customizing the Access Token Response -On the other end, if you need to customize the post-handling of the Token Response, you will need to provide `DefaultClientCredentialsTokenResponseClient.setRestOperations()` with a custom configured `RestOperations`. +On the other end, if you need to customize the post-handling of the Token Response, you need to provide `DefaultClientCredentialsTokenResponseClient.setRestOperations()` with a custom configured `RestOperations`. The default `RestOperations` is configured as follows: ==== @@ -1179,15 +1177,15 @@ restTemplate.errorHandler = OAuth2ErrorResponseErrorHandler() ---- ==== -TIP: Spring MVC `FormHttpMessageConverter` is required as it's used when sending the OAuth 2.0 Access Token Request. +TIP: Spring MVC `FormHttpMessageConverter` is required, as it is used when sending the OAuth 2.0 Access Token Request. `OAuth2AccessTokenResponseHttpMessageConverter` is a `HttpMessageConverter` for an OAuth 2.0 Access Token Response. You can provide `OAuth2AccessTokenResponseHttpMessageConverter.setTokenResponseConverter()` with a custom `Converter, OAuth2AccessTokenResponse>` that is used for converting the OAuth 2.0 Access Token Response parameters to an `OAuth2AccessTokenResponse`. -`OAuth2ErrorResponseErrorHandler` is a `ResponseErrorHandler` that can handle an OAuth 2.0 Error, eg. 400 Bad Request. -It uses an `OAuth2ErrorHttpMessageConverter` for converting the OAuth 2.0 Error parameters to an `OAuth2Error`. +`OAuth2ErrorResponseErrorHandler` is a `ResponseErrorHandler` that can handle an OAuth 2.0 Error, such as `400 Bad Request`. +It uses an `OAuth2ErrorHttpMessageConverter` to convert the OAuth 2.0 Error parameters to an `OAuth2Error`. -Whether you customize `DefaultClientCredentialsTokenResponseClient` or provide your own implementation of `OAuth2AccessTokenResponseClient`, you'll need to configure it as shown in the following example: +Whether you customize `DefaultClientCredentialsTokenResponseClient` or provide your own implementation of `OAuth2AccessTokenResponseClient`, you need to configure it as follows: ==== .Java @@ -1222,14 +1220,14 @@ authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider) ---- ==== -[NOTE] -`OAuth2AuthorizedClientProviderBuilder.builder().clientCredentials()` configures a `ClientCredentialsOAuth2AuthorizedClientProvider`, +NOTE: `OAuth2AuthorizedClientProviderBuilder.builder().clientCredentials()` configures a `ClientCredentialsOAuth2AuthorizedClientProvider`, which is an implementation of an `OAuth2AuthorizedClientProvider` for the Client Credentials grant. ===== Using the Access Token -Given the following Spring Boot 2.x properties for an OAuth 2.0 Client registration: +Consider the following Spring Boot 2.x properties for an OAuth 2.0 Client registration: +==== [source,yaml] ---- spring: @@ -1246,8 +1244,9 @@ spring: okta: token-uri: https://dev-1234.oktapreview.com/oauth2/v1/token ---- +==== -...and the `OAuth2AuthorizedClientManager` `@Bean`: +Further consider the following `OAuth2AuthorizedClientManager` `@Bean`: ==== .Java @@ -1290,7 +1289,7 @@ fun authorizedClientManager( ---- ==== -You may obtain the `OAuth2AccessToken` as follows: +Given the preceding properties and bean, you can obtain the `OAuth2AccessToken` as follows: ==== .Java @@ -1355,40 +1354,37 @@ class OAuth2ClientController { ---- ==== -[NOTE] -`HttpServletRequest` and `HttpServletResponse` are both OPTIONAL attributes. -If not provided, it will default to `ServletRequestAttributes` using `RequestContextHolder.getRequestAttributes()`. +NOTE: `HttpServletRequest` and `HttpServletResponse` are both OPTIONAL attributes. +If not provided, they default to `ServletRequestAttributes` by using `RequestContextHolder.getRequestAttributes()`. [[oauth2Client-password-grant]] ==== Resource Owner Password Credentials -[NOTE] -Please refer to the OAuth 2.0 Authorization Framework for further details on the https://tools.ietf.org/html/rfc6749#section-1.3.3[Resource Owner Password Credentials] grant. +NOTE: See the OAuth 2.0 Authorization Framework for further details on the https://tools.ietf.org/html/rfc6749#section-1.3.3[Resource Owner Password Credentials] grant. ===== Requesting an Access Token -[NOTE] -Please refer to the https://tools.ietf.org/html/rfc6749#section-4.3.2[Access Token Request/Response] protocol flow for the Resource Owner Password Credentials grant. +NOTE: See the https://tools.ietf.org/html/rfc6749#section-4.3.2[Access Token Request/Response] protocol flow for the Resource Owner Password Credentials grant. The default implementation of `OAuth2AccessTokenResponseClient` for the Resource Owner Password Credentials grant is `DefaultPasswordTokenResponseClient`, which uses a `RestOperations` when requesting an access token at the Authorization Server’s Token Endpoint. -The `DefaultPasswordTokenResponseClient` is quite flexible as it allows you to customize the pre-processing of the Token Request and/or post-handling of the Token Response. +The `DefaultPasswordTokenResponseClient` is flexible, as it lets you customize the pre-processing of the Token Request or post-handling of the Token Response. ===== Customizing the Access Token Request If you need to customize the pre-processing of the Token Request, you can provide `DefaultPasswordTokenResponseClient.setRequestEntityConverter()` with a custom `Converter>`. -The default implementation `OAuth2PasswordGrantRequestEntityConverter` builds a `RequestEntity` representation of a standard https://tools.ietf.org/html/rfc6749#section-4.3.2[OAuth 2.0 Access Token Request]. -However, providing a custom `Converter`, would allow you to extend the standard Token Request and add custom parameter(s). +The default implementation (`OAuth2PasswordGrantRequestEntityConverter`) builds a `RequestEntity` representation of a standard https://tools.ietf.org/html/rfc6749#section-4.3.2[OAuth 2.0 Access Token Request]. +However, providing a custom `Converter` would let you extend the standard Token Request and add custom parameter(s). IMPORTANT: The custom `Converter` must return a valid `RequestEntity` representation of an OAuth 2.0 Access Token Request that is understood by the intended OAuth 2.0 Provider. ===== Customizing the Access Token Response -On the other end, if you need to customize the post-handling of the Token Response, you will need to provide `DefaultPasswordTokenResponseClient.setRestOperations()` with a custom configured `RestOperations`. +On the other end, if you need to customize the post-handling of the Token Response, you need to provide `DefaultPasswordTokenResponseClient.setRestOperations()` with a custom configured `RestOperations`. The default `RestOperations` is configured as follows: ==== @@ -1413,15 +1409,15 @@ restTemplate.errorHandler = OAuth2ErrorResponseErrorHandler() ---- ==== -TIP: Spring MVC `FormHttpMessageConverter` is required as it's used when sending the OAuth 2.0 Access Token Request. +TIP: Spring MVC `FormHttpMessageConverter` is required, as it is used when sending the OAuth 2.0 Access Token Request. `OAuth2AccessTokenResponseHttpMessageConverter` is a `HttpMessageConverter` for an OAuth 2.0 Access Token Response. -You can provide `OAuth2AccessTokenResponseHttpMessageConverter.setTokenResponseConverter()` with a custom `Converter, OAuth2AccessTokenResponse>` that is used for converting the OAuth 2.0 Access Token Response parameters to an `OAuth2AccessTokenResponse`. +You can provide `OAuth2AccessTokenResponseHttpMessageConverter.setTokenResponseConverter()` with a custom `Converter, OAuth2AccessTokenResponse>` that is used to convert the OAuth 2.0 Access Token Response parameters to an `OAuth2AccessTokenResponse`. -`OAuth2ErrorResponseErrorHandler` is a `ResponseErrorHandler` that can handle an OAuth 2.0 Error, eg. 400 Bad Request. -It uses an `OAuth2ErrorHttpMessageConverter` for converting the OAuth 2.0 Error parameters to an `OAuth2Error`. +`OAuth2ErrorResponseErrorHandler` is a `ResponseErrorHandler` that can handle an OAuth 2.0 Error, such as `400 Bad Request`. +It uses an `OAuth2ErrorHttpMessageConverter` to convert the OAuth 2.0 Error parameters to an `OAuth2Error`. -Whether you customize `DefaultPasswordTokenResponseClient` or provide your own implementation of `OAuth2AccessTokenResponseClient`, you'll need to configure it as shown in the following example: +Whether you customize `DefaultPasswordTokenResponseClient` or provide your own implementation of `OAuth2AccessTokenResponseClient`, you need to configure it as follows: ==== .Java @@ -1463,7 +1459,7 @@ which is an implementation of an `OAuth2AuthorizedClientProvider` for the Resour ===== Using the Access Token -Given the following Spring Boot 2.x properties for an OAuth 2.0 Client registration: +Consider the following Spring Boot 2.x properties for an OAuth 2.0 Client registration: [source,yaml] ---- @@ -1482,7 +1478,7 @@ spring: token-uri: https://dev-1234.oktapreview.com/oauth2/v1/token ---- -...and the `OAuth2AuthorizedClientManager` `@Bean`: +Further consider the `OAuth2AuthorizedClientManager` `@Bean`: ==== .Java @@ -1568,7 +1564,7 @@ private fun contextAttributesMapper(): Function> and therefore inherits it's capabilities. +The `@RegisteredOAuth2AuthorizedClient` annotation is handled by `OAuth2AuthorizedClientArgumentResolver`, which directly uses an <> and, therefore, inherits its capabilities. [[oauth2Client-webclient-servlet]] -=== WebClient integration for Servlet Environments +=== WebClient Integration for Servlet Environments -The OAuth 2.0 Client support integrates with `WebClient` using an `ExchangeFilterFunction`. +The OAuth 2.0 Client support integrates with `WebClient` by using an `ExchangeFilterFunction`. -The `ServletOAuth2AuthorizedClientExchangeFilterFunction` provides a simple mechanism for requesting protected resources by using an `OAuth2AuthorizedClient` and including the associated `OAuth2AccessToken` as a Bearer Token. -It directly uses an <> and therefore inherits the following capabilities: +The `ServletOAuth2AuthorizedClientExchangeFilterFunction` provides a mechanism for requesting protected resources by using an `OAuth2AuthorizedClient` and including the associated `OAuth2AccessToken` as a Bearer Token. +It directly uses an <> and, therefore, inherits the following capabilities: -* An `OAuth2AccessToken` will be requested if the client has not yet been authorized. -** `authorization_code` - triggers the Authorization Request redirect to initiate the flow -** `client_credentials` - the access token is obtained directly from the Token Endpoint -** `password` - the access token is obtained directly from the Token Endpoint -* If the `OAuth2AccessToken` is expired, it will be refreshed (or renewed) if an `OAuth2AuthorizedClientProvider` is available to perform the authorization +* An `OAuth2AccessToken` is requested if the client has not yet been authorized. +** `authorization_code`: Triggers the Authorization Request redirect to initiate the flow. +** `client_credentials`: The access token is obtained directly from the Token Endpoint. +** `password`: The access token is obtained directly from the Token Endpoint. +* If the `OAuth2AccessToken` is expired, it is refreshed (or renewed) if an `OAuth2AuthorizedClientProvider` is available to perform the authorization The following code shows an example of how to configure `WebClient` with OAuth 2.0 Client support: @@ -2161,9 +2159,8 @@ fun index(@RegisteredOAuth2AuthorizedClient("okta") authorizedClient: OAuth2Auth return "index" } ---- -==== - <1> `oauth2AuthorizedClient()` is a `static` method in `ServletOAuth2AuthorizedClientExchangeFilterFunction`. +==== The following code shows how to set the `ClientRegistration.getRegistrationId()` as a request attribute: @@ -2209,15 +2206,14 @@ fun index(): String { return "index" } ---- -==== <1> `clientRegistrationId()` is a `static` method in `ServletOAuth2AuthorizedClientExchangeFilterFunction`. - +==== ==== Defaulting the Authorized Client -If neither `OAuth2AuthorizedClient` or `ClientRegistration.getRegistrationId()` is provided as a request attribute, the `ServletOAuth2AuthorizedClientExchangeFilterFunction` can determine the _default_ client to use depending on it's configuration. +If neither `OAuth2AuthorizedClient` or `ClientRegistration.getRegistrationId()` is provided as a request attribute, the `ServletOAuth2AuthorizedClientExchangeFilterFunction` can determine the _default_ client to use, depending on its configuration. -If `setDefaultOAuth2AuthorizedClient(true)` is configured and the user has authenticated using `HttpSecurity.oauth2Login()`, the `OAuth2AccessToken` associated with the current `OAuth2AuthenticationToken` is used. +If `setDefaultOAuth2AuthorizedClient(true)` is configured and the user has authenticated by using `HttpSecurity.oauth2Login()`, the `OAuth2AccessToken` associated with the current `OAuth2AuthenticationToken` is used. The following code shows the specific configuration: @@ -2250,8 +2246,7 @@ fun webClient(authorizedClientManager: OAuth2AuthorizedClientManager?): WebClien ---- ==== -[WARNING] -It is recommended to be cautious with this feature since all HTTP requests will receive the access token. +WARNING: Be cautious with this feature, since all HTTP requests receive the access token. Alternatively, if `setDefaultClientRegistrationId("okta")` is configured with a valid `ClientRegistration`, the `OAuth2AccessToken` associated with the `OAuth2AuthorizedClient` is used. @@ -2286,5 +2281,4 @@ fun webClient(authorizedClientManager: OAuth2AuthorizedClientManager?): WebClien ---- ==== -[WARNING] -It is recommended to be cautious with this feature since all HTTP requests will receive the access token. +WARNING: Be cautious with this feature, since all HTTP requests receive the access token. diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/oauth2/oauth2-login.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/oauth2/oauth2-login.adoc index 24cac1e45b0..b8fc76df6ea 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/oauth2/oauth2-login.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/oauth2/oauth2-login.adoc @@ -1,8 +1,8 @@ [[oauth2login]] == OAuth 2.0 Login -The OAuth 2.0 Login feature provides an application with the capability to have users log in to the application by using their existing account at an OAuth 2.0 Provider (e.g. GitHub) or OpenID Connect 1.0 Provider (such as Google). -OAuth 2.0 Login implements the use cases: "Login with Google" or "Login with GitHub". +The OAuth 2.0 Login feature lets an application have users log in to the application by using their existing account at an OAuth 2.0 Provider (such as GitHub) or OpenID Connect 1.0 Provider (such as Google). +OAuth 2.0 Login implements two use cases: "`Login with Google`" or "`Login with GitHub`". NOTE: OAuth 2.0 Login is implemented by using the *Authorization Code Grant*, as specified in the https://tools.ietf.org/html/rfc6749#section-4.1[OAuth 2.0 Authorization Framework] and https://openid.net/specs/openid-connect-core-1_0.html#CodeFlowAuth[OpenID Connect Core 1.0]. @@ -12,38 +12,38 @@ NOTE: OAuth 2.0 Login is implemented by using the *Authorization Code Grant*, as Spring Boot 2.x brings full auto-configuration capabilities for OAuth 2.0 Login. -This section shows how to configure the {gh-samples-url}/boot/oauth2login[*OAuth 2.0 Login sample*] using _Google_ as the _Authentication Provider_ and covers the following topics: +This section shows how to configure the {gh-samples-url}/boot/oauth2login[*OAuth 2.0 Login sample*] by using _Google_ as the _Authentication Provider_ and covers the following topics: -* <> -* <> -* <> -* <> +* <> +* <> +* <> +* <> [[oauth2login-sample-initial-setup]] -==== Initial setup +==== Initial Setup To use Google's OAuth 2.0 authentication system for login, you must set up a project in the Google API Console to obtain OAuth 2.0 credentials. -NOTE: https://developers.google.com/identity/protocols/OpenIDConnect[Google's OAuth 2.0 implementation] for authentication conforms to the https://openid.net/connect/[OpenID Connect 1.0] specification and is https://openid.net/certification/[OpenID Certified]. +NOTE: https://developers.google.com/identity/protocols/OpenIDConnect[Google's OAuth 2.0 implementation] for authentication conforms to the https://openid.net/connect/[OpenID Connect 1.0] specification and is https://openid.net/certification/[OpenID certified]. -Follow the instructions on the https://developers.google.com/identity/protocols/OpenIDConnect[OpenID Connect] page, starting in the section, "Setting up OAuth 2.0". +Follow the instructions on the https://developers.google.com/identity/protocols/OpenIDConnect[OpenID Connect] page, starting in the "`Setting up OAuth 2.0`" section. -After completing the "Obtain OAuth 2.0 credentials" instructions, you should have a new OAuth Client with credentials consisting of a Client ID and a Client Secret. +After completing the "`Obtain OAuth 2.0 credentials`" instructions, you should have new OAuth Client with credentials consisting of a Client ID and a Client Secret. [[oauth2login-sample-redirect-uri]] -==== Setting the redirect URI +==== Setting the Redirect URI -The redirect URI is the path in the application that the end-user's user-agent is redirected back to after they have authenticated with Google and have granted access to the OAuth Client _(<>)_ on the Consent page. +The redirect URI is the path in the application that the end-user's user-agent is redirected back to after they have authenticated with Google and have granted access to the OAuth Client (<>) on the Consent page. -In the "Set a redirect URI" sub-section, ensure that the *Authorized redirect URIs* field is set to `http://localhost:8080/login/oauth2/code/google`. +In the "`Set a redirect URI`" subsection, ensure that the *Authorized redirect URIs* field is set to `http://localhost:8080/login/oauth2/code/google`. TIP: The default redirect URI template is `+{baseUrl}/login/oauth2/code/{registrationId}+`. -The *_registrationId_* is a unique identifier for the <>. +The `registrationId` is a unique identifier for the <>. -IMPORTANT: If the OAuth Client is running behind a proxy server, it is recommended to check <> to ensure the application is correctly configured. -Also, see the supported <> for `redirect-uri`. +IMPORTANT: If the OAuth Client runs behind a proxy server, you should check the <> to ensure the application is correctly configured. +Also, see the supported <> for `redirect-uri`. [[oauth2login-sample-application-config]] @@ -69,21 +69,21 @@ spring: .OAuth Client properties ==== <1> `spring.security.oauth2.client.registration` is the base property prefix for OAuth Client properties. -<2> Following the base property prefix is the ID for the <>, such as google. +<2> Following the base property prefix is the ID for the <>, such as Google. ==== . Replace the values in the `client-id` and `client-secret` property with the OAuth 2.0 credentials you created earlier. [[oauth2login-sample-boot-application]] -==== Boot up the application +==== Boot up the Application Launch the Spring Boot 2.x sample and go to `http://localhost:8080`. You are then redirected to the default _auto-generated_ login page, which displays a link for Google. Click on the Google link, and you are then redirected to Google for authentication. -After authenticating with your Google account credentials, the next page presented to you is the Consent screen. +After authenticating with your Google account credentials, you see the Consent screen. The Consent screen asks you to either allow or deny access to the OAuth Client you created earlier. Click *Allow* to authorize the OAuth Client to access your email address and basic profile information. @@ -144,8 +144,7 @@ The following table outlines the mapping of the Spring Boot 2.x OAuth Client pro |`providerDetails.userInfoEndpoint.userNameAttributeName` |=== -[TIP] -A `ClientRegistration` can be initially configured using discovery of an OpenID Connect Provider's https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfig[Configuration endpoint] or an Authorization Server's https://tools.ietf.org/html/rfc8414#section-3[Metadata endpoint], by specifying the `spring.security.oauth2.client.provider._[providerId]_.issuer-uri` property. +TIP: You can initially configure a `ClientRegistration` by using discovery of an OpenID Connect Provider's https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfig[Configuration endpoint] or an Authorization Server's https://tools.ietf.org/html/rfc8414#section-3[Metadata endpoint], by specifying the `spring.security.oauth2.client.provider._[providerId]_.issuer-uri` property. [[oauth2login-common-oauth2-provider]] @@ -153,13 +152,14 @@ A `ClientRegistration` can be initially configured using discovery of an OpenID `CommonOAuth2Provider` pre-defines a set of default client properties for a number of well known providers: Google, GitHub, Facebook, and Okta. -For example, the `authorization-uri`, `token-uri`, and `user-info-uri` do not change often for a Provider. -Therefore, it makes sense to provide default values in order to reduce the required configuration. +For example, the `authorization-uri`, `token-uri`, and `user-info-uri` do not change often for a provider. +Therefore, it makes sense to provide default values, to reduce the required configuration. As demonstrated previously, when we <>, only the `client-id` and `client-secret` properties are required. The following listing shows an example: +==== [source,yaml] ---- spring: @@ -171,6 +171,7 @@ spring: client-id: google-client-id client-secret: google-client-secret ---- +==== [TIP] The auto-defaulting of client properties works seamlessly here because the `registrationId` (`google`) matches the `GOOGLE` `enum` (case-insensitive) in `CommonOAuth2Provider`. @@ -179,6 +180,7 @@ For cases where you may want to specify a different `registrationId`, such as `g The following listing shows an example: +==== [source,yaml] ---- spring: @@ -192,8 +194,8 @@ spring: client-secret: google-client-secret ---- <1> The `registrationId` is set to `google-login`. -<2> The `provider` property is set to `google`, which will leverage the auto-defaulting of client properties set in `CommonOAuth2Provider.GOOGLE.getBuilder()`. - +<2> The `provider` property is set to `google`, which uses the auto-defaulting of client properties set in `CommonOAuth2Provider.GOOGLE.getBuilder()`. +==== [[oauth2login-custom-provider-properties]] === Configuring Custom Provider Properties @@ -206,6 +208,7 @@ For these cases, Spring Boot 2.x provides the following base property for config The following listing shows an example: +==== [source,yaml] ---- spring: @@ -224,9 +227,8 @@ spring: user-name-attribute: sub jwk-set-uri: https://your-subdomain.oktapreview.com/oauth2/v1/keys ---- - <1> The base property (`spring.security.oauth2.client.provider.okta`) allows for custom configuration of protocol endpoint locations. - +==== [[oauth2login-override-boot-autoconfig]] === Overriding Spring Boot 2.x Auto-configuration @@ -240,9 +242,9 @@ It performs the following tasks: If you need to override the auto-configuration based on your specific requirements, you may do so in the following ways: -* <> -* <> -* <> +* <> +* <> +* <> [[oauth2login-register-clientregistrationrepository-bean]] @@ -600,14 +602,14 @@ The main goal of the `oauth2Login()` DSL was to closely align with the naming, a The OAuth 2.0 Authorization Framework defines the https://tools.ietf.org/html/rfc6749#section-3[Protocol Endpoints] as follows: -The authorization process utilizes two authorization server endpoints (HTTP resources): +The authorization process uses two authorization server endpoints (HTTP resources): -* Authorization Endpoint: Used by the client to obtain authorization from the resource owner via user-agent redirection. +* Authorization Endpoint: Used by the client to obtain authorization from the resource owner through user-agent redirection. * Token Endpoint: Used by the client to exchange an authorization grant for an access token, typically with client authentication. -As well as one client endpoint: +The authorization process also uses one client endpoint: -* Redirection Endpoint: Used by the authorization server to return responses containing authorization credentials to the client via the resource owner user-agent. +* Redirection Endpoint: Used by the authorization server to return responses that contain authorization credentials to the client through the resource owner user-agent. The OpenID Connect Core 1.0 specification defines the https://openid.net/specs/openid-connect-core-1_0.html#UserInfo[UserInfo Endpoint] as follows: @@ -719,9 +721,9 @@ The following code shows the complete configuration options available in the <> -* <> -* <> +* <> +* <> +* <> [[oauth2login-advanced-login-page]] @@ -730,8 +732,7 @@ The following sections go into more detail on each of the configuration options By default, the OAuth 2.0 Login Page is auto-generated by the `DefaultLoginPageGeneratingFilter`. The default login page shows each configured OAuth Client with its `ClientRegistration.clientName` as a link, which is capable of initiating the Authorization Request (or OAuth 2.0 Login). -[NOTE] -In order for `DefaultLoginPageGeneratingFilter` to show links for configured OAuth Clients, the registered `ClientRegistrationRepository` needs to also implement `Iterable`. +NOTE: For `DefaultLoginPageGeneratingFilter` to show links for configured OAuth Clients, the registered `ClientRegistrationRepository` needs to also implement `Iterable`. See `InMemoryClientRegistrationRepository` for reference. The link's destination for each OAuth Client defaults to the following: @@ -740,10 +741,12 @@ The link's destination for each OAuth Client defaults to the following: The following line shows an example: +==== [source,html] ---- Google ---- +==== To override the default login page, configure `oauth2Login().loginPage()` and (optionally) `oauth2Login().authorizationEndpoint().baseUri()`. @@ -802,35 +805,35 @@ class OAuth2LoginSecurityConfig : WebSecurityConfigurerAdapter() { ---- ==== -[IMPORTANT] -You need to provide a `@Controller` with a `@RequestMapping("/login/oauth2")` that is capable of rendering the custom login page. +IMPORTANT: You need to provide a `@Controller` with a `@RequestMapping("/login/oauth2")` that is capable of rendering the custom login page. [TIP] -==== +===== As noted earlier, configuring `oauth2Login().authorizationEndpoint().baseUri()` is optional. However, if you choose to customize it, ensure the link to each OAuth Client matches the `authorizationEndpoint().baseUri()`. The following line shows an example: +==== [source,html] ---- Google ---- ==== +===== [[oauth2login-advanced-redirection-endpoint]] ==== Redirection Endpoint -The Redirection Endpoint is used by the Authorization Server for returning the Authorization Response (which contains the authorization credentials) to the client via the Resource Owner user-agent. +The Redirection Endpoint is used by the Authorization Server for returning the Authorization Response (which contains the authorization credentials) to the client through the Resource Owner user-agent. -[TIP] -OAuth 2.0 Login leverages the Authorization Code Grant. +TIP: OAuth 2.0 Login leverages the Authorization Code Grant. Therefore, the authorization credential is the authorization code. The default Authorization Response `baseUri` (redirection endpoint) is `*/login/oauth2/code/**`, which is defined in `OAuth2LoginAuthenticationFilter.DEFAULT_FILTER_PROCESSES_URI`. -If you would like to customize the Authorization Response `baseUri`, configure it as shown in the following example: +If you would like to customize the Authorization Response `baseUri`, configure it as follows: .Redirection Endpoint Configuration ==== @@ -883,11 +886,12 @@ class OAuth2LoginSecurityConfig : WebSecurityConfigurerAdapter() { ==== [IMPORTANT] -==== +===== You also need to ensure the `ClientRegistration.redirectUri` matches the custom Authorization Response `baseUri`. The following listing shows an example: +==== .Java [source,java,role="primary",attrs="-attributes"] ---- @@ -908,36 +912,36 @@ return CommonOAuth2Provider.GOOGLE.getBuilder("google") .build() ---- ==== - +===== [[oauth2login-advanced-userinfo-endpoint]] ==== UserInfo Endpoint The UserInfo Endpoint includes a number of configuration options, as described in the following sub-sections: -* <> -* <> -* <> +* <> +* <> +* <> [[oauth2login-advanced-map-authorities]] ===== Mapping User Authorities -After the user successfully authenticates with the OAuth 2.0 Provider, the `OAuth2User.getAuthorities()` (or `OidcUser.getAuthorities()`) may be mapped to a new set of `GrantedAuthority` instances, which will be supplied to `OAuth2AuthenticationToken` when completing the authentication. +After the user successfully authenticates with the OAuth 2.0 Provider, the `OAuth2User.getAuthorities()` (or `OidcUser.getAuthorities()`) can be mapped to a new set of `GrantedAuthority` instances, which are supplied to `OAuth2AuthenticationToken` when completing the authentication. [TIP] `OAuth2AuthenticationToken.getAuthorities()` is used for authorizing requests, such as in `hasRole('USER')` or `hasRole('ADMIN')`. There are a couple of options to choose from when mapping user authorities: -* <> -* <> +* <> +* <> [[oauth2login-advanced-map-authorities-grantedauthoritiesmapper]] ====== Using a GrantedAuthoritiesMapper -Provide an implementation of `GrantedAuthoritiesMapper` and configure it as shown in the following example: +Provide an implementation of `GrantedAuthoritiesMapper` and configure it, as follows: .Granted Authorities Mapper Configuration ==== @@ -1037,7 +1041,7 @@ class OAuth2LoginSecurityConfig : WebSecurityConfigurerAdapter() { ---- ==== -Alternatively, you may register a `GrantedAuthoritiesMapper` `@Bean` to have it automatically applied to the configuration, as shown in the following example: +Alternatively, you can register a `GrantedAuthoritiesMapper` `@Bean` to have it automatically applied to the configuration, as follows: .Granted Authorities Mapper Bean Configuration ==== @@ -1081,11 +1085,11 @@ class OAuth2LoginSecurityConfig : WebSecurityConfigurerAdapter() { ==== [[oauth2login-advanced-map-authorities-oauth2userservice]] -====== Delegation-based strategy with OAuth2UserService +====== Delegation-based Strategy with OAuth2UserService -This strategy is advanced compared to using a `GrantedAuthoritiesMapper`, however, it's also more flexible as it gives you access to the `OAuth2UserRequest` and `OAuth2User` (when using an OAuth 2.0 UserService) or `OidcUserRequest` and `OidcUser` (when using an OpenID Connect 1.0 UserService). +This strategy is advanced compared to using a `GrantedAuthoritiesMapper`. However, it is also more flexible, as it gives you access to the `OAuth2UserRequest` and `OAuth2User` (when using an OAuth 2.0 UserService) or `OidcUserRequest` and `OidcUser` (when using an OpenID Connect 1.0 UserService). -The `OAuth2UserRequest` (and `OidcUserRequest`) provides you access to the associated `OAuth2AccessToken`, which is very useful in the cases where the _delegator_ needs to fetch authority information from a protected resource before it can map the custom authorities for the user. +The `OAuth2UserRequest` (and `OidcUserRequest`) provides you access to the associated `OAuth2AccessToken`, which is very useful in cases where the _delegator_ needs to fetch authority information from a protected resource before it can map the custom authorities for the user. The following example shows how to implement and configure a delegation-based strategy using an OpenID Connect 1.0 UserService: @@ -1187,27 +1191,28 @@ class OAuth2LoginSecurityConfig : WebSecurityConfigurerAdapter() { `DefaultOAuth2UserService` is an implementation of an `OAuth2UserService` that supports standard OAuth 2.0 Provider's. -[NOTE] -`OAuth2UserService` obtains the user attributes of the end-user (the resource owner) from the UserInfo Endpoint (by using the access token granted to the client during the authorization flow) and returns an `AuthenticatedPrincipal` in the form of an `OAuth2User`. +NOTE: `OAuth2UserService` obtains the user attributes of the end-user (the resource owner) from the UserInfo Endpoint (by using the access token granted to the client during the authorization flow) and returns an `AuthenticatedPrincipal` in the form of an `OAuth2User`. -`DefaultOAuth2UserService` uses a `RestOperations` when requesting the user attributes at the UserInfo Endpoint. +`DefaultOAuth2UserService` uses a `RestOperations` instance when requesting the user attributes at the UserInfo Endpoint. If you need to customize the pre-processing of the UserInfo Request, you can provide `DefaultOAuth2UserService.setRequestEntityConverter()` with a custom `Converter>`. The default implementation `OAuth2UserRequestEntityConverter` builds a `RequestEntity` representation of a UserInfo Request that sets the `OAuth2AccessToken` in the `Authorization` header by default. -On the other end, if you need to customize the post-handling of the UserInfo Response, you will need to provide `DefaultOAuth2UserService.setRestOperations()` with a custom configured `RestOperations`. +On the other end, if you need to customize the post-handling of the UserInfo Response, you need to provide `DefaultOAuth2UserService.setRestOperations()` with a custom configured `RestOperations`. The default `RestOperations` is configured as follows: +==== [source,java] ---- RestTemplate restTemplate = new RestTemplate(); restTemplate.setErrorHandler(new OAuth2ErrorResponseErrorHandler()); ---- +==== `OAuth2ErrorResponseErrorHandler` is a `ResponseErrorHandler` that can handle an OAuth 2.0 Error (400 Bad Request). It uses an `OAuth2ErrorHttpMessageConverter` for converting the OAuth 2.0 Error parameters to an `OAuth2Error`. -Whether you customize `DefaultOAuth2UserService` or provide your own implementation of `OAuth2UserService`, you'll need to configure it as shown in the following example: +Whether you customize `DefaultOAuth2UserService` or provide your own implementation of `OAuth2UserService`, you need to configure it as follows: ==== .Java @@ -1265,9 +1270,9 @@ class OAuth2LoginSecurityConfig : WebSecurityConfigurerAdapter() { The `OidcUserService` leverages the `DefaultOAuth2UserService` when requesting the user attributes at the UserInfo Endpoint. -If you need to customize the pre-processing of the UserInfo Request and/or the post-handling of the UserInfo Response, you will need to provide `OidcUserService.setOauth2UserService()` with a custom configured `DefaultOAuth2UserService`. +If you need to customize the pre-processing of the UserInfo Request or the post-handling of the UserInfo Response, you need to provide `OidcUserService.setOauth2UserService()` with a custom configured `DefaultOAuth2UserService`. -Whether you customize `OidcUserService` or provide your own implementation of `OAuth2UserService` for OpenID Connect 1.0 Provider's, you'll need to configure it as shown in the following example: +Whether you customize `OidcUserService` or provide your own implementation of `OAuth2UserService` for OpenID Connect 1.0 Provider's, you need to configure it as follows: ==== .Java @@ -1323,14 +1328,14 @@ class OAuth2LoginSecurityConfig : WebSecurityConfigurerAdapter() { OpenID Connect 1.0 Authentication introduces the https://openid.net/specs/openid-connect-core-1_0.html#IDToken[ID Token], which is a security token that contains Claims about the Authentication of an End-User by an Authorization Server when used by a Client. -The ID Token is represented as a https://tools.ietf.org/html/rfc7519[JSON Web Token] (JWT) and MUST be signed using https://tools.ietf.org/html/rfc7515[JSON Web Signature] (JWS). +The ID Token is represented as a https://tools.ietf.org/html/rfc7519[JSON Web Token] (JWT) and MUST be signed by using https://tools.ietf.org/html/rfc7515[JSON Web Signature] (JWS). The `OidcIdTokenDecoderFactory` provides a `JwtDecoder` used for `OidcIdToken` signature verification. The default algorithm is `RS256` but may be different when assigned during client registration. -For these cases, a resolver may be configured to return the expected JWS algorithm assigned for a specific client. +For these cases, you can configure a resolver to return the expected JWS algorithm assigned for a specific client. -The JWS algorithm resolver is a `Function` that accepts a `ClientRegistration` and returns the expected `JwsAlgorithm` for the client, eg. `SignatureAlgorithm.RS256` or `MacAlgorithm.HS256` +The JWS algorithm resolver is a `Function` that accepts a `ClientRegistration` and returns the expected `JwsAlgorithm` for the client, such as `SignatureAlgorithm.RS256` or `MacAlgorithm.HS256` -The following code shows how to configure the `OidcIdTokenDecoderFactory` `@Bean` to default to `MacAlgorithm.HS256` for all `ClientRegistration`: +The following code shows how to configure the `OidcIdTokenDecoderFactory` `@Bean` to default to `MacAlgorithm.HS256` for all `ClientRegistration` instances: ==== .Java @@ -1356,22 +1361,21 @@ fun idTokenDecoderFactory(): JwtDecoderFactory { ---- ==== -[NOTE] -For MAC based algorithms such as `HS256`, `HS384` or `HS512`, the `client-secret` corresponding to the `client-id` is used as the symmetric key for signature verification. +NOTE: For MAC-based algorithms (such as `HS256`, `HS384`, or `HS512`), the `client-secret` that corresponds to the `client-id` is used as the symmetric key for signature verification. -[TIP] -If more than one `ClientRegistration` is configured for OpenID Connect 1.0 Authentication, the JWS algorithm resolver may evaluate the provided `ClientRegistration` to determine which algorithm to return. +TIP: If more than one `ClientRegistration` is configured for OpenID Connect 1.0 Authentication, the JWS algorithm resolver may evaluate the provided `ClientRegistration` to determine which algorithm to return. [[oauth2login-advanced-oidc-logout]] ==== OpenID Connect 1.0 Logout -OpenID Connect Session Management 1.0 allows the ability to log out the End-User at the Provider using the Client. +OpenID Connect Session Management 1.0 allows the ability to log out the end user at the Provider by using the Client. One of the strategies available is https://openid.net/specs/openid-connect-session-1_0.html#RPLogout[RP-Initiated Logout]. -If the OpenID Provider supports both Session Management and https://openid.net/specs/openid-connect-discovery-1_0.html[Discovery], the client may obtain the `end_session_endpoint` `URL` from the OpenID Provider's https://openid.net/specs/openid-connect-session-1_0.html#OPMetadata[Discovery Metadata]. -This can be achieved by configuring the `ClientRegistration` with the `issuer-uri`, as in the following example: +If the OpenID Provider supports both Session Management and https://openid.net/specs/openid-connect-discovery-1_0.html[Discovery], the client can obtain the `end_session_endpoint` `URL` from the OpenID Provider's https://openid.net/specs/openid-connect-session-1_0.html#OPMetadata[Discovery Metadata]. +You can do so by configuring the `ClientRegistration` with the `issuer-uri`, as follows: +==== [source,yaml] ---- spring: @@ -1387,8 +1391,9 @@ spring: okta: issuer-uri: https://dev-1234.oktapreview.com ---- +==== -...and the `OidcClientInitiatedLogoutSuccessHandler`, which implements RP-Initiated Logout, may be configured as follows: +Also, you can configure `OidcClientInitiatedLogoutSuccessHandler`, which implements RP-Initiated Logout, as follows: ==== .Java @@ -1424,10 +1429,11 @@ public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter { } } -NOTE: `OidcClientInitiatedLogoutSuccessHandler` supports the `{baseUrl}` placeholder. -If used, the application's base URL, like `https://app.example.org`, will replace it at request time. ---- +NOTE: `OidcClientInitiatedLogoutSuccessHandler` supports the `{baseUrl}` placeholder. +If used, the application's base URL, such as `https://app.example.org`, replaces it at request time. + .Kotlin [source,kotlin,role="secondary"] ---- @@ -1458,7 +1464,7 @@ class OAuth2LoginSecurityConfig : WebSecurityConfigurerAdapter() { } } -NOTE: `OidcClientInitiatedLogoutSuccessHandler` supports the `{baseUrl}` placeholder. -If used, the application's base URL, like `https://app.example.org`, will replace it at request time. ---- +NOTE: `OidcClientInitiatedLogoutSuccessHandler` supports the `{baseUrl}` placeholder. +If used, the application's base URL, such as `https://app.example.org`, replaces it at request time. ==== diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/oauth2/oauth2-resourceserver.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/oauth2/oauth2-resourceserver.adoc index 5084b1d75bb..e284f1874d2 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/oauth2/oauth2-resourceserver.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/oauth2/oauth2-resourceserver.adoc @@ -1,9 +1,9 @@ -[[oauth2resourceserver]] +NML.[[oauth2resourceserver]] == OAuth 2.0 Resource Server :figures: images/servlet/oauth2 :icondir: images/icons -Spring Security supports protecting endpoints using two forms of OAuth 2.0 https://tools.ietf.org/html/rfc6750.html[Bearer Tokens]: +Spring Security supports protecting endpoints BY using two forms of OAuth 2.0 https://tools.ietf.org/html/rfc6750.html[Bearer Tokens]: * https://tools.ietf.org/html/rfc7519[JWT] * Opaque Tokens @@ -11,42 +11,37 @@ Spring Security supports protecting endpoints using two forms of OAuth 2.0 https This is handy in circumstances where an application has delegated its authority management to an https://tools.ietf.org/html/rfc6749[authorization server] (for example, Okta or Ping Identity). This authorization server can be consulted by resource servers to authorize requests. -This section provides details on how Spring Security provides support for OAuth 2.0 https://tools.ietf.org/html/rfc6750.html[Bearer Tokens]. +This section details how Spring Security provides support for OAuth 2.0 https://tools.ietf.org/html/rfc6750.html[Bearer Tokens]. -[NOTE] -==== -Working samples for both {gh-samples-url}/boot/oauth2resourceserver[JWTs] and {gh-samples-url}/boot/oauth2resourceserver-opaque[Opaque Tokens] are available in the {gh-samples-url}[Spring Security repository]. -==== +NOTE: Working samples for both {gh-samples-url}/boot/oauth2resourceserver[JWTs] and {gh-samples-url}/boot/oauth2resourceserver-opaque[Opaque Tokens] are available in the {gh-samples-url}[Spring Security repository]. -Let's take a look at how Bearer Token Authentication works within Spring Security. -First, we see that, like <>, the https://tools.ietf.org/html/rfc7235#section-4.1[WWW-Authenticate] header is sent back to an unauthenticated client. +Now we can consider how Bearer Token Authentication works within Spring Security. +First, we see that, as with <>, the https://tools.ietf.org/html/rfc7235#section-4.1[WWW-Authenticate] header is sent back to an unauthenticated client: .Sending WWW-Authenticate Header image::{figures}/bearerauthenticationentrypoint.png[] -The figure above builds off our <> diagram. +image:{icondir}/number_1.png[] First, a user makes an unauthenticated request to the `/private` resource for which the user is not authorized. -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 <> indicates that the unauthenticated request is _Denied_ by throwing an `AccessDeniedException`. -image:{icondir}/number_2.png[] Spring Security's <> indicates that the unauthenticated request is __Denied__ by throwing an `AccessDeniedException`. +image:{icondir}/number_3.png[] Since the user is not authenticated, <> initiates _Start Authentication_. +The configured <> is an instance of {security-api-url}org/springframework/security/oauth2/server/resource/authentication/BearerTokenAuthenticationEntryPoint.html[`BearerTokenAuthenticationEntryPoint`], which sends a `WWW-Authenticate` header. +The `RequestCache` is typically a `NullRequestCache` that does not save the request, since the client is capable of replaying the requests it originally requested. -image:{icondir}/number_3.png[] Since the user is not authenticated, <> initiates __Start Authentication__. -The configured <> is an instance of {security-api-url}org/springframework/security/oauth2/server/resource/authentication/BearerTokenAuthenticationEntryPoint.html[`BearerTokenAuthenticationEntryPoint`] which sends a WWW-Authenticate header. -The `RequestCache` is typically a `NullRequestCache` that does not save the request since the client is capable of replaying the requests it originally requested. +NOTE: The preceding figure builds off of our <> diagram. When a client receives the `WWW-Authenticate: Bearer` header, it knows it should retry with a bearer token. -Below is the flow for the bearer token being processed. +The following image shows the flow for the bearer token being processed: [[oauth2resourceserver-authentication-bearertokenauthenticationfilter]] .Authenticating Bearer Token image::{figures}/bearertokenauthenticationfilter.png[] -The figure builds off our <> diagram. - -image:{icondir}/number_1.png[] When the user submits their bearer token, the `BearerTokenAuthenticationFilter` creates a `BearerTokenAuthenticationToken` which is a type of <> by extracting the token from the `HttpServletRequest`. +image:{icondir}/number_1.png[] When the user submits their bearer token, the `BearerTokenAuthenticationFilter` creates a `BearerTokenAuthenticationToken`, which is a type of <>, by extracting the token from the `HttpServletRequest`. image:{icondir}/number_2.png[] Next, the `HttpServletRequest` is passed to the `AuthenticationManagerResolver`, which selects the `AuthenticationManager`. The `BearerTokenAuthenticationToken` is passed into the `AuthenticationManager` to be authenticated. -The details of what `AuthenticationManager` looks like depends on whether you're configured for <> or <>. +The details of what `AuthenticationManager` looks like depends on whether you configured for <> or an <>. image:{icondir}/number_3.png[] If authentication fails, then __Failure__ @@ -58,22 +53,27 @@ image:{icondir}/number_4.png[] If authentication is successful, then __Success__ * The <> is set on the <>. * The `BearerTokenAuthenticationFilter` invokes `FilterChain.doFilter(request,response)` to continue with the rest of the application logic. +NOTE: The preceding figure builds off our <> diagram. + [[oauth2resourceserver-jwt-minimaldependencies]] === Minimal Dependencies for JWT Most Resource Server support is collected into `spring-security-oauth2-resource-server`. -However, the support for decoding and verifying JWTs is in `spring-security-oauth2-jose`, meaning that both are necessary in order to have a working resource server that supports JWT-encoded Bearer Tokens. +However, the support for decoding and verifying JWTs is in `spring-security-oauth2-jose`, meaning that both are necessary to have a working resource server that supports JWT-encoded Bearer Tokens. [[oauth2resourceserver-jwt-minimalconfiguration]] === Minimal Configuration for JWTs When using https://spring.io/projects/spring-boot[Spring Boot], configuring an application as a resource server consists of two basic steps. -First, include the needed dependencies and second, indicate the location of the authorization server. + +. Include the needed dependencies. +. Indicate the location of the authorization server. ==== Specifying the Authorization Server -In a Spring Boot application, to specify which authorization server to use, simply do: +In a Spring Boot application, to specify which authorization server to use, you can use a YAML file similar to the following: +==== [source,yml] ---- spring: @@ -81,94 +81,93 @@ spring: oauth2: resourceserver: jwt: - issuer-uri: https://idp.example.com/issuer + issuer-uri: https://idp.example.com/issuer <1> ---- +<1> `https://idp.example.com/issuer` is the value contained in the `iss` claim for JWT tokens that the authorization server issues. +==== -Where `https://idp.example.com/issuer` is the value contained in the `iss` claim for JWT tokens that the authorization server will issue. -Resource Server will use this property to further self-configure, discover the authorization server's public keys, and subsequently validate incoming JWTs. +Resource Server uses this property to further self-configure, discover the authorization server's public keys, and, subsequently, validate incoming JWTs. -[NOTE] -To use the `issuer-uri` property, it must also be true that one of `https://idp.example.com/issuer/.well-known/openid-configuration`, `https://idp.example.com/.well-known/openid-configuration/issuer`, or `https://idp.example.com/.well-known/oauth-authorization-server/issuer` is a supported endpoint for the authorization server. +NOTE: To use the `issuer-uri` property, it must also be true that one of `https://idp.example.com/issuer/.well-known/openid-configuration`, `https://idp.example.com/.well-known/openid-configuration/issuer`, or `https://idp.example.com/.well-known/oauth-authorization-server/issuer` is a supported endpoint for the authorization server. This endpoint is referred to as a https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfig[Provider Configuration] endpoint or a https://tools.ietf.org/html/rfc8414#section-3[Authorization Server Metadata] endpoint. -And that's it! - ==== Startup Expectations -When this property and these dependencies are used, Resource Server will automatically configure itself to validate JWT-encoded Bearer Tokens. +When this property and these dependencies are used, Resource Server automatically configures itself to validate JWT-encoded Bearer Tokens. It achieves this through a deterministic startup process: -1. Query the Provider Configuration or Authorization Server Metadata endpoint for the `jwks_url` property -2. Query the `jwks_url` endpoint for supported algorithms -3. Configure the validation strategy to query `jwks_url` for valid public keys of the algorithms found -4. Configure the validation strategy to validate each JWTs `iss` claim against `https://idp.example.com`. +. Query the Provider Configuration or Authorization Server Metadata endpoint for the `jwks_url` property. +. Query the `jwks_url` endpoint for supported algorithms. +. Configure the validation strategy to query `jwks_url` for valid public keys of the algorithms found. +. Configure the validation strategy to validate each JWTs `iss` claim against `https://idp.example.com`. -A consequence of this process is that the authorization server must be up and receiving requests in order for Resource Server to successfully start up. +A consequence of this process is that the authorization server must be up and receiving requests for Resource Server to successfully start up. -[NOTE] -If the authorization server is down when Resource Server queries it (given appropriate timeouts), then startup will fail. +NOTE: If the authorization server is down when Resource Server queries it (given appropriate timeouts), startup fails. ==== Runtime Expectations -Once the application is started up, Resource Server will attempt to process any request containing an `Authorization: Bearer` header: +Once the application has started, Resource Server tries to process any request containing an `Authorization: Bearer` header: +==== [source,html] ---- GET / HTTP/1.1 Authorization: Bearer some-token-value # Resource Server will process this ---- +==== -So long as this scheme is indicated, Resource Server will attempt to process the request according to the Bearer Token specification. +So long as this scheme is indicated, Resource Server tries to process the request, according to the Bearer Token specification. -Given a well-formed JWT, Resource Server will: +Given a well-formed JWT, Resource Server: -1. Validate its signature against a public key obtained from the `jwks_url` endpoint during startup and matched against the JWT -2. Validate the JWT's `exp` and `nbf` timestamps and the JWT's `iss` claim, and -3. Map each scope to an authority with the prefix `SCOPE_`. +. Validates its signature against a public key obtained from the `jwks_url` endpoint during startup and matched against the JWT. +. Validates the JWT's `exp` and `nbf` timestamps and the JWT's `iss` claim. +. Maps each scope to an authority with the prefix `SCOPE_`. -[NOTE] -As the authorization server makes available new keys, Spring Security will automatically rotate the keys used to validate JWTs. +NOTE: As the authorization server makes available new keys, Spring Security automatically rotates the keys used to validate JWTs. The resulting `Authentication#getPrincipal`, by default, is a Spring Security `Jwt` object, and `Authentication#getName` maps to the JWT's `sub` property, if one is present. From here, consider jumping to: -* <> +* <> * <> * <> [[oauth2resourceserver-jwt-architecture]] === How JWT Authentication Works -Next, let's see the architectural components that Spring Security uses to support https://tools.ietf.org/html/rfc7519[JWT] Authentication in servlet-based applications, like the one we just saw. +Next, we consider the architectural components that Spring Security uses to support https://tools.ietf.org/html/rfc7519[JWT] Authentication in servlet-based applications, like the one we just saw. -{security-api-url}org/springframework/security/oauth2/server/resource/authentication/JwtAuthenticationProvider.html[`JwtAuthenticationProvider`] is an <> implementation that leverages a <> and <> to authenticate a JWT. +{security-api-url}org/springframework/security/oauth2/server/resource/authentication/JwtAuthenticationProvider.html[`JwtAuthenticationProvider`] is an <> implementation that uses a <> and <> to authenticate a JWT. -Let's take a look at how `JwtAuthenticationProvider` works within Spring Security. -The figure explains details of how the <> in figures from <> works. +Now we can examine how `JwtAuthenticationProvider` works within Spring Security. +The following figure details how the <> in other figures (from <>) works. .`JwtAuthenticationProvider` Usage image::{figures}/jwtauthenticationprovider.png[] -image:{icondir}/number_1.png[] The authentication `Filter` from <> passes a `BearerTokenAuthenticationToken` to the `AuthenticationManager` which is implemented by <>. +image:{icondir}/number_1.png[] The authentication `Filter` from <> passes a `BearerTokenAuthenticationToken` to the `AuthenticationManager`, which is implemented by <>. image:{icondir}/number_2.png[] The `ProviderManager` is configured to use an <> of type `JwtAuthenticationProvider`. [[oauth2resourceserver-jwt-architecture-jwtdecoder]] -image:{icondir}/number_3.png[] `JwtAuthenticationProvider` decodes, verifies, and validates the `Jwt` using a <>. +image:{icondir}/number_3.png[] `JwtAuthenticationProvider` decodes, verifies, and validates the `Jwt` by using a <>. [[oauth2resourceserver-jwt-architecture-jwtauthenticationconverter]] image:{icondir}/number_4.png[] `JwtAuthenticationProvider` then uses the <> to convert the `Jwt` into a `Collection` of granted authorities. image:{icondir}/number_5.png[] When authentication is successful, the <> that is returned is of type `JwtAuthenticationToken` and has a principal that is the `Jwt` returned by the configured `JwtDecoder`. -Ultimately, the returned `JwtAuthenticationToken` will be set on the <> by the authentication `Filter`. +Ultimately, the returned `JwtAuthenticationToken` is set on the <> by the authentication `Filter`. [[oauth2resourceserver-jwt-jwkseturi]] === Specifying the Authorization Server JWK Set Uri Directly -If the authorization server doesn't support any configuration endpoints, or if Resource Server must be able to start up independently from the authorization server, then the `jwk-set-uri` can be supplied as well: +If the authorization server does not support any configuration endpoints or if Resource Server must be able to start up independently from the authorization server, you can supply the `jwk-set-uri` as well: +==== [source,yaml] ---- spring: @@ -179,22 +178,21 @@ spring: issuer-uri: https://idp.example.com jwk-set-uri: https://idp.example.com/.well-known/jwks.json ---- +==== -[NOTE] -The JWK Set uri is not standardized, but can typically be found in the authorization server's documentation +NOTE: The JWK Set URI is not standardized, but you can typically find it in the authorization server's documentation. -Consequently, Resource Server will not ping the authorization server at startup. +Consequently, Resource Server does not ping the authorization server at startup. We still specify the `issuer-uri` so that Resource Server still validates the `iss` claim on incoming JWTs. -[NOTE] -This property can also be supplied directly on the <>. +NOTE: You can also supply this property directly on the <>. [[oauth2resourceserver-jwt-sansboot]] === Overriding or Replacing Boot Auto Configuration -There are two `@Bean` s that Spring Boot generates on Resource Server's behalf. +There are two `@Bean` instances that Spring Boot generates on Resource Server's behalf. -The first is a `WebSecurityConfigurerAdapter` that configures the app as a resource server. When including `spring-security-oauth2-jose`, this `WebSecurityConfigurerAdapter` looks like: +The first is a `WebSecurityConfigurerAdapter` that configures the application as a resource server. When you include `spring-security-oauth2-jose`, this `WebSecurityConfigurerAdapter` looks like: .Default JWT Configuration ==== @@ -226,7 +224,7 @@ fun configure(http: HttpSecurity) { ---- ==== -If the application doesn't expose a `WebSecurityConfigurerAdapter` bean, then Spring Boot will expose the above default one. +If the application does not expose a `WebSecurityConfigurerAdapter` bean, Spring Boot exposes the preceding default one. Replacing this is as simple as exposing the bean within the application: @@ -274,9 +272,9 @@ class MyCustomSecurityConfiguration : WebSecurityConfigurerAdapter() { ---- ==== -The above requires the scope of `message:read` for any URL that starts with `/messages/`. +The preceding exmaple requires the scope of `message:read` for any URL that starts with `/messages/`. -Methods on the `oauth2ResourceServer` DSL will also override or replace auto configuration. +Methods on the `oauth2ResourceServer` DSL also override or replace auto-configuration. [[oauth2resourceserver-jwt-decoder]] For example, the second `@Bean` Spring Boot creates is a `JwtDecoder`, which <>: @@ -302,16 +300,15 @@ fun jwtDecoder(): JwtDecoder { ---- ==== -[NOTE] -Calling `{security-api-url}org/springframework/security/oauth2/jwt/JwtDecoders.html#fromIssuerLocation-java.lang.String-[JwtDecoders#fromIssuerLocation]` is what invokes the Provider Configuration or Authorization Server Metadata endpoint in order to derive the JWK Set Uri. +NOTE: Calling `{security-api-url}org/springframework/security/oauth2/jwt/JwtDecoders.html#fromIssuerLocation-java.lang.String-[JwtDecoders#fromIssuerLocation]` invokes the Provider Configuration or Authorization Server Metadata endpoint, to derive the JWK Set URI. -If the application doesn't expose a `JwtDecoder` bean, then Spring Boot will expose the above default one. +If the application does not expose a `JwtDecoder` bean, Spring Boot exposes the earlier default one. -And its configuration can be overridden using `jwkSetUri()` or replaced using `decoder()`. +You can override its configuration by using `jwkSetUri()` or replaced using `decoder()`. -Or, if you're not using Spring Boot at all, then both of these components - the filter chain and a `JwtDecoder` can be specified in XML. +Alternatively, if you do not use Spring Boot at all, you can specify both of these components (the filter chain and a `JwtDecoder`) in XML. -The filter chain is specified like so: +The filter chain is specified as follows: .Default JWT Configuration ==== @@ -327,7 +324,7 @@ The filter chain is specified like so: ---- ==== -And the `JwtDecoder` like so: +The `JwtDecoder` is specified as follows: .JWT Decoder ==== @@ -345,7 +342,7 @@ And the `JwtDecoder` like so: [[oauth2resourceserver-jwt-jwkseturi-dsl]] ==== Using `jwkSetUri()` -An authorization server's JWK Set Uri can be configured <> or it can be supplied in the DSL: +You can configure an authorization server's JWK Set URI <>, or you can supply it in the DSL: .JWK Set Uri Configuration ==== @@ -405,7 +402,7 @@ Using `jwkSetUri()` takes precedence over any configuration property. [[oauth2resourceserver-jwt-decoder-dsl]] ==== Using `decoder()` -More powerful than `jwkSetUri()` is `decoder()`, which will completely replace any Boot auto configuration of <>: +More powerful than `jwkSetUri()` is `decoder()`, which completely replaces any Boot auto configuration of <>: .JWT Decoder Configuration ==== @@ -460,12 +457,12 @@ class DirectlyConfiguredJwtDecoder : WebSecurityConfigurerAdapter() { ---- ==== -This is handy when deeper configuration, like <>, <>, or <>, is necessary. +This is handy when deeper configuration (such as <>, <>, or <>) is necessary. [[oauth2resourceserver-jwt-decoder-bean]] ==== Exposing a `JwtDecoder` `@Bean` -Or, exposing a <> `@Bean` has the same effect as `decoder()`: +Alternatively, exposing a <> `@Bean` has the same effect as `decoder()`: ==== .Java @@ -490,15 +487,16 @@ fun jwtDecoder(): JwtDecoder { [[oauth2resourceserver-jwt-decoder-algorithm]] === Configuring Trusted Algorithms -By default, `NimbusJwtDecoder`, and hence Resource Server, will only trust and verify tokens using `RS256`. +By default, `NimbusJwtDecoder` and, hence, Resource Server, trust and verify tokens only that use `RS256`. -You can customize this via <>, <>, or from the <>. +You can customize this through <> or <> or from the <>. [[oauth2resourceserver-jwt-boot-algorithm]] ==== Via Spring Boot The simplest way to set the algorithm is as a property: +==== [source,yaml] ---- spring: @@ -509,6 +507,7 @@ spring: jws-algorithm: RS512 jwk-set-uri: https://idp.example.org/.well-known/jwks.json ---- +==== [[oauth2resourceserver-jwt-decoder-builder]] ==== Using a Builder @@ -537,7 +536,7 @@ fun jwtDecoder(): JwtDecoder { ---- ==== -Calling `jwsAlgorithm` more than once will configure `NimbusJwtDecoder` to trust more than one algorithm, like so: +Calling `jwsAlgorithm` more than once configures `NimbusJwtDecoder` to trust more than one algorithm, as follows: ==== .Java @@ -561,7 +560,7 @@ fun jwtDecoder(): JwtDecoder { ---- ==== -Or, you can call `jwsAlgorithms`: +Alternatively, you can call `jwsAlgorithms`: ==== .Java @@ -594,10 +593,10 @@ fun jwtDecoder(): JwtDecoder { [[oauth2resourceserver-jwt-decoder-jwk-response]] ==== From JWK Set response -Since Spring Security's JWT support is based off of Nimbus, you can use all it's great features as well. +Since Spring Security's JWT support is based off of Nimbus, you can use all its great features as well. -For example, Nimbus has a `JWSKeySelector` implementation that will select the set of algorithms based on the JWK Set URI response. -You can use it to generate a `NimbusJwtDecoder` like so: +For example, Nimbus has a `JWSKeySelector` implementation that selects the set of algorithms, based on the JWK Set URI response. +You can use it to generate a `NimbusJwtDecoder`, as follows: ==== .Java @@ -634,15 +633,16 @@ fun jwtDecoder(): JwtDecoder { [[oauth2resourceserver-jwt-decoder-public-key]] === Trusting a Single Asymmetric Key -Simpler than backing a Resource Server with a JWK Set endpoint is to hard-code an RSA public key. -The public key can be provided via <> or by <>. +Simpler than backing a Resource Server with a JWK Set endpoint is to hard code an RSA public key. +The public key can be provided through <> or by <>. [[oauth2resourceserver-jwt-decoder-public-key-boot]] -==== Via Spring Boot +==== Providing a Public Key through Spring Boot -Specifying a key via Spring Boot is quite simple. -The key's location can be specified like so: +With Spring Boot, +you can specify the key's location: +==== [source,yaml] ---- spring: @@ -652,8 +652,9 @@ spring: jwt: public-key-location: classpath:my-key.pub ---- +==== -Or, to allow for a more sophisticated lookup, you can post-process the `RsaKeyConversionServicePostProcessor`: +Alternatively, to allow for a more sophisticated lookup, you can post-process the `RsaKeyConversionServicePostProcessor`: ==== .Java @@ -680,13 +681,16 @@ fun conversionServiceCustomizer(): BeanFactoryPostProcessor { ---- ==== -Specify your key's location: +To specify your key's location: -```yaml +==== +[source,yaml] +---- key.location: hfds://my-key.pub -``` +---- +==== -And then autowire the value: +Then autowire the value: ==== .Java @@ -705,9 +709,9 @@ val key: RSAPublicKey? = null ==== [[oauth2resourceserver-jwt-decoder-public-key-builder]] -==== Using a Builder +==== Using a Builder to Provide a Public Key -To wire an `RSAPublicKey` directly, you can simply use the appropriate `NimbusJwtDecoder` builder, like so: +To wire an `RSAPublicKey` directly, you can use the appropriate `NimbusJwtDecoder` builder: ==== .Java @@ -732,8 +736,7 @@ fun jwtDecoder(): JwtDecoder { [[oauth2resourceserver-jwt-decoder-secret-key]] === Trusting a Single Symmetric Key -Using a single symmetric key is also simple. -You can simply load in your `SecretKey` and use the appropriate `NimbusJwtDecoder` builder, like so: +To use a single symmetric key, you can load in your `SecretKey` and use the appropriate `NimbusJwtDecoder` builder: ==== .Java @@ -758,13 +761,13 @@ fun jwtDecoder(): JwtDecoder { [[oauth2resourceserver-jwt-authorization]] === Configuring Authorization -A JWT that is issued from an OAuth 2.0 Authorization Server will typically either have a `scope` or `scp` attribute, indicating the scopes (or authorities) it's been granted, for example: +A JWT that is issued from an OAuth 2.0 Authorization Server typically have either a `scope` or an `scp` attribute, indicating the scopes (or authorities) it has been granted -- for example: `{ ..., "scope" : "messages contacts"}` -When this is the case, Resource Server will attempt to coerce these scopes into a list of granted authorities, prefixing each scope with the string "SCOPE_". +When this is the case, Resource Server tries to coerce these scopes into a list of granted authorities, prefixing each scope with the string, `SCOPE_`. -This means that to protect an endpoint or method with a scope derived from a JWT, the corresponding expressions should include this prefix: +This means that, to protect an endpoint or method with a scope derived from a JWT, the corresponding expressions should include this prefix: .Authorization Configuration ==== @@ -818,28 +821,30 @@ class DirectlyConfiguredJwkSetUri : WebSecurityConfigurerAdapter() { ---- ==== -Or similarly with method security: +A similar arrangement applies to method security: +==== [source,java] ---- @PreAuthorize("hasAuthority('SCOPE_messages')") public List getMessages(...) {} ---- +==== [[oauth2resourceserver-jwt-authorization-extraction]] ==== Extracting Authorities Manually However, there are a number of circumstances where this default is insufficient. -For example, some authorization servers don't use the `scope` attribute, but instead have their own custom attribute. -Or, at other times, the resource server may need to adapt the attribute or a composition of attributes into internalized authorities. +For example, some authorization servers do not use the `scope` attribute but, instead, have their own custom attribute. +At other times, the resource server may need to adapt the attribute or a composition of attributes into internalized authorities. To this end, Spring Security ships with `JwtAuthenticationConverter`, which is responsible for <>. -By default, Spring Security will wire the `JwtAuthenticationProvider` with a default instance of `JwtAuthenticationConverter`. +By default, Spring Security wires the `JwtAuthenticationProvider` with a default instance of `JwtAuthenticationConverter`. As part of configuring a `JwtAuthenticationConverter`, you can supply a subsidiary converter to go from `Jwt` to a `Collection` of granted authorities. -Let's say that that your authorization server communicates authorities in a custom claim called `authorities`. -In that case, you can configure the claim that <> should inspect, like so: +Suppose your authorization server communicates authorities in a custom claim called `authorities`. +In that case, you can configure the claim that <> should inspect: .Authorities Claim Configuration ==== @@ -896,7 +901,7 @@ fun jwtAuthenticationConverter(): JwtAuthenticationConverter { ==== You can also configure the authority prefix to be different as well. -Instead of prefixing each authority with `SCOPE_`, you can change it to `ROLE_` like so: +Instead of prefixing each authority with `SCOPE_`, you can change it to `ROLE_`: .Authorities Prefix Configuration ==== @@ -952,7 +957,7 @@ fun jwtAuthenticationConverter(): JwtAuthenticationConverter { ---- ==== -Or, you can remove the prefix altogether by calling `JwtGrantedAuthoritiesConverter#setAuthorityPrefix("")`. +Alternatively, you can remove the prefix altogether by calling `JwtGrantedAuthoritiesConverter#setAuthorityPrefix("")`. For more flexibility, the DSL supports entirely replacing the converter with any class that implements `Converter`: @@ -1016,7 +1021,7 @@ class CustomAuthenticationConverterConfig : WebSecurityConfigurerAdapter() { [[oauth2resourceserver-jwt-validation]] === Configuring Validation -Using <>, indicating the authorization server's issuer uri, Resource Server will default to verifying the `iss` claim as well as the `exp` and `nbf` timestamp claims. +Using <> and indicating the authorization server's issuer URI, Resource Server defaults to verifying the `iss` claim as well as the `exp` and `nbf` timestamp claims. In circumstances where validation needs to be customized, Resource Server ships with two standard validators and also accepts custom `OAuth2TokenValidator` instances. @@ -1025,10 +1030,10 @@ In circumstances where validation needs to be customized, Resource Server ships JWT's typically have a window of validity, with the start of the window indicated in the `nbf` claim and the end indicated in the `exp` claim. -However, every server can experience clock drift, which can cause tokens to appear expired to one server, but not to another. +However, every server can experience clock drift, which can cause tokens to appear to be expired to one server but not to another. This can cause some implementation heartburn as the number of collaborating servers increases in a distributed system. -Resource Server uses `JwtTimestampValidator` to verify a token's validity window, and it can be configured with a `clockSkew` to alleviate the above problem: +Resource Server uses `JwtTimestampValidator` to verify a token's validity window, and you can configure it with a `clockSkew` to alleviate the problem of clock drift: ==== .Java @@ -1073,7 +1078,7 @@ By default, Resource Server configures a clock skew of 60 seconds. [[oauth2resourceserver-jwt-validation-custom]] ==== Configuring a Custom Validator -Adding a check for the `aud` claim is simple with the `OAuth2TokenValidator` API: +You can use the `OAuth2TokenValidator` API to add a check for the `aud` claim: ==== .Java @@ -1093,7 +1098,7 @@ fun audienceValidator(): OAuth2TokenValidator { ---- ==== -Or, for more control you can implement your own `OAuth2TokenValidator`: +Alternatively, for more control, you can implement your own `OAuth2TokenValidator`: ==== .Java @@ -1142,7 +1147,7 @@ fun audienceValidator(): OAuth2TokenValidator { ---- ==== -Then, to add into a resource server, it's a matter of specifying the <> instance: +Then, to add into a resource server, you can specify the <> instance: ==== .Java @@ -1184,21 +1189,21 @@ fun jwtDecoder(): JwtDecoder { [[oauth2resourceserver-jwt-claimsetmapping]] === Configuring Claim Set Mapping -Spring Security uses the https://bitbucket.org/connect2id/nimbus-jose-jwt/wiki/Home[Nimbus] library for parsing JWTs and validating their signatures. +Spring Security uses the https://bitbucket.org/connect2id/nimbus-jose-jwt/wiki/Home[Nimbus] library to parse JWTs and validate their signatures. Consequently, Spring Security is subject to Nimbus's interpretation of each field value and how to coerce each into a Java type. -For example, because Nimbus remains Java 7 compatible, it doesn't use `Instant` to represent timestamp fields. +For example, because Nimbus remains Java 7 compatible, it does not use `Instant` to represent timestamp fields. -And it's entirely possible to use a different library or for JWT processing, which may make its own coercion decisions that need adjustment. +Also, it is entirely possible to use a different library or for JWT processing, which may make its own coercion decisions that need adjustment. -Or, quite simply, a resource server may want to add or remove claims from a JWT for domain-specific reasons. +Put differently, a resource server may want to add or remove claims from a JWT for domain-specific reasons. For these purposes, Resource Server supports mapping the JWT claim set with `MappedJwtClaimSetConverter`. [[oauth2resourceserver-jwt-claimsetmapping-singleclaim]] ==== Customizing the Conversion of a Single Claim -By default, `MappedJwtClaimSetConverter` will attempt to coerce claims into the following types: +By default, `MappedJwtClaimSetConverter` tries to coerce claims into the following types: |============ | Claim | Java Type @@ -1211,7 +1216,7 @@ By default, `MappedJwtClaimSetConverter` will attempt to coerce claims into the | `sub` | `String` |============ -An individual claim's conversion strategy can be configured using `MappedJwtClaimSetConverter.withDefaults`: +You can configure an individual claim's conversion strategy by using `MappedJwtClaimSetConverter.withDefaults`: ==== .Java @@ -1244,12 +1249,13 @@ fun jwtDecoder(): JwtDecoder { } ---- ==== -This will keep all the defaults, except it will override the default claim converter for `sub`. + +This approach keeps all the defaults, except that it overrides the default claim converter for `sub`. [[oauth2resourceserver-jwt-claimsetmapping-add]] ==== Adding a Claim -`MappedJwtClaimSetConverter` can also be used to add a custom claim, for example, to adapt to an existing system: +`MappedJwtClaimSetConverter` can also be used to add a custom claim -- for example, to adapt to an existing system: ==== .Java @@ -1268,7 +1274,7 @@ MappedJwtClaimSetConverter.withDefaults(mapOf("custom" to Converter [[oauth2resourceserver-jwt-claimsetmapping-remove]] ==== Removing a Claim -And removing a claim is also simple, using the same API: +And removing a claim is also simple, by using the same API: ==== .Java @@ -1323,7 +1329,7 @@ class UsernameSubClaimAdapter : Converter, Map> ---- ==== -And then, the instance can be supplied like normal: +Then you can supply the instance in the normal way: ==== .Java @@ -1355,7 +1361,7 @@ fun jwtDecoder(): JwtDecoder { By default, Resource Server uses connection and socket timeouts of 30 seconds each for coordinating with the authorization server. This may be too short in some scenarios. -Further, it doesn't take into account more sophisticated patterns like back-off and discovery. +Further, it does not take into account more sophisticated patterns like back-off and discovery. To adjust the way in which Resource Server connects to the authorization server, `NimbusJwtDecoder` accepts an instance of `RestOperations`: @@ -1389,8 +1395,8 @@ fun jwtDecoder(builder: RestTemplateBuilder): JwtDecoder { ---- ==== -Also by default, Resource Server caches in-memory the authorization server's JWK set for 5 minutes, which you may want to adjust. -Further, it doesn't take into account more sophisticated caching patterns like eviction or using a shared cache. +Also, by default, Resource Server caches (in memory) the authorization server's JWK set for 5 minutes, which you may want to adjust. +Further, it does not take into account more sophisticated caching patterns, such as eviction or using a shared cache. To adjust the way in which Resource Server caches the JWK set, `NimbusJwtDecoder` accepts an instance of `Cache`: @@ -1418,34 +1424,37 @@ fun jwtDecoder(cacheManager: CacheManager): JwtDecoder { ---- ==== -When given a `Cache`, Resource Server will use the JWK Set Uri as the key and the JWK Set JSON as the value. +When given a `Cache`, Resource Server uses the JWK Set URI as the key and the JWK Set JSON as the value. -NOTE: Spring isn't a cache provider, so you'll need to make sure to include the appropriate dependencies, like `spring-boot-starter-cache` and your favorite caching provider. +NOTE: Spring is not a cache provider, so you need to make sure to include the appropriate dependencies, such as `spring-boot-starter-cache` and your favorite caching provider. -NOTE: Whether it's socket or cache timeouts, you may instead want to work with Nimbus directly. +NOTE: Whether it is socket or cache timeouts, you may instead want to work with Nimbus directly. To do so, remember that `NimbusJwtDecoder` ships with a constructor that takes Nimbus's `JWTProcessor`. [[oauth2resourceserver-opaque-minimaldependencies]] === Minimal Dependencies for Introspection As described in <> most of Resource Server support is collected in `spring-security-oauth2-resource-server`. -However unless a custom <> is provided, the Resource Server will fallback to NimbusOpaqueTokenIntrospector. -Meaning that both `spring-security-oauth2-resource-server` and `oauth2-oidc-sdk` are necessary in order to have a working minimal Resource Server that supports opaque Bearer Tokens. -Please refer to `spring-security-oauth2-resource-server` in order to determin the correct version for `oauth2-oidc-sdk`. +However, unless a custom <> is provided, Resource Server falls back to NimbusOpaqueTokenIntrospector. +This means that both `spring-security-oauth2-resource-server` and `oauth2-oidc-sdk` are necessary to have a working minimal Resource Server that supports opaque Bearer Tokens. +See `spring-security-oauth2-resource-server` to determine the correct version for `oauth2-oidc-sdk`. [[oauth2resourceserver-opaque-minimalconfiguration]] === Minimal Configuration for Introspection -Typically, an opaque token can be verified via an https://tools.ietf.org/html/rfc7662[OAuth 2.0 Introspection Endpoint], hosted by the authorization server. +Typically, you can verify an opaque token through an https://tools.ietf.org/html/rfc7662[OAuth 2.0 Introspection Endpoint], hosted by the authorization server. This can be handy when revocation is a requirement. -When using https://spring.io/projects/spring-boot[Spring Boot], configuring an application as a resource server that uses introspection consists of two basic steps. -First, include the needed dependencies and second, indicate the introspection endpoint details. +When you use https://spring.io/projects/spring-boot[Spring Boot], configuring an application as a resource server that uses introspection consists of two basic steps: + +. Include the needed dependencies. +. Indicate the introspection endpoint details. [[oauth2resourceserver-opaque-introspectionuri]] ==== Specifying the Authorization Server -To specify where the introspection endpoint is, simply do: +The following exmaple specifies where the introspection endpoint is: +==== [source,yaml] ---- security: @@ -1456,39 +1465,40 @@ security: client-id: client client-secret: secret ---- +==== Where `https://idp.example.com/introspect` is the introspection endpoint hosted by your authorization server and `client-id` and `client-secret` are the credentials needed to hit that endpoint. -Resource Server will use these properties to further self-configure and subsequently validate incoming JWTs. - -[NOTE] -When using introspection, the authorization server's word is the law. -If the authorization server responses that the token is valid, then it is. +Resource Server uses these properties to further self-configure and subsequently validate incoming JWTs. -And that's it! +NOTE: When using introspection, the authorization server's word is law. +If the authorization server responsed that the token is valid, it is. ==== Startup Expectations -When this property and these dependencies are used, Resource Server will automatically configure itself to validate Opaque Bearer Tokens. +When this property and these dependencies are used, Resource Server automatically configures itself to validate Opaque Bearer Tokens. -This startup process is quite a bit simpler than for JWTs since no endpoints need to be discovered and no additional validation rules get added. +This startup process is quite a bit simpler than for JWTs, since no endpoints need to be discovered and no additional validation rules get added. ==== Runtime Expectations -Once the application is started up, Resource Server will attempt to process any request containing an `Authorization: Bearer` header: +Once the application has started, Resource Server tries to process any request containing an `Authorization: Bearer` header: -```http +==== +[source,text] +---- GET / HTTP/1.1 Authorization: Bearer some-token-value # Resource Server will process this -``` +---- +==== -So long as this scheme is indicated, Resource Server will attempt to process the request according to the Bearer Token specification. +So long as this scheme is indicated, Resource Server tries to process the request according to the Bearer Token specification. -Given an Opaque Token, Resource Server will +Given an Opaque Token, Resource Server: -1. Query the provided introspection endpoint using the provided credentials and the token -2. Inspect the response for an `{ 'active' : true }` attribute -3. Map each scope to an authority with the prefix `SCOPE_` +1. Queries the provided introspection endpoint by using the provided credentials and the token. +2. Inspects the response for an `{ 'active' : true }` attribute. +3. Maps each scope to an authority with a prefix of `SCOPE_`. The resulting `Authentication#getPrincipal`, by default, is a Spring Security `{security-api-url}org/springframework/security/oauth2/core/OAuth2AuthenticatedPrincipal.html[OAuth2AuthenticatedPrincipal]` object, and `Authentication#getName` maps to the token's `sub` property, if one is present. @@ -1502,12 +1512,12 @@ From here, you may want to jump to: [[oauth2resourceserver-opaque-architecture]] === How Opaque Token Authentication Works -Next, let's see the architectural components that Spring Security uses to support https://tools.ietf.org/html/rfc7662[opaque token] Authentication in servlet-based applications, like the one we just saw. +Next, let's see the architectural components that Spring Security uses to support https://tools.ietf.org/html/rfc7662[opaque token] authentication in servlet-based applications, such as the one we examined earlier in this chapter. {security-api-url}org/springframework/security/oauth2/server/resource/authentication/OpaqueTokenAuthenticationProvider.html[`OpaqueTokenAuthenticationProvider`] is an <> implementation that leverages a <> to authenticate an opaque token. -Let's take a look at how `OpaqueTokenAuthenticationProvider` works within Spring Security. -The figure explains details of how the <> in figures from <> works. +Now we examine how `OpaqueTokenAuthenticationProvider` works within Spring Security. +The figure details how the <> in figures from <> works. .`OpaqueTokenAuthenticationProvider` Usage image::{figures}/opaquetokenauthenticationprovider.png[] @@ -1517,16 +1527,16 @@ image:{icondir}/number_1.png[] The authentication `Filter` from <> of type `OpaqueTokenAuthenticationProvider`. [[oauth2resourceserver-opaque-architecture-introspector]] -image:{icondir}/number_3.png[] `OpaqueTokenAuthenticationProvider` introspects the opaque token and adds granted authorities using an <>. +image:{icondir}/number_3.png[] `OpaqueTokenAuthenticationProvider` introspects the opaque token and adds granted authorities by using an <>. When authentication is successful, the <> that is returned is of type `BearerTokenAuthentication` and has a principal that is the `OAuth2AuthenticatedPrincipal` returned by the configured <>. -Ultimately, the returned `BearerTokenAuthentication` will be set on the <> by the authentication `Filter`. +Ultimately, the returned `BearerTokenAuthentication` is set on the <> by the authentication `Filter`. [[oauth2resourceserver-opaque-attributes]] === Looking Up Attributes Post-Authentication Once a token is authenticated, an instance of `BearerTokenAuthentication` is set in the `SecurityContext`. -This means that it's available in `@Controller` methods when using `@EnableWebMvc` in your configuration: +This means that it is available in `@Controller` methods when you use `@EnableWebMvc` in your configuration: ==== .Java @@ -1548,7 +1558,7 @@ fun foo(authentication: BearerTokenAuthentication): String { ---- ==== -Since `BearerTokenAuthentication` holds an `OAuth2AuthenticatedPrincipal`, that also means that it's available to controller methods, too: +Since `BearerTokenAuthentication` holds an `OAuth2AuthenticatedPrincipal`, that also means that it is available to controller methods, too: ==== .Java @@ -1570,11 +1580,11 @@ fun foo(@AuthenticationPrincipal principal: OAuth2AuthenticatedPrincipal): Strin ---- ==== -==== Looking Up Attributes Via SpEL +==== Looking Up Attributes with SpEL -Of course, this also means that attributes can be accessed via SpEL. +Of course, this also means that attributes can be accessed with SpEL (Spring Expression Language). -For example, if using `@EnableGlobalMethodSecurity` so that you can use `@PreAuthorize` annotations, you can do: +For example, if you use `@EnableGlobalMethodSecurity` so that you can use `@PreAuthorize` annotations, you can use: ==== .Java @@ -1599,10 +1609,10 @@ fun forFoosEyesOnly(): String { [[oauth2resourceserver-opaque-sansboot]] === Overriding or Replacing Boot Auto Configuration -There are two `@Bean` s that Spring Boot generates on Resource Server's behalf. +There are two `@Bean` instances that Spring Boot generates on Resource Server's behalf. -The first is a `WebSecurityConfigurerAdapter` that configures the app as a resource server. -When use Opaque Token, this `WebSecurityConfigurerAdapter` looks like: +The first is a `WebSecurityConfigurerAdapter` that configures the application as a resource server. +When you use Opaque Token, this `WebSecurityConfigurerAdapter` looks like: .Default Opaque Token Configuration ==== @@ -1634,9 +1644,9 @@ override fun configure(http: HttpSecurity) { ---- ==== -If the application doesn't expose a `WebSecurityConfigurerAdapter` bean, then Spring Boot will expose the above default one. +If the application does not expose a `WebSecurityConfigurerAdapter` bean, Spring Boot exposes the preceding default one. -Replacing this is as simple as exposing the bean within the application: +Replacing this involves exposing the bean within the application: .Custom Opaque Token Configuration ==== @@ -1682,12 +1692,12 @@ class MyCustomSecurityConfiguration : WebSecurityConfigurerAdapter() { ---- ==== -The above requires the scope of `message:read` for any URL that starts with `/messages/`. +The preceding example requires the scope of `message:read` for any URL that starts with `/messages/`. -Methods on the `oauth2ResourceServer` DSL will also override or replace auto configuration. +Methods on the `oauth2ResourceServer` DSL also override or replace auto configuration. [[oauth2resourceserver-opaque-introspector]] -For example, the second `@Bean` Spring Boot creates is an `OpaqueTokenIntrospector`, <>: +For example, the second `@Bean` that Spring Boot creates is an `OpaqueTokenIntrospector`, <>: ==== .Java @@ -1709,11 +1719,11 @@ fun introspector(): OpaqueTokenIntrospector { ---- ==== -If the application doesn't expose a <> bean, then Spring Boot will expose the above default one. +If the application does not expose a <> bean, Spring Boot exposes the preceding default one. -And its configuration can be overridden using `introspectionUri()` and `introspectionClientCredentials()` or replaced using `introspector()`. +You can override its configuration by using `introspectionUri()` and `introspectionClientCredentials()` or replace it by using `introspector()`. -Or, if you're not using Spring Boot at all, then both of these components - the filter chain and a <> can be specified in XML. +Alternatively, if you do not use Spring Boot at all, you can specify both of these components (the filter chain and a <>) in XML. The filter chain is specified like so: @@ -1750,7 +1760,7 @@ And the <> or it can be supplied in the DSL: +You can configure an authorization server's introspection URI <> or supply it in the DSL: .Introspection URI Configuration ==== @@ -1812,7 +1822,7 @@ Using `introspectionUri()` takes precedence over any configuration property. [[oauth2resourceserver-opaque-introspector-dsl]] ==== Using `introspector()` -More powerful than `introspectionUri()` is `introspector()`, which will completely replace any Boot auto configuration of <>: +More powerful than `introspectionUri()` is `introspector()`, which completely replaces any Boot auto-configuration of <>: .Introspector Configuration ==== @@ -1867,13 +1877,14 @@ class DirectlyConfiguredIntrospector : WebSecurityConfigurerAdapter() { ---- ==== -This is handy when deeper configuration, like <>, <>, or <>, is necessary. +This is handy when deeper configuration (such as <>, <>, or <>) is necessary. [[oauth2resourceserver-opaque-introspector-bean]] ==== Exposing a `OpaqueTokenIntrospector` `@Bean` -Or, exposing a <> `@Bean` has the same effect as `introspector()`: +Alternatively, exposing an <> `@Bean` has the same effect as `introspector()`: +==== [source,java] ---- @Bean @@ -1881,17 +1892,18 @@ public OpaqueTokenIntrospector introspector() { return new NimbusOpaqueTokenIntrospector(introspectionUri, clientId, clientSecret); } ---- +==== [[oauth2resourceserver-opaque-authorization]] === Configuring Authorization -An OAuth 2.0 Introspection endpoint will typically return a `scope` attribute, indicating the scopes (or authorities) it's been granted, for example: +An OAuth 2.0 Introspection endpoint typically returns a `scope` attribute, indicating the scopes (or authorities) it has been granted -- for example: `{ ..., "scope" : "messages contacts"}` -When this is the case, Resource Server will attempt to coerce these scopes into a list of granted authorities, prefixing each scope with the string "SCOPE_". +When this is the case, Resource Server tries to coerce these scopes into a list of granted authorities, prefixing each scope with the string "SCOPE_". -This means that to protect an endpoint or method with a scope derived from an Opaque Token, the corresponding expressions should include this prefix: +This means that, to protect an endpoint or method with a scope derived from an Opaque Token, the corresponding expressions should include this prefix: .Authorization Opaque Token Configuration ==== @@ -1945,7 +1957,7 @@ class MappedAuthorities : WebSecurityConfigurerAdapter() { ---- ==== -Or similarly with method security: +Method security requires a similar approach: ==== .Java @@ -1966,10 +1978,11 @@ fun getMessages(): List {} [[oauth2resourceserver-opaque-authorization-extraction]] ==== Extracting Authorities Manually -By default, Opaque Token support will extract the scope claim from an introspection response and parse it into individual `GrantedAuthority` instances. +By default, Opaque Token support extracts the scope claim from an introspection response and parse it into individual `GrantedAuthority` instances. -For example, if the introspection response were: +For example, consider the following introspection response: +==== [source,json] ---- { @@ -1977,10 +1990,11 @@ For example, if the introspection response were: "scope" : "message:read message:write" } ---- +==== -Then Resource Server would generate an `Authentication` with two authorities, one for `message:read` and the other for `message:write`. +Given that response, Resource Server would generate an `Authentication` with two authorities, one for `message:read` and the other for `message:write`. -This can, of course, be customized using a custom <> that takes a look at the attribute set and converts in its own way: +You can customize this can be customized by using a custom <> that examines the attribute set and converts in its own way: ==== .Java @@ -2025,7 +2039,7 @@ class CustomAuthoritiesOpaqueTokenIntrospector : OpaqueTokenIntrospector { ---- ==== -Thereafter, this custom introspector can be configured simply by exposing it as a `@Bean`: +Thereafter, you can configure this custom introspector by exposing it as a `@Bean`: ==== .Java @@ -2050,10 +2064,10 @@ fun introspector(): OpaqueTokenIntrospector { [[oauth2resourceserver-opaque-timeouts]] === Configuring Timeouts -By default, Resource Server uses connection and socket timeouts of 30 seconds each for coordinating with the authorization server. +By default, Resource Server uses connection and socket timeouts of 30 seconds each to coordinate with the authorization server. -This may be too short in some scenarios. -Further, it doesn't take into account more sophisticated patterns like back-off and discovery. +In some scenarios this value may be too short. +Further, it does not take into account more sophisticated patterns, such as backing off and discovery. To adjust the way in which Resource Server connects to the authorization server, `NimbusOpaqueTokenIntrospector` accepts an instance of `RestOperations`: @@ -2092,12 +2106,13 @@ fun introspector(builder: RestTemplateBuilder, properties: OAuth2ResourceServerP === Using Introspection with JWTs A common question is whether or not introspection is compatible with JWTs. -Spring Security's Opaque Token support has been designed to not care about the format of the token -- it will gladly pass any token to the introspection endpoint provided. +Spring Security's Opaque Token support has been designed to not care about the format of the token -- it gladly passes any token to the provided introspection endpoint. -So, let's say that you've got a requirement that requires you to check with the authorization server on each request, in case the JWT has been revoked. +So, suppose you have a requirement to check with the authorization server on each request, in case the JWT has been revoked. -Even though you are using the JWT format for the token, your validation method is introspection, meaning you'd want to do: +Even though you use the JWT format for the token, your validation method is introspection, meaning that you want to do: +==== [source,yaml] ---- spring: @@ -2109,14 +2124,15 @@ spring: client-id: client client-secret: secret ---- +==== -In this case, the resulting `Authentication` would be `BearerTokenAuthentication`. +In this case, the resulting `Authentication` is `BearerTokenAuthentication`. Any attributes in the corresponding `OAuth2AuthenticatedPrincipal` would be whatever was returned by the introspection endpoint. -But, let's say that, oddly enough, the introspection endpoint only returns whether or not the token is active. +However, suppose that, oddly enough, the introspection endpoint returns only whether or not the token is active. Now what? -In this case, you can create a custom <> that still hits the endpoint, but then updates the returned principal to have the JWTs claims as the attributes: +In that case, you can create a custom <> that still hits the endpoint but then updates the returned principal to have the JWTs claims as the attributes: ==== .Java @@ -2171,7 +2187,7 @@ class JwtOpaqueTokenIntrospector : OpaqueTokenIntrospector { ---- ==== -Thereafter, this custom introspector can be configured simply by exposing it as a `@Bean`: +Thereafter, you can configure this custom introspector by exposing it as a `@Bean`: ==== .Java @@ -2196,12 +2212,12 @@ fun introspector(): OpaqueTokenIntrospector { [[oauth2resourceserver-opaque-userinfo]] === Calling a `/userinfo` Endpoint -Generally speaking, a Resource Server doesn't care about the underlying user, but instead about the authorities that have been granted. +Generally speaking, a Resource Server does not care about the underlying user but, instead, cares about the authorities that have been granted. -That said, at times it can be valuable to tie the authorization statement back to a user. +That said, at times, it can be valuable to tie the authorization statement back to a user. -If an application is also using `spring-security-oauth2-client`, having set up the appropriate `ClientRegistrationRepository`, then this is quite simple with a custom <>. -This implementation below does three things: +If an application also uses `spring-security-oauth2-client`, having set up the appropriate `ClientRegistrationRepository`, then this is possible with a custom <>. +The implementation shown in the next listing does three things: * Delegates to the introspection endpoint, to affirm the token's validity * Looks up the appropriate client registration associated with the `/userinfo` endpoint @@ -2256,8 +2272,8 @@ class UserInfoOpaqueTokenIntrospector : OpaqueTokenIntrospector { ---- ==== -If you aren't using `spring-security-oauth2-client`, it's still quite simple. -You will simply need to invoke the `/userinfo` with your own instance of `WebClient`: +If you do not use `spring-security-oauth2-client`, it is still possible. +You need to invoke the `/userinfo` with your own instance of `WebClient`: ==== .Java @@ -2316,10 +2332,10 @@ fun introspector(): OpaqueTokenIntrospector { [[oauth2reourceserver-opaqueandjwt]] === Supporting both JWT and Opaque Token -In some cases, you may have a need to access both kinds of tokens. -For example, you may support more than one tenant where one tenant issues JWTs and the other issues opaque tokens. +In some cases, you may need to access both kinds of tokens. +For example, you may support more than one tenant, where one tenant issues JWTs and the other issues opaque tokens. -If this decision must be made at request-time, then you can use an `AuthenticationManagerResolver` to achieve it, like so: +If this decision must be made at request-time, you can use an `AuthenticationManagerResolver` to achieve it: ==== .Java @@ -2361,9 +2377,9 @@ fun tokenAuthenticationManagerResolver(): AuthenticationManagerResolver A hypothetical source for tenant information. +<2> A cache for `JWKKeySelector`s, keyed by tenant identifier. +<3> Looking up the tenant is more secure than calculating the JWK Set endpoint on the fly -- the lookup acts as a list of allowed tenants. +<4> Create a `JWSKeySelector` through the types of keys that come back from the JWK Set endpoint -- the lazy lookup here means that you need not configure all tenants at startup. ==== -<1> A hypothetical source for tenant information -<2> A cache for `JWKKeySelector`s, keyed by tenant identifier -<3> Looking up the tenant is more secure than simply calculating the JWK Set endpoint on the fly - the lookup acts as a list of allowed tenants -<4> Create a `JWSKeySelector` via the types of keys that come back from the JWK Set endpoint - the lazy lookup here means that you don't need to configure all tenants at startup -The above key selector is a composition of many key selectors. +The preceding key selector is a composition of many key selectors. It chooses which key selector to use based on the `iss` claim in the JWT. NOTE: To use this approach, make sure that the authorization server is configured to include the claim set as part of the token's signature. -Without this, you have no guarantee that the issuer hasn't been altered by a bad actor. +Without this, you have no guarantee that the issuer has not been altered by a bad actor. Next, we can construct a `JWTProcessor`: @@ -2661,8 +2677,8 @@ fun jwtProcessor(keySelector: JWTClaimsSetAwareJWSKeySelector): As you are already seeing, the trade-off for moving tenant-awareness down to this level is more configuration. We have just a bit more. -Next, we still want to make sure you are validating the issuer. -But, since the issuer may be different per JWT, then you'll need a tenant-aware validator, too: +Next, we still want to make sure you validate the issuer. +However, since the issuer may differ per JWT, you need a tenant-aware validator, too: ==== .Java @@ -2755,10 +2771,10 @@ fun jwtDecoder(jwtProcessor: JWTProcessor?, jwtValidator: OAuth ---- ==== -We've finished talking about resolving the tenant. +We have finished talking about resolving the tenant. -If you've chosen to resolve the tenant by something other than a JWT claim, then you'll need to make sure you address your downstream resource servers in the same way. -For example, if you are resolving it by subdomain, you may need to address the downstream resource server using the same subdomain. +If you chose to resolve the tenant by something other than a JWT claim, you need to make sure you address your downstream resource servers in the same way. +For example, if you resolve it by subdomain, you may need to address the downstream resource server by using the same subdomain. However, if you resolve it by a claim in the bearer token, read on to learn about <>. @@ -2766,12 +2782,12 @@ However, if you resolve it by a claim in the bearer token, read on to learn abou === Bearer Token Resolution By default, Resource Server looks for a bearer token in the `Authorization` header. -This, however, can be customized in a handful of ways. +However, you can customize this in a handful of ways. ==== Reading the Bearer Token from a Custom Header -For example, you may have a need to read the bearer token from a custom header. -To achieve this, you can expose a `DefaultBearerTokenResolver` as a bean, or wire an instance into the DSL, as you can see in the following example: +For example, you may need to read the bearer token from a custom header. +To do so, you can expose a `DefaultBearerTokenResolver` as a bean or wire an instance into the DSL, as follows: .Custom Bearer Token Header ==== @@ -2811,11 +2827,11 @@ fun bearerTokenResolver(): BearerTokenResolver { ---- ==== -Or, in circumstances where a provider is using both a custom header and value, you can use `HeaderBearerTokenResolver` instead. +Alternatively, in circumstances where a provider uses both a custom header and value, you can use `HeaderBearerTokenResolver` instead. ==== Reading the Bearer Token from a Form Parameter -Or, you may wish to read the token from a form parameter, which you can do by configuring the `DefaultBearerTokenResolver`, as you can see below: +Alternatively, you may wish to read the token from a form parameter, which you can do by configuring the `DefaultBearerTokenResolver`: .Form Parameter Bearer Token ==== @@ -2858,8 +2874,8 @@ http { === Bearer Token Propagation -Now that you're resource server has validated the token, it might be handy to pass it to downstream services. -This is quite simple with `{security-api-url}org/springframework/security/oauth2/server/resource/web/reactive/function/client/ServletBearerExchangeFilterFunction.html[ServletBearerExchangeFilterFunction]`, which you can see in the following example: +Now that your resource server has validated the token, it might be handy to pass it to downstream services. +This is possible with {security-api-url}org/springframework/security/oauth2/server/resource/web/reactive/function/client/ServletBearerExchangeFilterFunction.html[`ServletBearerExchangeFilterFunction`]: ==== .Java @@ -2885,10 +2901,8 @@ fun rest(): WebClient { ---- ==== -When the above `WebClient` is used to perform requests, Spring Security will look up the current `Authentication` and extract any `{security-api-url}org/springframework/security/oauth2/core/AbstractOAuth2Token.html[AbstractOAuth2Token]` credential. -Then, it will propagate that token in the `Authorization` header. - -For example: +When the `WebClient` performs requests, Spring Security looks up the current `Authentication` and extracts any `{security-api-url}org/springframework/security/oauth2/core/AbstractOAuth2Token.html[`AbstractOAuth2Token`]` credential. +Then it propagates that token in the `Authorization` header: ==== .Java @@ -2912,9 +2926,9 @@ this.rest.get() ---- ==== -Will invoke the `https://other-service.example.com/endpoint`, adding the bearer token `Authorization` header for you. +The preceding code invokes the `https://other-service.example.com/endpoint`, adding the bearer token `Authorization` header for you. -In places where you need to override this behavior, it's a simple matter of supplying the header yourself, like so: +In places where you need to override this behavior, you can supply the header yourself: ==== .Java @@ -2940,15 +2954,14 @@ this.rest.get() ---- ==== -In this case, the filter will fall back and simply forward the request onto the rest of the web filter chain. +In this case, the filter falls back and forwards the request onto the rest of the web filter chain. -[NOTE] -Unlike the {security-api-url}org/springframework/security/oauth2/client/web/reactive/function/client/ServletOAuth2AuthorizedClientExchangeFilterFunction.html[OAuth 2.0 Client filter function], this filter function makes no attempt to renew the token, should it be expired. -To obtain this level of support, please use the OAuth 2.0 Client filter. +NOTE: Unlike the {security-api-url}org/springframework/security/oauth2/client/web/reactive/function/client/ServletOAuth2AuthorizedClientExchangeFilterFunction.html[OAuth 2.0 Client filter function], this filter function makes no attempt to renew the token, should it be expired. +To obtain this level of support, use the OAuth 2.0 Client filter. ==== `RestTemplate` support -There is no `RestTemplate` equivalent for `ServletBearerExchangeFilterFunction` at the moment, but you can propagate the request's bearer token quite simply with your own interceptor: +There is no `RestTemplate` equivalent for `ServletBearerExchangeFilterFunction` at the moment, but you can propagate the request's bearer token with your own interceptor: ==== .Java @@ -3001,25 +3014,26 @@ fun rest(): RestTemplate { ==== -[NOTE] -Unlike the {security-api-url}org/springframework/security/oauth2/client/OAuth2AuthorizedClientManager.html[OAuth 2.0 Authorized Client Manager], this filter interceptor makes no attempt to renew the token, should it be expired. -To obtain this level of support, please create an interceptor using the <>. +NOTE: Unlike the {security-api-url}org/springframework/security/oauth2/client/OAuth2AuthorizedClientManager.html[OAuth 2.0 Authorized Client Manager], this filter interceptor makes no attempt to renew the token, should it be expired. +To obtain this level of support, create an interceptor by using the <>. [[oauth2resourceserver-bearertoken-failure]] === Bearer Token Failure -A bearer token may be invalid for a number of reasons. For example, the token may no longer be active. +A bearer token can be invalid for a number of reasons. For example, the token may no longer be active. In these circumstances, Resource Server throws an `InvalidBearerTokenException`. Like other exceptions, this results in an OAuth 2.0 Bearer Token error response: -[source,http request] +==== +[source,text] ---- HTTP/1.1 401 Unauthorized WWW-Authenticate: Bearer error_code="invalid_token", error_description="Unsupported algorithm of none", error_uri="https://tools.ietf.org/html/rfc6750#section-3.1" ---- +==== -Additionally, it is published as an `AuthenticationFailureBadCredentialsEvent`, which you can <> like so: +Additionally, it is published as an `AuthenticationFailureBadCredentialsEvent`, for which you can <>: ==== .Java diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/saml2/index.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/saml2/index.adoc index e872f5d9d82..b1eccd41123 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/saml2/index.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/saml2/index.adoc @@ -1,4 +1,7 @@ [[servlet-saml2]] -= SAML2 += SAML 2.0 + +This section discusses how Spring Security works with Security Assertion Markup Language 2.0. +The https://en.wikipedia.org/wiki/SAML_2.0[Wikipedia article about SAML 2.0] provides some general background include::saml2-login.adoc[] diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/saml2/saml2-login.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/saml2/saml2-login.adoc index 27d55ebef6a..11ed3058b90 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/saml2/saml2-login.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/saml2/saml2-login.adoc @@ -1,10 +1,9 @@ - [[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). +The SAML 2.0 Login feature provides an application with the ability 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, and others). 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]. @@ -14,55 +13,54 @@ Since 2009, support for relying parties has existed as an https://github.com/spr 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 <>. -[NOTE] -==== -A working sample for {gh-samples-url}/boot/saml2login[SAML 2.0 Login] is available in the {gh-samples-url}[Spring Security repository]. -==== +NOTE: A working sample for {gh-samples-url}/boot/saml2login[SAML 2.0 Login] is available in the {gh-samples-url}[Spring Security repository]. -Let's take a look at how SAML 2.0 Relying Party Authentication works within Spring Security. -First, we see that, like <>, Spring Security takes the user to a third-party for performing authentication. -It does this through a series of redirects. +We start by examining how SAML 2.0 Relying Party Authentication works within Spring Security. +First, we see that, like <>, 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 <> and <> diagrams: +NOTE: The preceding figure above builds off our <> and <> 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_1.png[] First, a user makes an unauthenticated request to the `/private` resource, for which it is not authorized. -image:{icondir}/number_2.png[] Spring Security's <> indicates that the unauthenticated request is __Denied__ by throwing an `AccessDeniedException`. +image:{icondir}/number_2.png[] Spring Security's <> indicates that the unauthenticated request is _Denied_ by throwing an `AccessDeniedException`. -image:{icondir}/number_3.png[] Since the user lacks authorization, the <> initiates __Start Authentication__. -The configured <> is an instance of {security-api-url}org/springframework/security/web/authentication/LoginUrlAuthenticationEntryPoint.html[`LoginUrlAuthenticationEntryPoint`] which redirects to <` generating endpoint>>, `Saml2WebSsoAuthenticationRequestFilter`. -Or, if you've <>, it will first redirect to a picker page. +image:{icondir}/number_3.png[] Since the user lacks authorization, the <> initiates _Start Authentication_. +The configured <> is an instance of {security-api-url}org/springframework/security/web/authentication/LoginUrlAuthenticationEntryPoint.html[`LoginUrlAuthenticationEntryPoint`], which redirects to <` generating endpoint>>, `Saml2WebSsoAuthenticationRequestFilter`. +Alternatively, if you have <>, it first redirects to a picker page. -image:{icondir}/number_4.png[] Next, the `Saml2WebSsoAuthenticationRequestFilter` creates, signs, serializes, and encodes a `` using its configured <>. +image:{icondir}/number_4.png[] Next, the `Saml2WebSsoAuthenticationRequestFilter` creates, signs, serializes, and encodes a `` by using its configured <>. -image:{icondir}/number_5.png[] Then, the browser takes this `` and presents it to the asserting party. -The asserting party attempts to authentication the user. -If successful, it will return a `` back to the browser. +image:{icondir}/number_5.png[] Then the browser takes this `` and presents it to the asserting party. +The asserting party tries to authentication the user. +If successful, it returns a `` back to the browser. image:{icondir}/number_6.png[] The browser then POSTs the `` to the assertion consumer service endpoint. +The following image shows how Spring Security authenticates a ``. + [[servlet-saml2login-authentication-saml2webssoauthenticationfilter]] .Authenticating a `` image::{figures}/saml2webssoauthenticationfilter.png[] -The figure builds off our <> diagram. +NOTE: The figure builds off our <> diagram. image:{icondir}/number_1.png[] When the browser submits a `` to the application, it <>. This filter calls its configured `AuthenticationConverter` to create a `Saml2AuthenticationToken` by extracting the response from the `HttpServletRequest`. This converter additionally resolves the <> and supplies it to `Saml2AuthenticationToken`. image:{icondir}/number_2.png[] Next, the filter passes the token to its configured <>. -By default, it will use the <>. +By default, it uses the <>. -image:{icondir}/number_3.png[] If authentication fails, then __Failure__ +image:{icondir}/number_3.png[] If authentication fails, then _Failure_. * The <> is cleared out. * The <> is invoked to restart the authentication process. -image:{icondir}/number_4.png[] If authentication is successful, then __Success__. +image:{icondir}/number_4.png[] If authentication is successful, then _Success_. * The <> is set on the <>. * The `Saml2WebSsoAuthenticationFilter` invokes `FilterChain#doFilter(request,response)` to continue with the rest of the application logic. @@ -76,16 +74,19 @@ 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. +When using https://spring.io/projects/spring-boot[Spring Boot], configuring an application as a service provider consists of two basic steps: +. Include the needed dependencies. +. Indicate the necessary asserting party metadata. [NOTE] -Also, this presupposes that you've already <>. +Also, this configuration presupposes that you have already <>. +[[saml2-specifying-identity-provider-metadata]] ==== Specifying Identity Provider Metadata -In a Spring Boot application, to specify an identity provider's metadata, simply do: +In a Spring Boot application, to specify an identity provider's metadata, create configuration similar to the following: +==== [source,yml] ---- spring: @@ -101,63 +102,63 @@ spring: 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. +where: -And that's it! +* `https://idp.example.com/issuer` is the value contained in the `Issuer` attribute of the SAML responses that the identity provider issues. +* `classpath:idp.crt` is the location on the classpath for the identity provider's certificate for verifying SAML responses. +* `https://idp.example.com/issuer/sso` is the endpoint where the identity provider is expecting `AuthnRequest` instances. -[NOTE] -Identity Provider and Asserting Party are synonymous, as are Service Provider and Relying Party. +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: +As configured <>, the application processes any `+POST /login/saml2/sso/{registrationId}+` request containing a `SAMLResponse` parameter: -[source,html] +==== +[source,text] ---- POST /login/saml2/sso/adfs HTTP/1.1 SAMLResponse=PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZ... ---- +==== -There are two ways to see induce your asserting party to generate a `SAMLResponse`: +There are two ways to induce your asserting party to generate a `SAMLResponse`: -* First, you can navigate to your asserting party. +* 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`. +* You can navigate to a protected page in your application -- for example, `http://localhost:8080`. +Your application 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 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. +* 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. +* Ensure that 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. +This makes it possible for you to switch out OpenSAML for some other library or 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 `OpenSamlAuthenticationRequestFactory` and `OpenSamlAuthenticationProvider` expose `Converter` s that customize various steps in the authentication process. +As a natural outcome of these two goals, Spring Security's SAML API is quite small relative to other modules. +Instead, such classes as `OpenSamlAuthenticationRequestFactory` and `OpenSamlAuthenticationProvider` expose `Converter` implementationss 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 `OpenSamlAuthenticationProvider`. +For example, once your application receives a `SAMLResponse` and delegates to `Saml2WebSsoAuthenticationFilter`, the filter delegates to `OpenSamlAuthenticationProvider`: .Authenticating an OpenSAML `Response` image:{figures}/opensamlauthenticationprovider.png[] -This figure builds off of the <>. +NOTE: This figure builds off of the <>. image:{icondir}/number_1.png[] The `Saml2WebSsoAuthenticationFilter` formulates the `Saml2AuthenticationToken` and invokes the <>. @@ -166,18 +167,18 @@ image:{icondir}/number_2.png[] The <>. +image:{icondir}/number_4.png[] Then the provider <>. 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. +If they do not 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 <>. +image:{icondir}/number_7.png[] Then the provider <>. If any decryptions fail, authentication fails. image:{icondir}/number_8.png[] Next, the provider validates each assertion's `ExpiresAt` and `NotBefore` timestamps, the `` and any `` conditions. @@ -186,22 +187,24 @@ 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>`. 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`. +image:{icondir}/number_10.png[] 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: +Any class that uses both Spring Security and OpenSAML should statically initialize `OpenSamlInitializationService` at the beginning of the class: +==== [source,java] ---- static { OpenSamlInitializationService.initialize(); } ---- +==== This replaces OpenSAML's `InitializationService#initialize`. @@ -237,14 +240,14 @@ static { } ---- -The `requireInitialize` method may only be called once per application instance. +The `requireInitialize` method may be called only 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. +Spring Boot generates two `@Bean` objects for a relying party. -The first is a `WebSecurityConfigurerAdapter` that configures the app as a relying party. +The first is a `WebSecurityConfigurerAdapter` that configures the application as a relying party. When including `spring-security-saml2-service-provider`, the `WebSecurityConfigurerAdapter` looks like: .Default JWT Configuration @@ -275,7 +278,7 @@ fun configure(http: HttpSecurity) { ---- ==== -If the application doesn't expose a `WebSecurityConfigurerAdapter` bean, then Spring Boot will expose the above default one. +If the application does not expose a `WebSecurityConfigurerAdapter` bean, Spring Boot exposes the preceding default one. You can replace this by exposing the bean within the application: @@ -316,14 +319,14 @@ class MyCustomSecurityConfiguration : WebSecurityConfigurerAdapter() { ---- ==== -The above requires the role of `USER` for any URL that starts with `/messages/`. +The preceding example 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. +This includes such things as 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: +For example, you can look up the asserting party's configuration by hitting its metadata endpoint: .Relying Party Registration Repository ==== @@ -343,7 +346,7 @@ public RelyingPartyRegistrationRepository relyingPartyRegistrations() { ---- ==== -Or you can provide each detail manually, as you can see below: +Alternatively, you can provide each detail manually: .Relying Party Registration Repository Manual Configuration ==== @@ -370,12 +373,10 @@ public RelyingPartyRegistrationRepository relyingPartyRegistrations() throws Exc ---- ==== -[NOTE] -Note that `X509Support` is an OpenSAML class, used here in the snippet for brevity +NOTE: `X509Support` is an OpenSAML class, used in the preceding 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`: +Alternatively, you can directly wire up the repository by using the DSL, which also overrides the auto-configured `WebSecurityConfigurerAdapter`: .Custom Relying Party Registration DSL ==== @@ -417,20 +418,20 @@ class MyCustomSecurityConfiguration : WebSecurityConfigurerAdapter() { ---- ==== -[NOTE] -A relying party can be multi-tenant by registering more than one relying party in the `RelyingPartyRegistrationRepository`. +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. +instance represents a link between an relying party and an asserting 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. +In a `RelyingPartyRegistration`, you can provide relying party metadata, such as its `Issuer` value, where it expects SAML Responses to be sent, 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. +Also, you can provide asserting party metadata such as its `Issuer` value, where it expects AuthnRequests to be sent, 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: +==== [source,java] ---- RelyingPartyRegistration relyingPartyRegistration = RelyingPartyRegistrations @@ -438,9 +439,11 @@ RelyingPartyRegistration relyingPartyRegistration = RelyingPartyRegistrations .registrationId("my-id") .build(); ---- +==== -Though a more sophisticated setup is also possible, like so: +A more sophisticated setup is also possible: +==== [source,java] ---- RelyingPartyRegistration relyingPartyRegistration = RelyingPartyRegistration.withRegistrationId("my-id") @@ -453,26 +456,25 @@ RelyingPartyRegistration relyingPartyRegistration = RelyingPartyRegistration.wit .singleSignOnServiceLocation("https://ap.example.org/SSO.saml2") ); ---- +==== -[TIP] -The top-level metadata methods are details about the relying party. +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. +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. +You need this value when you configure 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 <> in the filter chain. +By default, it is mapped to <> in the filter chain. [[servlet-saml2login-rpr-uripatterns]] ==== URI Patterns -You probably noticed in the above examples the `+{baseUrl}+` and `+{registrationId}+` placeholders. +You probably noticed the `+{baseUrl}+` and `+{registrationId}+` placeholders in the preceding examples. -These are useful for generating URIs. As such, the relying party's `entityId` and `assertionConsumerServiceLocation` support the following placeholders: +These are useful for generating URIs. As a result, 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 @@ -480,37 +482,38 @@ These are useful for generating URIs. As such, the relying party's `entityId` an * `baseHost` - the host of a deployed application * `basePort` - the port of a deployed application -For example, the `assertionConsumerServiceLocation` defined above was: +For example, the `assertionConsumerServiceLocation` defined earlier was: `+/my-login-endpoint/{registrationId}+` -which in a deployed application would translate to +In a deployed application, it translates to: `+/my-login-endpoint/adfs+` -The `entityId` above was defined as: +The `entityId` shown earlier was defined as: `+{baseUrl}/{registrationId}+` -which in a deployed application would translate to +In a deployed application, that translates to: `+https://rp.example.com/adfs+` [[servlet-saml2login-rpr-credentials]] ==== Credentials -You also likely noticed the credential that was used. +In the example shown <>, 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. +Oftentimes, a relying party uses the same key to sign payloads as well as decrypt them. +Alternatively, it can 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. +At a minimum, you need 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: +To construct a `Saml2X509Credential` that you can use to verify assertions from the asserting party, you can load the file and use +the `CertificateFactory`: +==== [source,java] ---- Resource resource = new ClassPathResource("ap.crt"); @@ -520,13 +523,15 @@ try (InputStream is = resource.getInputStream()) { return Saml2X509Credential.verification(certificate); } ---- +==== -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. +Suppose that the asserting party is going to also encrypt the assertion. +In that case, the relying party needs a private key 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: +In that case, you need an `RSAPrivateKey` as well as its corresponding `X509Certificate`. +You can load the first by using Spring Security's `RsaKeyConverters` utility class and the second as you did before: +==== [source,java] ---- X509Certificate certificate = relyingPartyDecryptionCertificate(); @@ -536,25 +541,26 @@ try (InputStream is = resource.getInputStream()) { 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. +TIP: When you specify the locations of these files as the appropriate Spring Boot properties, Spring Boot performs 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. +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 want to customize for a number of reasons, including: -* 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 +* You may know that your application is never going to be a multi-tenant application and, as a result, want 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`. -The default looks up the registration id from the URI's last path element and looks it up in your `RelyingPartyRegistrationRepository`. +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: +==== [source,java] ---- public class SingleRelyingPartyRegistrationResolver @@ -566,11 +572,11 @@ public class SingleRelyingPartyRegistrationResolver } } ---- +==== -Then, you can provide this resolver to the appropriate filters that <` s>>, <` s>>, and <` metadata>>. +Then you can provide this resolver to the appropriate filters that <` instances>>, <` instances>>, and <` metadata>>. -[NOTE] -Remember that if you have any placeholders in your `RelyingPartyRegistration`, your resolver implementation should resolve them. +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 @@ -578,15 +584,16 @@ Remember that if you have any placeholders in your `RelyingPartyRegistration`, y 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 +* Its `assertionConsumerServiceLocation` +* 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. +This setup may let credentials be more easily rotated for some identity providers versus others. The duplication can be alleviated in a few different ways. -First, in YAML this can be alleviated with references, like so: +First, in YAML this can be alleviated with references: +==== [source,yaml] ---- spring: @@ -604,11 +611,13 @@ spring: identityprovider: entity-id: ... ---- +==== -Second, in a database, it's not necessary to replicate `RelyingPartyRegistration` 's model. +Second, in a database, you need not replicate the model of `RelyingPartyRegistration`. -Third, in Java, you can create a custom configuration method, like so: +Third, in Java, you can create a custom configuration method: +==== [source,java] ---- private RelyingPartyRegistration.Builder @@ -634,29 +643,29 @@ public RelyingPartyRegistrationRepository relyingPartyRegistrations() { return new InMemoryRelyingPartyRegistrationRepository(okta, azure); } ---- +==== [[servlet-saml2login-sp-initiated-factory]] -=== Producing `` s +=== Producing `` Instances -As stated earlier, Spring Security's SAML 2.0 support produces a `` to commence authentication with the asserting party. +As stated earlier, Spring Security's SAML 2.0 support produces a `` to start 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}+`. +Spring Security achieves this, in part, by registering the `Saml2WebSsoAuthenticationRequestFilter` in the filter chain. +By default, this filter responds to the `+/saml2/authenticate/{registrationId}+` endpoint. -For example, if you were deployed to `https://rp.example.com` and you gave your registration an ID of `okta`, you could navigate to: +For example, if you were deployed to `https://rp.example.com` and 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 ``. +The result should be a redirect that includes a `SAMLRequest` parameter containing the signed, deflated, and encoded ``. [[servlet-saml2login-sp-initiated-factory-signing]] ==== Changing How the `` Gets Sent -By default, Spring Security signs each `` and send it as a GET to the asserting party. - -Many asserting parties don't require a signed ``. -This can be configured automatically via `RelyingPartyRegistrations`, or you can supply it manually, like so: +By default, Spring Security signs each `` and sends it as a `GET` to the asserting party. +Many asserting parties do not require a signed ``. +This can be configured automatically by `RelyingPartyRegistrations`, or you can supply it manually: .Not Requiring Signed AuthnRequests ==== @@ -685,15 +694,16 @@ RelyingPartyRegistration relyingPartyRegistration = RelyingPartyRegistration.wit ---- ==== -Otherwise, you will need to specify a private key to `RelyingPartyRegistration#signingX509Credentials` so that Spring Security can sign the `` before sending. +Otherwise, you need to specify a private key to `RelyingPartyRegistration#signingX509Credentials` so that Spring Security can sign the `` before sending. [[servlet-saml2login-sp-initiated-factory-algorithm]] -By default, Spring Security will sign the `` using `rsa-sha256`, though some asserting parties will require a different algorithm, as indicated in their metadata. +By default, Spring Security signs the `` by using `rsa-sha256`, though some asserting parties require a different algorithm, as indicated in their metadata. -You can configure the algorithm based on the asserting party's <>. +You can configure the algorithm based on the asserting party's <>. -Or, you can provide it manually: +Alternatively, you can provide it manually: +==== [source,java] ---- String metadataLocation = "classpath:asserting-party-metadata.xml"; @@ -704,15 +714,17 @@ RelyingPartyRegistration relyingPartyRegistration = RelyingPartyRegistrations.fr .signingAlgorithms((sign) -> sign.add(SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA512)) ); ---- +==== -NOTE: The snippet above uses the OpenSAML `SignatureConstants` class to supply the algorithm name. -But, that's just for convenience. +NOTE: The preceding snippet uses the OpenSAML `SignatureConstants` class to supply the algorithm name. +However, that is only 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 `` be POSTed. -This can be configured automatically via `RelyingPartyRegistrations`, or you can supply it manually, like so: +This can be configured automatically through `RelyingPartyRegistrations`, or you can supply it manually: +==== [source,java] ---- RelyingPartyRegistration relyingPartyRegistration = RelyingPartyRegistration.withRegistrationId("okta") @@ -722,19 +734,20 @@ RelyingPartyRegistration relyingPartyRegistration = RelyingPartyRegistration.wit .singleSignOnServiceBinding(Saml2MessageType.POST) ); ---- - +==== [[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. +You may want to adjust an `AuthnRequest` for a number of reasons. +For example, you may want `ForceAuthN` to be set to `true`. By default, Spring Security sets it to `false`. -If you don't need information from the `HttpServletRequest` to make your decision, then the easiest way is to <>. -This will give you access to post-process the `AuthnRequest` instance before it's serialized. +If you do not need information from the `HttpServletRequest` to make your decision, the easiest way is to <>. +This gives you access to post-process the `AuthnRequest` instance before it is serialized. -But, if you do need something from the request, then you can use create a custom `Saml2AuthenticationRequestContext` implementation and then a `Converter` to build an `AuthnRequest` yourself, like so: +However, if you do need something from the request, you can use create a custom `Saml2AuthenticationRequestContext` implementation and then a `Converter` to build an `AuthnRequest` yourself: +==== [source,java] ---- @Component @@ -763,9 +776,11 @@ public class AuthnRequestConverter implements } } ---- +==== -Then, you can construct your own `Saml2AuthenticationRequestContextResolver` and `Saml2AuthenticationRequestFactory` and publish them as `@Bean` s: +Then you can construct your own `Saml2AuthenticationRequestContextResolver` and `Saml2AuthenticationRequestFactory` and publish them as `@Bean` objects: +==== [source,java] ---- @Bean @@ -788,27 +803,29 @@ Saml2AuthenticationRequestFactory authenticationRequestFactory( return authenticationRequestFactory; } ---- +==== [[servlet-saml2login-authenticate-responses]] -=== Authenticating `` s +=== Authenticating `` Instances To verify SAML 2.0 Responses, Spring Security uses <> by default. -You can configure this in a number of ways including: +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 +* Setting a clock skew to timestamp validation +* Mapping the response to a list of `GrantedAuthority` instances +* Customizing the strategy for validating assertions +* Customizing the strategy for decrypting response and assertion elements -To configure these, you'll use the `saml2Login#authenticationManager` method in the DSL. +To configure these, you can 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 `OpenSamlAuthenticationProvider` 's default assertion validator with some tolerance: +Often, the asserting and relying parties have system clocks that are not perfectly synchronized. +For that reason, you can configure the default assertion validator of `OpenSamlAuthenticationProvider` with some tolerance: +==== [source,java] ---- @EnableWebSecurity @@ -836,13 +853,15 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter { } } ---- +==== [[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: +Alternatively, you might like to include user details from a legacy `UserDetailsService`. +In that case, the response authentication converter can come in handy: +==== [source,java] ---- @EnableWebSecurity @@ -873,28 +892,29 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter { } } ---- -<1> First, call the default converter, which extracts attributes and authorities from the response -<2> Second, call the <> using the relevant information -<3> Third, return a custom authentication that includes the user details +<1> Call the default converter, which extracts attributes and authorities from the response +<2> Call the <> by using the relevant information +<3> Return a custom authentication that includes the user details +==== -[NOTE] -It's not required to call `OpenSamlAuthenticationProvider` 's default authentication converter. -It returns a `Saml2AuthenticatedPrincipal` containing the attributes it extracted from `AttributeStatement` s as well as the single `ROLE_USER` authority. +NOTE: You need not call the default authentication converter of `OpenSamlAuthenticationProvider`. +It returns a `Saml2AuthenticatedPrincipal` that contains the attributes it extracted from `AttributeStatement` instances as well as the single `ROLE_USER` authority. [[servlet-saml2login-opensamlauthenticationprovider-additionalvalidation]] ==== Performing Additional Validation `OpenSamlAuthenticationProvider` performs minimal validation on SAML 2.0 Assertions. -After verifying the signature, it will: +After verifying the signature, it: -1. Validate `` and `` conditions -2. Validate `` s, expect for any IP address information +. Validates `` and `` conditions +. Validates `` instances, expect for any IP address information -To perform additional validation, you can configure your own assertion validator that delegates to `OpenSamlAuthenticationProvider` 's default and then performs its own. +To perform additional validation, you can configure your own assertion validator that delegates to the default of `OpenSamlAuthenticationProvider` and then performs its own validation. [[servlet-saml2login-opensamlauthenticationprovider-onetimeuse]] -For example, you can use OpenSAML's `OneTimeUseConditionValidator` to also validate a `` condition, like so: +For example, you can use OpenSAML's `OneTimeUseConditionValidator` to also validate a `` condition: +==== [source,java] ---- OpenSamlAuthenticationProvider provider = new OpenSamlAuthenticationProvider(); @@ -916,10 +936,10 @@ provider.setAssertionValidator(assertionToken -> { return result.contact(new Saml2Error(INVALID_ASSERTION, context.getValidationFailureMessage())); }); ---- +==== -[NOTE] -While recommended, it's not necessary to call `OpenSamlAuthenticationProvider` 's default assertion validator. -A circumstance where you would skip it would be if you don't need it to check the `` or the `` since you are doing those yourself. +NOTE: While recommended, you need not call the default assertion validator of `OpenSamlAuthenticationProvider`. +For example, you could skip it if you do not need to check the `` or the `` because you are doing those yourself. [[servlet-saml2login-opensamlauthenticationprovider-decryption]] ==== Customizing Decryption @@ -927,37 +947,42 @@ A circumstance where you would skip it would be if you don't need it to check th Spring Security decrypts ``, ``, and `` elements automatically by using the decryption <> registered in the <>. `OpenSamlAuthenticationProvider` exposes <>. -The response decrypter is for decrypting encrypted elements of the ``, like ``. -The assertion decrypter is for decrypting encrypted elements of the ``, like `` and ``. +The response decrypter decrypts encrypted elements of the ``, such as ``. +The assertion decrypter decrypts encrypted elements of the ``, such as `` and ``. -You can replace `OpenSamlAuthenticationProvider`'s default decryption strategy with your own. -For example, if you have a separate service that decrypts the assertions in a ``, you can use it instead like so: +You can replace the default decryption strategy of `OpenSamlAuthenticationProvider` with your own strategy. +For example, if you have a separate service that decrypts the assertions in a ``, you can use it instead: +==== [source,java] ---- MyDecryptionService decryptionService = ...; OpenSamlAuthenticationProvider provider = new OpenSamlAuthenticationProvider(); provider.setResponseElementsDecrypter((responseToken) -> decryptionService.decrypt(responseToken.getResponse())); ---- +==== -If you are also decrypting individual elements in a ``, you can customize the assertion decrypter, too: +If you also decrypt individual elements in a ``, you can customize the assertion decrypter, too: +==== [source,java] ---- provider.setAssertionElementsDecrypter((assertionToken) -> decryptionService.decrypt(assertionToken.getAssertion())); ---- +==== -NOTE: There are two separate decrypters since assertions can be signed separately from responses. +NOTE: We have two separate decrypters, because 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. +If your asserting party signs only the response, it is safe to decrypt all elements by 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. +You can also use the `authenticationManager` DSL method to perform a completely custom SAML 2.0 authentication. +This authentication manager should expect a `Saml2AuthenticationToken` object that contains the SAML 2.0 Response XML data. +==== [source,java] ---- @EnableWebSecurity @@ -977,15 +1002,17 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter { } } ---- +==== [[servlet-saml2login-authenticatedprincipal]] -=== Using `Saml2AuthenticatedPrincipal` +=== Using the `Saml2AuthenticatedPrincipal` -With the relying party correctly configured for a given asserting party, it's ready to accept assertions. +With the relying party correctly configured for a given asserting party, it is 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: +This means that you can access the principal in your controller: +==== [source,java] ---- @Controller @@ -998,16 +1025,17 @@ public class MainController { } } ---- +==== -[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. +TIP: Because the SAML 2.0 specification lets each attribute 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 handy when you know that there is only one value. [[servlet-saml2login-metadata]] === Producing `` Metadata -You can publish a metadata endpoint by adding the `Saml2MetadataFilter` to the filter chain, as you'll see below: +You can publish a metadata endpoint by adding the `Saml2MetadataFilter` to the filter chain: +==== [source,java] ---- Converter relyingPartyRegistrationResolver = @@ -1021,26 +1049,31 @@ http .saml2Login(withDefaults()) .addFilterBefore(new Saml2MetadataFilter(r), Saml2WebSsoAuthenticationFilter.class); ---- +==== 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. +This is often as simple as finding the correct form field to supply to 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: +==== [source,java] ---- filter.setRequestMatcher(new AntPathRequestMatcher("/saml2/metadata/{registrationId}", "GET")); ---- +==== -ensuring that the `registrationId` hint is at the end of the path. +Doing so ensures 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: +Alternatively, if you have registered a custom relying party registration resolver in the constructor, you can specify a path without a `registrationId` hint: +==== [source,java] ---- filter.setRequestMatcher(new AntPathRequestMatcher("/saml2/metadata", "GET")); ---- +==== [[servlet-saml2login-logout]] === Performing Single Logout @@ -1049,6 +1082,7 @@ Spring Security does not yet support single logout. Generally speaking, though, you can achieve this by creating and registering a custom `LogoutSuccessHandler` and `RequestMatcher`: +==== [source,java] ---- http @@ -1058,7 +1092,8 @@ http .logoutRequestMatcher(myRequestMatcher()) ) ---- +==== -The success handler will send logout requests to the asserting party. +The success handler sends logout requests to the asserting party. -The request matcher will detect logout requests from the asserting party. +The request matcher detects logout requests from the asserting party. diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/test/index.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/test/index.adoc index da7d74db4af..ae8ef2de74a 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/test/index.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/test/index.adoc @@ -3,10 +3,7 @@ This section describes the testing support provided by Spring Security. -[TIP] -==== -To use the Spring Security test support, you must include `spring-security-test-{spring-security-version}.jar` as a dependency of your project. -==== +NOTE: To use the Spring Security test support, you must include `spring-security-test-{spring-security-version}.jar` as a dependency of your project. include::method.adoc[] diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/test/method.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/test/method.adoc index 6bc72723472..316cf6c4d04 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/test/method.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/test/method.adoc @@ -1,9 +1,10 @@ [[test-method]] == 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. +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 to be able to access it: +==== [source,java] ---- public class HelloMessageService implements MessageService { @@ -16,41 +17,46 @@ public class HelloMessageService implements MessageService { } } ---- +==== -The result of `getMessage` is a String saying "Hello" to the current Spring Security `Authentication`. -An example of the output is displayed below. +The result of `getMessage` is a `String` that says "`Hello`" to the current Spring Security `Authentication`. +The follwoing listing shows example output: +==== [source,text] ---- Hello org.springframework.security.authentication.UsernamePasswordAuthenticationToken@ca25360: Principal: org.springframework.security.core.userdetails.User@36ebcb: Username: user; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: ROLE_USER; Credentials: [PROTECTED]; Authenticated: true; Details: null; Granted Authorities: ROLE_USER ---- +==== [[test-method-setup]] === Security Test Setup -Before we can use Spring Security Test support, we must perform some setup. An example can be seen below: +Before we can use the Spring Security test support, we must perform some setup: +==== [source,java] ---- @RunWith(SpringJUnit4ClassRunner.class) // <1> @ContextConfiguration // <2> public class WithMockUserTests { + ... +} ---- +<1> `@RunWith` instructs the spring-test module that it should create an `ApplicationContext`. This is no different than using the existing Spring Test support. For additional information, see the https://docs.spring.io/spring-framework/docs/4.0.x/spring-framework-reference/htmlsingle/#integration-testing-annotations-standard[Spring Reference]. +<2> `@ContextConfiguration` instructs the Spring test configuration to use to create the `ApplicationContext`. Since no configuration is specified, the default configuration locations are tried. This is no different than using the existing Spring test support. For additional information, see the https://docs.spring.io/spring-framework/docs/4.0.x/spring-framework-reference/htmlsingle/#testcontext-ctx-management[Spring Reference]. +==== -This is a basic example of how to setup Spring Security Test. The highlights are: - -<1> `@RunWith` instructs the spring-test module that it should create an `ApplicationContext`. This is no different than using the existing Spring Test support. For additional information, refer to the https://docs.spring.io/spring-framework/docs/4.0.x/spring-framework-reference/htmlsingle/#integration-testing-annotations-standard[Spring Reference] -<2> `@ContextConfiguration` instructs the spring-test the configuration to use to create the `ApplicationContext`. Since no configuration is specified, the default configuration locations will be tried. This is no different than using the existing Spring Test support. For additional information, refer to the https://docs.spring.io/spring-framework/docs/4.0.x/spring-framework-reference/htmlsingle/#testcontext-ctx-management[Spring Reference] - -NOTE: Spring Security hooks into Spring Test support using the `WithSecurityContextTestExecutionListener` which will ensure our tests are ran with the correct user. +NOTE: Spring Security hooks into Spring Test support through the `WithSecurityContextTestExecutionListener`, which ensures that our tests are run with the correct user. It does this by populating the `SecurityContextHolder` prior to running our tests. -If you are using reactive method security, you will also need `ReactorContextTestExecutionListener` which populates `ReactiveSecurityContextHolder`. -After the test is done, it will clear out the `SecurityContextHolder`. -If you only need Spring Security related support, you can replace `@ContextConfiguration` with `@SecurityTestExecutionListeners`. +If you use reactive method security, you also need `ReactorContextTestExecutionListener`, which populates `ReactiveSecurityContextHolder`. +After the test is done, it clears out the `SecurityContextHolder`. +If you need only Spring Security related support, you can replace `@ContextConfiguration` with `@SecurityTestExecutionListeners`. -Remember we added the `@PreAuthorize` annotation to our `HelloMessageService` and so it requires an authenticated user to invoke it. -If we ran the following test, we would expect the following test will pass: +Remember, we added the `@PreAuthorize` annotation to our `HelloMessageService`, so it requires an authenticated user to invoke it. +If we run the tests, we expect the following test will pass: +==== [source,java] ---- @Test(expected = AuthenticationCredentialsNotFoundException.class) @@ -58,14 +64,16 @@ public void getMessageUnauthenticated() { messageService.getMessage(); } ---- +==== [[test-method-withmockuser]] === @WithMockUser -The question is "How could we most easily run the test as a specific user?" +The question is "`How could we most easily run the test as a specific user?`" The answer is to use `@WithMockUser`. -The following test will be run as a user with the username "user", the password "password", and the roles "ROLE_USER". +The following test runs as a user with a username of `user`, a password of `password`, and the role of `ROLE_USER`. +==== [source,java] ---- @Test @@ -75,18 +83,22 @@ String message = messageService.getMessage(); ... } ---- +==== Specifically the following is true: -* The user with the username "user" does not have to exist since we are mocking the user -* The `Authentication` that is populated in the `SecurityContext` is of type `UsernamePasswordAuthenticationToken` -* The principal on the `Authentication` is Spring Security's `User` object -* The `User` will have the username of "user", the password "password", and a single `GrantedAuthority` named "ROLE_USER" is used. +* The user with a username of `user` does not have to exist, since we mock the user object. +* The `Authentication` that is populated in the `SecurityContext` is of type `UsernamePasswordAuthenticationToken`. +* The principal on the `Authentication` is Spring Security's `User` object. +* The `User` has a username of `user`. +* The `User` has a password of `password`. +* A single `GrantedAuthority` named `ROLE_USER` is used. -Our example is nice because we are able to leverage a lot of defaults. +The preceding example is handy, because it lets us use a lot of defaults. What if we wanted to run the test with a different username? -The following test would run with the username "customUser". Again, the user does not need to actually exist. +The following test would run with a username of `customUser` (again, the user does not need to actually exist): +==== [source,java] ---- @Test @@ -96,10 +108,12 @@ public void getMessageWithMockUserCustomUsername() { ... } ---- +==== We can also easily customize the roles. -For example, this test will be invoked with the username "admin" and the roles "ROLE_USER" and "ROLE_ADMIN". +For example, the following test is invoked with a username of `admin` and roles of `ROLE_USER` and `ROLE_ADMIN`. +==== [source,java] ---- @Test @@ -109,10 +123,12 @@ public void getMessageWithMockUserCustomUser() { ... } ---- +==== -If we do not want the value to automatically be prefixed with ROLE_ we can leverage the authorities attribute. -For example, this test will be invoked with the username "admin" and the authorities "USER" and "ADMIN". +If we do not want the value to automatically be prefixed with `ROLE_` we can use the `authorities` attribute. +For example, the following test is invoked with a username of `admin` and the `USER` and `ADMIN` authorities. +==== [source,java] ---- @Test @@ -122,22 +138,28 @@ public void getMessageWithMockUserCustomAuthorities() { ... } ---- +==== -Of course it can be a bit tedious placing the annotation on every test method. -Instead, we can place the annotation at the class level and every test will use the specified user. -For example, the following would run every test with a user with the username "admin", the password "password", and the roles "ROLE_USER" and "ROLE_ADMIN". +It can be a bit tedious to place the annotation on every test method. +Instead, we can place the annotation at the class level. Then every test uses the specified user. +The following example runs every test with a user whose username is `admin`, whose password is `password`, and who has the `ROLE_USER` and `ROLE_ADMIN` roles: +==== [source,java] ---- @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration @WithMockUser(username="admin",roles={"USER","ADMIN"}) public class WithMockUserTests { + ... +} ---- +==== -If you are using JUnit 5's `@Nested` test support, you can also place the annotation on the enclosing class to apply to all nested classes. -For example, the following would run every test with a user with the username "admin", the password "password", and the roles "ROLE_USER" and "ROLE_ADMIN" for both test methods. +If you use JUnit 5's `@Nested` test support, you can also place the annotation on the enclosing class to apply to all nested classes. +The following example runs every test with a user whose username is `admin`, whose password is `password`, and who has the `ROLE_USER` and `ROLE_ADMIN` roles for both test methods. +==== [source,java] ---- @ExtendWith(SpringExtension.class) @@ -156,24 +178,27 @@ public class WithMockUserTests { } } ---- +==== -By default the `SecurityContext` is set during the `TestExecutionListener.beforeTestMethod` event. +By default, the `SecurityContext` is set during the `TestExecutionListener.beforeTestMethod` event. This is the equivalent of happening before JUnit's `@Before`. -You can change this to happen during the `TestExecutionListener.beforeTestExecution` event which is after JUnit's `@Before` but before the test method is invoked. +You can change this to happen during the `TestExecutionListener.beforeTestExecution` event, which is after JUnit's `@Before` but before the test method is invoked: +==== [source,java] ---- @WithMockUser(setupBefore = TestExecutionEvent.TEST_EXECUTION) ---- - +==== [[test-method-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. -For example, the following will run withMockUser1 and withMockUser2 using <> and anonymous 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. +The following example runs `withMockUser1` and `withMockUser2` by using <> and `anonymous` as an anonymous user: +==== [source,java] ---- @RunWith(SpringJUnit4ClassRunner.class) @@ -195,30 +220,33 @@ public class WithUserClassLevelAuthenticationTests { } } ---- +==== -By default the `SecurityContext` is set during the `TestExecutionListener.beforeTestMethod` event. +By default, the `SecurityContext` is set during the `TestExecutionListener.beforeTestMethod` event. This is the equivalent of happening before JUnit's `@Before`. -You can change this to happen during the `TestExecutionListener.beforeTestExecution` event which is after JUnit's `@Before` but before the test method is invoked. +You can change this to happen during the `TestExecutionListener.beforeTestExecution` event, which is after JUnit's `@Before` but before the test method is invoked: +==== [source,java] ---- @WithAnonymousUser(setupBefore = TestExecutionEvent.TEST_EXECUTION) ---- - +==== [[test-method-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. +While `@WithMockUser` is a convenient way to get started, it may not work in all instances. +For example, some applications expect the `Authentication` principal to be of a specific type. This is done so that the application can refer to the principal as the custom type and reduce coupling on Spring Security. -The custom principal is often times returned by a custom `UserDetailsService` that returns an object that implements both `UserDetails` and the custom type. -For situations like this, it is useful to create the test user using the custom `UserDetailsService`. +The custom principal is often returned by a custom `UserDetailsService` that returns an object that implements both `UserDetails` and the custom type. +For situations like this, it is useful to create the test user by using a custom `UserDetailsService`. That is exactly what `@WithUserDetails` does. -Assuming we have a `UserDetailsService` exposed as a bean, the following test will be invoked with an `Authentication` of type `UsernamePasswordAuthenticationToken` and a principal that is returned from the `UserDetailsService` with the username of "user". +Assuming we have a `UserDetailsService` exposed as a bean, the following test is invoked with an `Authentication` of type `UsernamePasswordAuthenticationToken` and a principal that is returned from the `UserDetailsService` with the username of `user`: +==== [source,java] ---- @Test @@ -228,10 +256,12 @@ public void getMessageWithUserDetails() { ... } ---- +==== We can also customize the username used to lookup the user from our `UserDetailsService`. -For example, this test would be run with a principal that is returned from the `UserDetailsService` with the username of "customUsername". +For example, this test can be run with a principal that is returned from the `UserDetailsService` with the username of `customUsername`: +==== [source,java] ---- @Test @@ -241,10 +271,12 @@ public void getMessageWithUserDetailsCustomUsername() { ... } ---- +==== We can also provide an explicit bean name to look up the `UserDetailsService`. -For example, this test would look up the username of "customUsername" using the `UserDetailsService` with the bean name "myUserDetailsService". +The following test looks up the username of `customUsername` by using the `UserDetailsService` with a bean name of `myUserDetailsService`: +==== [source,java] ---- @Test @@ -254,30 +286,33 @@ public void getMessageWithUserDetailsServiceBeanName() { ... } ---- +==== -Like `@WithMockUser` we can also place our annotation at the class level so that every test uses the same user. -However unlike `@WithMockUser`, `@WithUserDetails` requires the user to exist. +As we did with `@WithMockUser`, we can also place our annotation at the class level so that every test uses the same user. +However, unlike `@WithMockUser`, `@WithUserDetails` requires the user to exist. -By default the `SecurityContext` is set during the `TestExecutionListener.beforeTestMethod` event. +By default, the `SecurityContext` is set during the `TestExecutionListener.beforeTestMethod` event. This is the equivalent of happening before JUnit's `@Before`. -You can change this to happen during the `TestExecutionListener.beforeTestExecution` event which is after JUnit's `@Before` but before the test method is invoked. +You can change this to happen during the `TestExecutionListener.beforeTestExecution` event, which is after JUnit's `@Before` but before the test method is invoked: +==== [source,java] ---- @WithUserDetails(setupBefore = TestExecutionEvent.TEST_EXECUTION) ---- - +==== [[test-method-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. -We will now see an option that allows the most flexibility. +We have seen that `@WithMockUser` is an excellent choice if we do not use a custom `Authentication` principal. +Next, we discovered that `@WithUserDetails` lets us use a custom `UserDetailsService` to create our `Authentication` principal but requires the user to exist. +We now see an option that allows the most flexibility. We can create our own annotation that uses the `@WithSecurityContext` to create any `SecurityContext` we want. -For example, we might create an annotation named `@WithMockCustomUser` as shown below: +For example, we might create an annotation named `@WithMockCustomUser`: +==== [source,java] ---- @Retention(RetentionPolicy.RUNTIME) @@ -289,12 +324,14 @@ public @interface WithMockCustomUser { String name() default "Rob Winch"; } ---- +==== You can see that `@WithMockCustomUser` is annotated with the `@WithSecurityContext` annotation. -This is what signals to Spring Security Test support that we intend to create a `SecurityContext` for the test. -The `@WithSecurityContext` annotation requires we specify a `SecurityContextFactory` that will create a new `SecurityContext` given our `@WithMockCustomUser` annotation. -You can find our `WithMockCustomUserSecurityContextFactory` implementation below: +This is what signals to Spring Security test support that we intend to create a `SecurityContext` for the test. +The `@WithSecurityContext` annotation requires that we specify a `SecurityContextFactory` to create a new `SecurityContext`, given our `@WithMockCustomUser` annotation. +The following listing shows our `WithMockCustomUserSecurityContextFactory` implementation: +==== [source,java] ---- public class WithMockCustomUserSecurityContextFactory @@ -312,12 +349,14 @@ public class WithMockCustomUserSecurityContextFactory } } ---- +==== -We can now annotate a test class or a test method with our new annotation and Spring Security's `WithSecurityContextTestExecutionListener` will ensure that our `SecurityContext` is populated appropriately. +We can now annotate a test class or a test method with our new annotation and Spring Security's `WithSecurityContextTestExecutionListener` to ensure that our `SecurityContext` is populated appropriately. When creating your own `WithSecurityContextFactory` implementations, it is nice to know that they can be annotated with standard Spring annotations. For example, the `WithUserDetailsSecurityContextFactory` uses the `@Autowired` annotation to acquire the `UserDetailsService`: +==== [source,java] ---- final class WithUserDetailsSecurityContextFactory @@ -341,39 +380,45 @@ final class WithUserDetailsSecurityContextFactory } } ---- +==== -By default the `SecurityContext` is set during the `TestExecutionListener.beforeTestMethod` event. +By default, the `SecurityContext` is set during the `TestExecutionListener.beforeTestMethod` event. This is the equivalent of happening before JUnit's `@Before`. -You can change this to happen during the `TestExecutionListener.beforeTestExecution` event which is after JUnit's `@Before` but before the test method is invoked. +You can change this to happen during the `TestExecutionListener.beforeTestExecution` event, which is after JUnit's `@Before` but before the test method is invoked: +==== [source,java] ---- @WithSecurityContext(setupBefore = TestExecutionEvent.TEST_EXECUTION) ---- - +==== [[test-method-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: +For example, if you have many tests related to an administrative user with a username of `admin` and roles of `ROLE_USER` and `ROLE_ADMIN`, you have to write: +==== [source,java] ---- @WithMockUser(username="admin",roles={"USER","ADMIN"}) ---- +==== Rather than repeating this everywhere, we can use a meta annotation. For example, we could create a meta annotation named `WithMockAdmin`: +==== [source,java] ---- @Retention(RetentionPolicy.RUNTIME) @WithMockUser(value="rob",roles="ADMIN") public @interface WithMockAdmin { } ---- +==== Now we can use `@WithMockAdmin` in the same way as the more verbose `@WithMockUser`. -Meta annotations work with any of the testing annotations described above. -For example, this means we could create a meta annotation for `@WithUserDetails("admin")` as well. +Meta annotations work with any of the testing annotations described in this section. +For example, this means that we could create a meta annotation for `@WithUserDetails("admin")` as well. diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/test/mockmvc.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/test/mockmvc.adoc index 5fe1fbd94d0..6a8e3712b19 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/test/mockmvc.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/test/mockmvc.adoc @@ -6,16 +6,15 @@ Spring Security provides comprehensive integration with https://docs.spring.io/s [[test-mockmvc-setup]] === 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 <>. -This can be done using Spring Security's `SecurityMockMvcConfigurers.springSecurity()`. -For example: - NOTE: Spring Security's testing support requires spring-test-4.1.3.RELEASE or greater. +To use Spring Security with Spring MVC Test, add the Spring Security `FilterChainProxy` as a `Filter`. +You also need to add Spring Security's `TestSecurityContextHolderPostProcessor` to support <>. +To do so, use Spring Security's `SecurityMockMvcConfigurers.springSecurity()`: + +==== [source,java] ---- - import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.*; @RunWith(SpringJUnit4ClassRunner.class) @@ -37,129 +36,151 @@ public 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 -Spring MVC Test provides a convenient interface called a `RequestPostProcessor` that can be used to modify a request. +Spring MVC Test provides a convenient interface (`RequestPostProcessor`) that you can use to modify a request. Spring Security provides a number of `RequestPostProcessor` implementations that make testing easier. -In order to use Spring Security's `RequestPostProcessor` implementations ensure the following static import is used: +To use Spring Security's `RequestPostProcessor` implementations, use the following static import: +==== [source,java] ---- import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.*; ---- +==== [[test-mockmvc-csrf]] ==== 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: +When testing any non-safe HTTP methods and using Spring Security's CSRF protection, you must include a valid CSRF Token in the request. +To specify a valid CSRF token as a request parameter, use the following: +==== [source,java] ---- mvc .perform(post("/").with(csrf())) ---- +==== -If you like you can include CSRF token in the header instead: +If you like, you can include CSRF token in the header instead: +==== [source,java] ---- mvc .perform(post("/").with(csrf().asHeader())) ---- +==== -You can also test providing an invalid CSRF token using the following: +You can also test providing an invalid CSRF token by using the following: +==== [source,java] ---- mvc .perform(post("/").with(csrf().useInvalidToken())) ---- +==== [[test-mockmvc-securitycontextholder]] ==== 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: +There are two simple ways to populate the user: -* <> -* <> +* <> +* <> [[test-mockmvc-securitycontextholder-rpp]] ==== 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": +You have a number of options to associate a user to the current `HttpServletRequest`. +The following example runs as a user (which does not need to exist) whose username is `user`, whose password is `password`, and whose role is `ROLE_USER`: + +==== +[source,java] +---- +mvc + .perform(get("/").with(user("user"))) +---- +==== [NOTE] ==== The support works by associating the user to the `HttpServletRequest`. -To associate the request to the `SecurityContextHolder` you need to ensure that the `SecurityContextPersistenceFilter` is associated with the `MockMvc` instance. -A few ways to do this are: +To associate the request to the `SecurityContextHolder`, you need to ensure that the `SecurityContextPersistenceFilter` is associated with the `MockMvc` instance. +You can do so in a number of ways: * Invoking <> * Adding Spring Security's `FilterChainProxy` to `MockMvc` * Manually adding `SecurityContextPersistenceFilter` to the `MockMvc` instance may make sense when using `MockMvcBuilders.standaloneSetup` ==== -[source,java] ----- -mvc - .perform(get("/").with(user("user"))) ----- - -You can easily make customizations. -For example, the following will run as a user (which does not need to exist) with the username "admin", the password "pass", and the roles "ROLE_USER" and "ROLE_ADMIN". +You can make customizations. +The following example runs as a user (which does not need to exist) whose username is `admin`, whose password is `pass`, and whose roles are `ROLE_USER` and `ROLE_ADMIN`. +==== [source,java] ---- mvc .perform(get("/admin").with(user("admin").password("pass").roles("USER","ADMIN"))) ---- +==== -If you have a custom `UserDetails` that you would like to use, you can easily specify that as well. -For example, the following will use the specified `UserDetails` (which does not need to exist) to run with a `UsernamePasswordAuthenticationToken` that has a principal of the specified `UserDetails`: +If you have a custom `UserDetails` object that you would like to use, you can specify that as well. +The following example uses the specified `UserDetails` (which does not need to exist) to run with a `UsernamePasswordAuthenticationToken` that has a principal of the specified `UserDetails`: +==== [source,java] ---- mvc .perform(get("/").with(user(userDetails))) ---- +==== -You can run as anonymous user using the following: +You can run as anonymous user by using the following: +==== [source,java] ---- mvc .perform(get("/").with(anonymous())) ---- +==== -This is especially useful if you are running with a default user and wish to process a few requests as an anonymous user. +This is especially useful when you run with a default user and wish to process a few requests as an anonymous user. -If you want a custom `Authentication` (which does not need to exist) you can do so using the following: +If you want a custom `Authentication` (which does not need to exist), you can do so by using the following: +==== [source,java] ---- mvc .perform(get("/").with(authentication(authentication))) ---- +==== -You can even customize the `SecurityContext` using the following: +You can even customize the `SecurityContext`, by using the following: +==== [source,java] ---- mvc .perform(get("/").with(securityContext(securityContext))) ---- +==== -We can also ensure to run as a specific user for every request by using ``MockMvcBuilders``'s default request. -For example, the following will run as a user (which does not need to exist) with the username "admin", the password "password", and the role "ROLE_ADMIN": +We can also ensure running as a specific user for every request by using the default request of `MockMvcBuilders`. +The following exampe runs as a user (which does not need to exist) whose username is `admin`, whose password is `password`, and whose role is `ROLE_ADMIN`: +==== [source,java] ---- mvc = MockMvcBuilders @@ -168,19 +189,23 @@ mvc = MockMvcBuilders .apply(springSecurity()) .build(); ---- +==== -If you find you are using the same user in many of your tests, it is recommended to move the user to a method. -For example, you can specify the following in your own class named `CustomSecurityMockMvcRequestPostProcessors`: +If you find yourself using the same user in many of your tests, we recommended moving the user to a method. +For example, you can specify the following in your own `CustomSecurityMockMvcRequestPostProcessors` class: +==== [source,java] ---- public static RequestPostProcessor rob() { return user("rob").roles("ADMIN"); } ---- +==== Now you can perform a static import on `SecurityMockMvcRequestPostProcessors` and use that within your tests: +==== [source,java] ---- import static sample.CustomSecurityMockMvcRequestPostProcessors.*; @@ -190,12 +215,14 @@ import static sample.CustomSecurityMockMvcRequestPostProcessors.*; mvc .perform(get("/").with(rob())) ---- - +==== +[[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 <>. -For example, the following will run the test with the user with username "user", password "password", and role "ROLE_USER": +As an alternative to using a `RequestPostProcessor` to create your user, you can use the annotations described in <>. +The following example runs the test with a user whose username is `user`, whose password is `password`, and whose role is `ROLE_USER`: +==== [source,java] ---- @Test @@ -206,9 +233,11 @@ mvc ... } ---- +==== -Alternatively, the following will run the test with the user with username "user", password "password", and role "ROLE_ADMIN": +Alternatively, the following example runs the test with a user whose username is `user`, whose password is `password`, and whose role is `ROLE_ADMIN`: +==== [source,java] ---- @Test @@ -219,33 +248,39 @@ mvc ... } ---- +==== ==== 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`. -For example, the snippet below: +Now you can do so by using Spring Security's `httpBasic` `RequestPostProcessor`. +Consider the following snippet: +==== [source,java] ---- mvc .perform(get("/").with(httpBasic("user","password"))) ---- +==== -will attempt to use HTTP Basic to authenticate a user with the username "user" and the password "password" by ensuring the following header is populated on the HTTP Request: +The preceding line tries to use HTTP Basic to authenticate a user whose username is `user` and whose password is `password` by ensuring the following header is populated on the HTTP Request: +==== [source,text] ---- Authorization: Basic dXNlcjpwYXNzd29yZA== ---- +==== [[testing-oauth2]] ==== 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`. -For example, for a controller that looks like this: +For example, consider the following controller: +==== [source,java] ---- @GetMapping("/endpoint") @@ -253,11 +288,13 @@ public String foo(Principal user) { return user.getName(); } ---- +==== -There's nothing OAuth2-specific about it, so you will likely be able to simply <> and be fine. +There is nothing OAuth2-specific about it, so you can probably <> and be fine. -But, in cases where your controllers are bound to some aspect of Spring Security's OAuth 2.0 support, like the following: +However, in cases where your controllers are bound to some aspect of Spring Security's OAuth 2.0 support, Spring Security's test support can come in handy: +==== [source,java] ---- @GetMapping("/endpoint") @@ -265,50 +302,57 @@ public String foo(@AuthenticationPrincipal OidcUser user) { return user.getIdToken().getSubject(); } ---- - -then Spring Security's test support can come in handy. +==== [[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. +Testing the method above with Spring MVC Test requires simulating some kind of grant flow with an authorization server. +This can be a daunting task, which is why Spring Security ships with support for removing this boilerplate. -For example, we can tell Spring Security to include a default `OidcUser` using the `SecurityMockMvcRequestPostProcessors#oidcLogin` method, like so: +For example, we can tell Spring Security to include a default `OidcUser` by using the `SecurityMockMvcRequestPostProcessors#oidcLogin` method: +==== [source,java] ---- mvc .perform(get("/endpoint").with(oidcLogin())); ---- +==== -What this will do is configure the associated `MockHttpServletRequest` with an `OidcUser` that includes a simple `OidcIdToken`, `OidcUserInfo`, and `Collection` of granted authorities. +The preceding line configures the associated `MockHttpServletRequest` with an `OidcUser` that includes a `OidcIdToken`, an `OidcUserInfo`, and a `Collection` of granted authorities. -Specifically, it will include an `OidcIdToken` with a `sub` claim set to `user`: +Specifically, it includes an `OidcIdToken` with a `sub` claim set to `user`: -[source,json] +==== +[source,java] ---- assertThat(user.getIdToken().getClaim("sub")).isEqualTo("user"); ---- +==== -an `OidcUserInfo` with no claims set: +It also includes an `OidcUserInfo` with no claims set: -[source,json] +==== +[source,java] ---- assertThat(user.getUserInfo().getClaims()).isEmpty(); ---- +==== -and a `Collection` of authorities with just one authority, `SCOPE_read`: +Finally, it includes a `Collection` of authorities with only one authority, `SCOPE_read`: -[source,json] +==== +[source,java] ---- assertThat(user.getAuthorities()).hasSize(1); assertThat(user.getAuthorities()).containsExactly(new SimpleGrantedAuthority("SCOPE_read")); ---- +==== Spring Security does the necessary work to make sure that the `OidcUser` instance is available for <>. -Further, it also links that `OidcUser` to a simple instance of `OAuth2AuthorizedClient` that it deposits into an mock `OAuth2AuthorizedClientRepository`. +Further, it also links the `OidcUser` to an instance of `OAuth2AuthorizedClient` that it deposits into an mock `OAuth2AuthorizedClientRepository`. This can be handy if your tests <>.. [[testing-oidc-login-authorities]] @@ -316,8 +360,9 @@ This can be handy if your tests <>, 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. -Let's say that we've got a controller that gets the logged-in user as an `OAuth2User`: +Suppose that you have a controller that gets the logged-in user as an `OAuth2User`: +==== [source,java] ---- @GetMapping("/endpoint") @@ -403,35 +456,42 @@ public String foo(@AuthenticationPrincipal OAuth2User oauth2User) { return oauth2User.getAttribute("sub"); } ---- +==== -In that case, we can tell Spring Security to include a default `OAuth2User` using the `SecurityMockMvcRequestPostProcessors#oauth2User` method, like so: +In that case, you can tell Spring Security to include a default `OAuth2User` by using the `SecurityMockMvcRequestPostProcessors#oauth2User` method: +==== [source,java] ---- mvc .perform(get("/endpoint").with(oauth2Login())); ---- +==== -What this will do is configure the associated `MockHttpServletRequest` with an `OAuth2User` that includes a simple `Map` of attributes and `Collection` of granted authorities. +This line configures the associated `MockHttpServletRequest` with an `OAuth2User` that includes a simple `Map` of attributes and a `Collection` of granted authorities. -Specifically, it will include a `Map` with a key/value pair of `sub`/`user`: +Specifically, it includes a `Map` with a key/value pair of `sub`/`user`: -[source,json] +==== +[source,java] ---- assertThat((String) user.getAttribute("sub")).isEqualTo("user"); ---- +==== -and a `Collection` of authorities with just one authority, `SCOPE_read`: +It also includes a `Collection` of authorities with only one authority, `SCOPE_read`: -[source,json] +==== +[source,java] ---- assertThat(user.getAuthorities()).hasSize(1); assertThat(user.getAuthorities()).containsExactly(new SimpleGrantedAuthority("SCOPE_read")); ---- +==== Spring Security does the necessary work to make sure that the `OAuth2User` instance is available for <>. -Further, it also links that `OAuth2User` to a simple instance of `OAuth2AuthorizedClient` that it deposits in a mock `OAuth2AuthorizedClientRepository`. +Further, it also links that `OAuth2User` to an instance of `OAuth2AuthorizedClient` that it deposits in a mock `OAuth2AuthorizedClientRepository`. This can be handy if your tests <>. [[testing-oauth2-login-authorities]] @@ -439,8 +499,9 @@ This can be handy if your tests <)` - For configuring the associated `ClientRegistration` -* `clientRegistration(ClientRegistration)` - For configuring the complete `ClientRegistration` +* `principalName(String)`: For configuring the resource owner name +* `clientRegistration(Consumer)`: For configuring the associated `ClientRegistration` +* `clientRegistration(ClientRegistration)`: For configuring the complete `ClientRegistration` -That last one is handy if you want to use a real `ClientRegistration` +That last one is handy if you want to use a real `ClientRegistration` object. -For example, let's say that you are wanting to use one of your app's `ClientRegistration` definitions, as specified in your `application.yml`. +For example, suppose that you want to use one of your application's `ClientRegistration` definitions, as specified in your `application.yml`. In that case, your test can autowire the `ClientRegistrationRepository` and look up the one your test needs: +==== [source,java] ---- @Autowired @@ -623,33 +706,37 @@ mvc .with(oauth2Client() .clientRegistration(this.clientRegistrationRepository.findByRegistrationId("facebook")))); ---- +==== [[testing-jwt]] ==== Testing JWT Authentication -In order to make an authorized request on a resource server, you need a bearer token. +To make an authorized request on a resource server, you need a bearer token. -If your resource server is configured for JWTs, then this would mean that the bearer token needs to be signed and then encoded according to the JWT specification. -All of this can be quite daunting, especially when this isn't the focus of your test. +If your resource server is configured for JWTs, the bearer token needs to be signed and then encoded according to the JWT specification. +All of this can be quite daunting, especially when this is not the focus of your test. -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: +Fortunately, there are a number of ways that you can overcome this difficulty and let your tests focus on authorization and not on representing bearer tokens. +We look at two of them in the next two subsections. ===== `jwt() RequestPostProcessor` -The first way is via a `RequestPostProcessor`. -The simplest of these would look something like this: +The first way is with a `RequestPostProcessor`. +The simplest of these looks something like this: +==== [source,java] ---- mvc .perform(get("/endpoint").with(jwt())); ---- +==== -What this will do is create a mock `Jwt`, passing it correctly through any authentication APIs so that it's available for your authorization mechanisms to verify. +This line creates a mock `Jwt` and passes it correctly through any authentication APIs so that itis available for your authorization mechanisms to verify. By default, the `JWT` that it creates has the following characteristics: +==== [source,json] ---- { @@ -660,9 +747,11 @@ By default, the `JWT` that it creates has the following characteristics: } } ---- +==== -And the resulting `Jwt`, were it tested, would pass in the following way: +The resulting `Jwt`, were it tested, would pass in the following way: +==== [source,java] ---- assertThat(jwt.getTokenValue()).isEqualTo("token"); @@ -671,11 +760,13 @@ assertThat(jwt.getSubject()).isEqualTo("sub"); GrantedAuthority authority = jwt.getAuthorities().iterator().next(); assertThat(authority.getAuthority()).isEqualTo("read"); ---- +==== -These values can, of course be configured. +You can configure these values. -Any headers or claims can be configured with their corresponding methods: +You can configure any headers or claims with their corresponding methods: +==== [source,java] ---- mvc @@ -689,28 +780,34 @@ mvc .perform(get("/endpoint") .with(jwt().jwt(jwt -> jwt.claims(claims -> claims.remove("scope"))))); ---- +==== The `scope` and `scp` claims are processed the same way here as they are in a normal bearer token request. -However, this can be overridden simply by providing the list of `GrantedAuthority` instances that you need for your test: +However, you can override this by providing the list of `GrantedAuthority` instances that you need for your test: +==== [source,java] ---- mvc .perform(get("/endpoint") .with(jwt().authorities(new SimpleGrantedAuthority("SCOPE_messages")))); ---- +==== -Or, if you have a custom `Jwt` to `Collection` converter, you can also use that to derive the authorities: +Alternatively, if you have a custom `Jwt` to `Collection` converter, you can also use that to derive the authorities: +==== [source,java] ---- mvc .perform(get("/endpoint") .with(jwt().authorities(new MyConverter()))); ---- +==== -You can also specify a complete `Jwt`, for which `{security-api-url}org/springframework/security/oauth2/jwt/Jwt.Builder.html[Jwt.Builder]` comes quite handy: +You can also specify a complete `Jwt`, which you can do with `{security-api-url}org/springframework/security/oauth2/jwt/Jwt.Builder.html[`Jwt.Builder`]`: +==== [source,java] ---- Jwt jwt = Jwt.withTokenValue("token") @@ -722,12 +819,14 @@ mvc .perform(get("/endpoint") .with(jwt().jwt(jwt))); ---- +==== ===== `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: +Essentially, you can instantiate your own `JwtAuthenticationToken` and provide it in your test: +==== [source,java] ---- Jwt jwt = Jwt.withTokenValue("token") @@ -741,17 +840,19 @@ mvc .perform(get("/endpoint") .with(authentication(token))); ---- +==== -Note that as an alternative to these, you can also mock the `JwtDecoder` bean itself with a `@MockBean` annotation. +Note that, as an alternative to these approaches, you can also mock the `JwtDecoder` bean itself with a `@MockBean` annotation. [[testing-opaque-token]] ==== Testing Opaque Token Authentication -Similar to <>, opaque tokens require an authorization server in order to verify their validity, which can make testing more difficult. +Similar to <>, opaque tokens require an authorization server to verify their validity, which can make testing more difficult. To help with that, Spring Security has test support for opaque tokens. -Let's say that we've got a controller that retrieves the authentication as a `BearerTokenAuthentication`: +Suppose that you have a controller that retrieves the authentication as a `BearerTokenAuthentication`: +==== [source,java] ---- @GetMapping("/endpoint") @@ -759,27 +860,32 @@ public String foo(BearerTokenAuthentication authentication) { return (String) authentication.getTokenAttributes("sub"); } ---- +==== -In that case, we can tell Spring Security to include a default `BearerTokenAuthentication` using the `SecurityMockMvcRequestPostProcessors#opaqueToken` method, like so: +In that case, we can tell Spring Security to include a default `BearerTokenAuthentication` by using the `SecurityMockMvcRequestPostProcessors#opaqueToken` method: +==== [source,java] ---- mvc .perform(get("/endpoint").with(opaqueToken())); ---- +==== -What this will do is configure the associated `MockHttpServletRequest` with a `BearerTokenAuthentication` that includes a simple `OAuth2AuthenticatedPrincipal`, `Map` of attributes, and `Collection` of granted authorities. +This line configures the associated `MockHttpServletRequest` with a `BearerTokenAuthentication` that includes a simple `OAuth2AuthenticatedPrincipal`, a `Map` of attributes, and a `Collection` of granted authorities. -Specifically, it will include a `Map` with a key/value pair of `sub`/`user`: +Specifically, it includes a `Map` with a key/value pair of `sub`/`user`: -[source,json] +==== +[source,java] ---- assertThat((String) token.getTokenAttributes().get("sub")).isEqualTo("user"); ---- +==== -and a `Collection` of authorities with just one authority, `SCOPE_read`: +It also includes a `Collection` of authorities with only one authority, `SCOPE_read`: -[source,json] +[source,java] ---- assertThat(token.getAuthorities()).hasSize(1); assertThat(token.getAuthorities()).containsExactly(new SimpleGrantedAuthority("SCOPE_read")); @@ -792,8 +898,9 @@ Spring Security does the necessary work to make sure that the `BearerTokenAuthen 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. -In this case, you can supply what granted authorities you need using the `authorities()` method: +In this case, you can supply the granted authorities you need by using the `authorities()` method: +==== [source,java] ---- mvc @@ -803,15 +910,17 @@ mvc ) ); ---- +==== [[testing-opaque-token-attributes]] ===== 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. +While granted authorities are quite common across all of Spring Security, we also have attributes, in the case of OAuth 2.0. -Let's say, for example, that you've got a `user_id` attribute that indicates the user's id in your system. -You might access it like so in a controller: +Suppose, for example, that you have a `user_id` attribute that indicates the user's ID in your system. +You can access it in a controller: +==== [source,java] ---- @GetMapping("/endpoint") @@ -820,9 +929,11 @@ public String foo(BearerTokenAuthentication authentication) { // ... } ---- +==== -In that case, you'd want to specify that attribute with the `attributes()` method: +In that case, you want to specify that attribute with the `attributes()` method: +==== [source,java] ---- mvc @@ -832,21 +943,23 @@ mvc ) ); ---- +==== [[testing-opaque-token-principal]] ===== Additional Configurations -There are additional methods, too, for further configuring the authentication; it simply depends on what data your controller expects. +There are additional methods, too, for further configuring the authentication. It simply depends on what data your controller expects. -One such is `principal(OAuth2AuthenticatedPrincipal)`, which you can use to configure the complete `OAuth2AuthenticatedPrincipal` instance that underlies the `BearerTokenAuthentication` +One such method is `principal(OAuth2AuthenticatedPrincipal)`, which you can use to configure the complete `OAuth2AuthenticatedPrincipal` instance that underlies the `BearerTokenAuthentication` -It's handy if you: -1. Have your own implementation of `OAuth2AuthenticatedPrincipal`, or -2. Want to specify a different principal name +It is useful if you: +* Have your own implementation of `OAuth2AuthenticatedPrincipal` +* Want to specify a different principal name -For example, let's say that your authorization server sends the principal name in the `user_name` attribute instead of the `sub` attribute. +For example, suppose that your authorization server sends the principal name in the `user_name` attribute instead of the `sub` attribute. In that case, you can configure an `OAuth2AuthenticatedPrincipal` by hand: +==== [source,java] ---- Map attributes = Collections.singletonMap("user_name", "foo_user"); @@ -860,136 +973,162 @@ mvc .with(opaqueToken().principal(principal)) ); ---- +==== -Note that as an alternative to using `opaqueToken()` test support, you can also mock the `OpaqueTokenIntrospector` bean itself with a `@MockBean` annotation. +Note that, as an alternative to using `opaqueToken()` test support, you can also mock the `OpaqueTokenIntrospector` bean itself with a `@MockBean` annotation. === 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. -In order to use Spring Security's `RequestBuilder` implementations ensure the following static import is used: +Spring MVC Test also provides a `RequestBuilder` interface that you can use to create the `MockHttpServletRequest` for your test. +Spring Security provides a few `RequestBuilder` implementations that you can use to make testing easier. +To use Spring Security's `RequestBuilder` implementations, use the following static import: +==== [source,java] ---- import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestBuilders.*; ---- +==== -==== 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: +You can create a request to test a form-based authentication using Spring Security's testing support. +For example, the following line submits a POST to `/login` with a username of `user`, a password of `password`, and a valid CSRF token: +==== [source,java] ---- mvc .perform(formLogin()) ---- +==== It is easy to customize the request. -For example, the following will submit a POST to "/auth" with the username "admin", the password "pass", and a valid CSRF token: +For example, the following line submits a POST to `/auth` with a username of `admin`, a password of `pass`, and a valid CSRF token: +==== [source,java] ---- mvc .perform(formLogin("/auth").user("admin").password("pass")) ---- +==== -We can also customize the parameters names that the username and password are included on. -For example, this is the above request modified to include the username on the HTTP parameter "u" and the password on the HTTP parameter "p". +You can also customize the parameters names on which the username and password are included. +For example, the following line modifies the preceding request to include the username on the HTTP parameter named `u` and the password on the HTTP parameter named `p`: +==== [source,java] ---- mvc .perform(formLogin("/auth").user("u","admin").password("p","pass")) ---- +==== [[test-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: +A minor but still useful use case for Spring Security's testing support is to test logging out. +The following example submits a POST to `/logout` with a valid CSRF token: +==== [source,java] ---- mvc .perform(logout()) ---- +==== -You can also customize the URL to post to. -For example, the snippet below will submit a POST to "/signout" with a valid CSRF token: +You can also customize the URL to which to post. +The following example submits a POST to `/signout` with a valid CSRF token: +==== [source,java] ---- mvc .perform(logout("/signout")) ---- +==== === 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. -In order to use Spring Security's `ResultMatcher` implementations ensure the following static import is used: +At times, you may want to make various security-related assertions about a request. +To accommodate this need, Spring Security's testing support implements Spring MVC Test's `ResultMatcher` interface. +To use Spring Security's `ResultMatcher` implementations, use the following static import: +==== [source,java] ---- import static org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.*; ---- +==== ==== Unauthenticated Assertion -At times it may be valuable to assert that there is no authenticated user associated with the result of a `MockMvc` invocation. +At times, you may want 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. -You can easily do this with Spring Security's testing support using something like the following: +You can do so with Spring Security's testing support by using something like the following: +==== [source,java] ---- mvc .perform(formLogin().password("invalid")) .andExpect(unauthenticated()); ---- +==== ==== 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. -We could verify that a form based login was successful with the following snippet of code: +Often, you must assert that an authenticated user exists. +For example, you may want to verify that we authenticated successfully. +You could verify that a form-based login was successful: +==== [source,java] ---- mvc .perform(formLogin()) .andExpect(authenticated()); ---- +==== -If we wanted to assert the roles of the user, we could refine our previous code as shown below: +To assert the roles of the user, you can refine our previous code as follows: +==== [source,java] ---- mvc .perform(formLogin().user("admin")) .andExpect(authenticated().withRoles("USER","ADMIN")); ---- +==== -Alternatively, we could verify the username: +Similarly, you can verify the username: +==== [source,java] ---- mvc .perform(formLogin().user("admin")) .andExpect(authenticated().withUsername("admin")); ---- +==== -We can also combine the assertions: +You can also combine the assertions: +==== [source,java] ---- mvc .perform(formLogin().user("admin").roles("USER","ADMIN")) .andExpect(authenticated().withUsername("admin")); ---- +==== -We can also make arbitrary assertions on the authentication +We can also make arbitrary assertions on the authentication: +==== [source,java] ---- mvc @@ -997,3 +1136,4 @@ mvc .andExpect(authenticated().withAuthentication(auth -> assertThat(auth).isInstanceOf(UsernamePasswordAuthenticationToken.class))); ---- +==== diff --git a/docs/manual/src/docs/asciidoc/index.adoc b/docs/manual/src/docs/asciidoc/index.adoc index 3a5e250b75b..383d2e1c29f 100644 --- a/docs/manual/src/docs/asciidoc/index.adoc +++ b/docs/manual/src/docs/asciidoc/index.adoc @@ -6,8 +6,9 @@ Ben Alex; Luke Taylor; Rob Winch; Gunnar Hillert; Joe Grandja; Jay Bryant; Eddú :tabsize: 4 :toc: left -// FIXME: Add links for authentication, authorization, common attacks -Spring Security is a framework that provides authentication, authorization, and protection against common attacks. + +// FIXME: The current authorization link is for the servlet architecture. We need a reactive link, too. (On a deeper level, we need an authorization topic that accounts for both paths.) +Spring Security is a framework that provides <>, <>, and protection against <>. // FIXME: Add links for imperative and reactive applications With first class support for both imperative and reactive applications, it is the de-facto standard for securing Spring-based applications. @@ -16,5 +17,3 @@ include::{include-dir}/about/index.adoc[] include::{include-dir}/servlet/index.adoc[] include::{include-dir}/reactive/index.adoc[] - - From 0fdee9cdb8299e635d55d0d3fda74647701d7c32 Mon Sep 17 00:00:00 2001 From: Jay Bryant Date: Wed, 21 Apr 2021 16:09:17 -0500 Subject: [PATCH 2/7] Further changes A file changed while I was working on it, as the developers added more material for Kotlin. I edited the changes, to make everything be consistent. --- .../asciidoc/_includes/reactive/method.adoc | 23 +++++++------------ 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/docs/manual/src/docs/asciidoc/_includes/reactive/method.adoc b/docs/manual/src/docs/asciidoc/_includes/reactive/method.adoc index f2f60c3caaf..5f6b135c5d4 100644 --- a/docs/manual/src/docs/asciidoc/_includes/reactive/method.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/reactive/method.adoc @@ -4,9 +4,7 @@ Spring Security supports method security by using https://projectreactor.io/docs/core/release/reference/#context[Reactor's Context], which is set up by `ReactiveSecurityContextHolder`. The following example shows how to retrieve the currently logged in user's message: -[NOTE] -==== -For this to work the return type of the method must be a `org.reactivestreams.Publisher` (i.e. `Mono`/`Flux`) or the function must be a Kotlin coroutine function. +NOTE: For this example to work, the return type of the method must be a `org.reactivestreams.Publisher` (that is, a `Mono` or a `Flux`) or the function must be a Kotlin coroutine function. This is necessary to integrate with Reactor's `Context`. ==== @@ -26,7 +24,6 @@ StepVerifier.create(messageByUsername) .expectNext("Hi user") .verifyComplete(); ---- -==== .Kotlin [source,kotlin,role="secondary"] @@ -45,7 +42,7 @@ StepVerifier.create(messageByUsername) ---- ==== -with `this::findMessageByUsername` defined as: +Where `this::findMessageByUsername` is defined as: ==== .Java @@ -55,7 +52,6 @@ Mono findMessageByUsername(String username) { return Mono.just("Hi " + username); } ---- -==== .Kotlin [source,kotlin,role="secondary"] @@ -66,7 +62,7 @@ fun findMessageByUsername(username: String): Mono { ---- ==== -Below is a minimal method security configuration when using method security in reactive applications. +The following minimal method security configures method security in reactive applications: ==== .Java @@ -89,7 +85,6 @@ public class SecurityConfig { } } ---- -==== .Kotlin [source,kotlin,role="secondary"] @@ -127,7 +122,6 @@ public class HelloWorldMessageService { } } ---- -==== .Kotlin [source,kotlin,role="secondary"] @@ -142,7 +136,7 @@ class HelloWorldMessageService { ---- ==== -Or, the following class using Kotlin coroutines: +Alternatively, the following class uses Kotlin coroutines: ==== .Kotlin @@ -160,9 +154,9 @@ class HelloWorldMessageService { ==== -Combined with our configuration above, `@PreAuthorize("hasRole('ADMIN')")` will ensure that `findByMessage` is only invoked by a user with the role `ADMIN`. -It is important to note that any of the expressions in standard method security work for `@EnableReactiveMethodSecurity`. -However, at this time we only support return type of `Boolean` or `boolean` of the expression. +Combined with our configuration above, `@PreAuthorize("hasRole('ADMIN')")` ensures that `findByMessage` is invoked only by a user with the `ADMIN` role. +Note that any of the expressions in standard method security work for `@EnableReactiveMethodSecurity`. +However, at this time, we support only a return type of `Boolean` or `boolean` of the expression. This means that the expression must not block. When integrating with <>, the Reactor Context is automatically established by Spring Security according to the authenticated user: @@ -202,7 +196,6 @@ public class SecurityConfig { } } ---- -==== .Kotlin [source,kotlin,role="secondary"] @@ -237,4 +230,4 @@ class SecurityConfig { ---- ==== -You can find a complete sample in {gh-samples-url}/javaconfig/hellowebflux-method[hellowebflux-method] +You can find a complete sample in {gh-samples-url}/javaconfig/hellowebflux-method[hellowebflux-method]. From 849aaa4f3ea01f56d9fdcca7ec5b823d379d6aa2 Mon Sep 17 00:00:00 2001 From: Jay Bryant Date: Tue, 27 Apr 2021 15:36:17 -0500 Subject: [PATCH 3/7] Change to main The switch to main triggered some conflicts, which I have fixed in this commit. --- .../manual/src/docs/asciidoc/_includes/reactive/x509.adoc | 2 +- .../asciidoc/_includes/servlet/appendix/namespace.adoc | 8 ++++---- .../_includes/servlet/java-configuration/index.adoc | 2 +- .../_includes/servlet/kotlin-configuration/index.adoc | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/manual/src/docs/asciidoc/_includes/reactive/x509.adoc b/docs/manual/src/docs/asciidoc/_includes/reactive/x509.adoc index 515ae7533ea..a71fc814a29 100644 --- a/docs/manual/src/docs/asciidoc/_includes/reactive/x509.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/reactive/x509.adoc @@ -54,4 +54,4 @@ public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) { In the previous example, a username is extracted from the OU field of a client certificate instead of CN, and account lookup using `ReactiveUserDetailsService` is not performed at all. Instead, if the provided certificate issued to an OU named "`Trusted Org Unit`", a request is authenticated. -For an example of configuring Netty and `WebClient` or `curl` command-line tool to use mutual TLS and enable X.509 authentication, please refer to https://github.com/spring-projects/spring-security-samples/tree/main/servlet/java-configuration/authentication/x509. +For an example of configuring Netty and `WebClient` or `curl` command-line tool to use mutual TLS and enable X.509 authentication, see https://github.com/spring-projects/spring-security-samples/tree/main/servlet/java-configuration/authentication/x509. diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/appendix/namespace.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/appendix/namespace.adoc index 19d1dae7642..0904218ca84 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/appendix/namespace.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/appendix/namespace.adoc @@ -1,9 +1,9 @@ [[appendix-namespace]] == The Security Namespace -This appendix provides a reference to the elements available in the security namespace and information on the underlying beans they create (a knowledge of the individual classes and how they work together is assumed - you can find more information in the project Javadoc and elsewhere in this document). -If you haven't used the namespace before, please read the <> on namespace configuration, as this is intended as a supplement to the information there. -Using a good quality XML editor while editing a configuration based on the schema is recommended as this will provide contextual information on which elements and attributes are available as well as comments explaining their purpose. -The namespace is written in https://relaxng.org/[RELAX NG] Compact format and later converted into an XSD schema. +This appendix provides a reference to the elements available in the security namespace and information on the underlying beans they create (a knowledge of the individual classes and how they work together is assumed -- you can find more information in the project Javadoc and elsewhere in this document). +If you have not used the namespace before, read the <> on namespace configuration, as this appendix is intended as a supplement to the information there. +We recommend using a good XML editor while editing a configuration based on the schema is recommended, as doing so provides contextual information on which elements and attributes are available as well as comments explaining their purpose. +The namespace is written in https://relaxng.org/[RELAX NG] Compact format and then converted into an XSD schema. If you are familiar with this format, you may wish to examine the https://raw.githubusercontent.com/spring-projects/spring-security/main/config/src/main/resources/org/springframework/security/config/spring-security-4.1.rnc[schema file] directly. [[nsa-web]] diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/java-configuration/index.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/java-configuration/index.adoc index 56cff5437a7..7ffe185379f 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/java-configuration/index.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/java-configuration/index.adoc @@ -6,7 +6,7 @@ Spring Security 3.2 introduced Java configuration to let users configure Spring If you are familiar with the <>, you should find quite a few similarities between it and Spring Security Java configuration. -NOTE: Spring Security provides https://github.com/spring-projects/spring-security-samples/tree/main/servlet/java-configuration[lots of sample applications] which demonstrate the use of Spring Security Java Configuration. +NOTE: Spring Security provides https://github.com/spring-projects/spring-security-samples/tree/main/servlet/java-configuration[lots of sample applications] to demonstrate the use of Spring Security Java Configuration. == Hello Web Security Java Configuration diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/kotlin-configuration/index.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/kotlin-configuration/index.adoc index ab9a114e1ef..03dda38e48c 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/kotlin-configuration/index.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/kotlin-configuration/index.adoc @@ -4,7 +4,7 @@ Spring Security Kotlin configuration has been available since Spring Security 5.3. It lets users configure Spring Security by using a native Kotlin DSL. -NOTE: Spring Security provides https://github.com/spring-projects/spring-security-samples/tree/main/servlet/spring-boot/kotlin/hello-security[a sample application] which demonstrates the use of Spring Security Kotlin Configuration. +NOTE: Spring Security provides https://github.com/spring-projects/spring-security-samples/tree/main/servlet/spring-boot/kotlin/hello-security[a sample application] to demonstrate the use of Spring Security Kotlin Configuration. [[kotlin-config-httpsecurity]] == HttpSecurity From a6d071917743db2b22ad6b190602669597ec4906 Mon Sep 17 00:00:00 2001 From: Jay Bryant Date: Fri, 28 May 2021 12:03:16 -0500 Subject: [PATCH 4/7] Various fixes Fixes to make the build work. --- buildSrc/build.gradle | 4 +- .../asciidoc/_includes/reactive/rsocket.adoc | 4 +- .../_includes/reactive/webclient.adoc | 1 + .../_includes/servlet/appendix/namespace.adoc | 158 +++++++++--------- .../_includes/servlet/authorization/acls.adoc | 2 +- .../authorization/authorize-requests.adoc | 4 +- .../authorization/method-security.adoc | 5 +- .../servlet/java-configuration/index.adoc | 4 +- .../_includes/servlet/namespace/index.adoc | 2 +- .../servlet/oauth2/oauth2-login.adoc | 11 +- .../servlet/oauth2/oauth2-resourceserver.adoc | 2 +- .../_includes/servlet/test/mockmvc.adoc | 2 +- 12 files changed, 102 insertions(+), 97 deletions(-) diff --git a/buildSrc/build.gradle b/buildSrc/build.gradle index b75e9291a90..4574a8cb021 100644 --- a/buildSrc/build.gradle +++ b/buildSrc/build.gradle @@ -80,8 +80,8 @@ dependencies { implementation 'io.spring.gradle:propdeps-plugin:0.0.10.RELEASE' implementation 'io.spring.javaformat:spring-javaformat-gradle-plugin:0.0.15' implementation 'io.spring.nohttp:nohttp-gradle:0.0.8' - implementation 'org.asciidoctor:asciidoctor-gradle-jvm:3.1.0' - implementation 'org.asciidoctor:asciidoctor-gradle-jvm-pdf:3.1.0' + implementation 'org.asciidoctor:asciidoctor-gradle-jvm:3.3.0' + implementation 'org.asciidoctor:asciidoctor-gradle-jvm-pdf:3.3.0' implementation 'org.hidetake:gradle-ssh-plugin:2.10.1' implementation 'org.jfrog.buildinfo:build-info-extractor-gradle:4.9.10' implementation 'org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:2.7.1' diff --git a/docs/manual/src/docs/asciidoc/_includes/reactive/rsocket.adoc b/docs/manual/src/docs/asciidoc/_includes/reactive/rsocket.adoc index 822b0cd1a9c..d3b7eac685d 100644 --- a/docs/manual/src/docs/asciidoc/_includes/reactive/rsocket.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/reactive/rsocket.adoc @@ -16,7 +16,7 @@ The following example shows a minimal RSocket Security configuration: ==== [source,java] ------ +---- @Configuration @EnableRSocketSecurity public class HelloRSocketSecurityConfig { @@ -31,7 +31,7 @@ public class HelloRSocketSecurityConfig { return new MapReactiveUserDetailsService(user); } } ------ +---- ==== This configuration enables <> and sets up <> to require an authenticated user for any request. diff --git a/docs/manual/src/docs/asciidoc/_includes/reactive/webclient.adoc b/docs/manual/src/docs/asciidoc/_includes/reactive/webclient.adoc index 5de656a0e80..2ea6b412d2b 100644 --- a/docs/manual/src/docs/asciidoc/_includes/reactive/webclient.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/reactive/webclient.adoc @@ -1,3 +1,4 @@ +[[webclient]] = WebClient NOTE: The documentation in this section is for use within Reactive environments. diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/appendix/namespace.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/appendix/namespace.adoc index 0904218ca84..5281530d23c 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/appendix/namespace.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/appendix/namespace.adoc @@ -274,7 +274,7 @@ The default is false (the headers are enabled). [[nsa-headers-parents]] ===== Parent Elements of -The parent element of the `` element is the <`>> element. +The parent element of the `` element is the <> element. [[nsa-headers-children]] @@ -314,7 +314,7 @@ Default: `false`. [[nsa-cache-control-parents]] ===== Parent Elements of -The parent of the `` element is the <`>> element. +The parent of the `` element is the <> element. [[nsa-hsts]] @@ -358,7 +358,7 @@ Default: `false`. [[nsa-hsts-parents]] ===== Parent Elements of -The parent element of the `` element is the <`>> element. +The parent element of the `` element is the <> element. [[nsa-hpkp]] @@ -403,7 +403,7 @@ Specifies the URI to which the browser should report pin validation failures. [[nsa-hpkp-parents]] ===== Parent Elements of -The parent element of the element is the <`>> element. +The parent element of the element is the <> element. [[nsa-pins]] @@ -414,7 +414,7 @@ This section describes the attributes and child elements of the `` element [[nsa-pins-children]] ===== Child Elements of -The element has a single child element: <`>>. There can be multiple elements. +The element has a single child element: <>. There can be multiple elements. [[nsa-pin]] @@ -433,7 +433,7 @@ Default: SHA256. [[nsa-pin-parents]] ===== Parent Elements of -The parent element of the element is the <`>> element. +The parent element of the element is the <> element. @@ -459,7 +459,7 @@ Default: `false`. [[nsa-content-security-policy-parents]] ===== Parent Elements of -The parent element of the element is <`>>. +The parent element of the element is <>. @@ -480,7 +480,7 @@ Default: `no-referrer`. [[nsa-referrer-policy-parents]] ===== Parent Elements of -The parent element of the `` element is the <`>> element. +The parent element of the `` element is the <> element. @@ -500,7 +500,7 @@ The security policy directive(s) for the Feature-Policy header. [[nsa-feature-policy-parents]] ===== Parent Elements of -The parent element of the element is the <`>> element. +The parent element of the element is the <> element. @@ -533,7 +533,7 @@ On the other hand, if you specify `SAMEORIGIN`, you can still use the page in a [[nsa-frame-options-parents]] ===== Parent Elements of -The parent element of the `` element is the <`>> element. +The parent element of the `` element is the <> element. [[nsa-permissions-policy]] ==== @@ -583,7 +583,7 @@ Note that there are sometimes ways of bypassing this mode, which can often times [[nsa-xss-protection-parents]] ===== Parent Elements of -The parent element of the `` is the <`>> element. +The parent element of the `` is the <> element. @@ -606,7 +606,7 @@ Default: `false`. [[nsa-content-type-options-parents]] ===== Parent Elements of -The parent element of the `` element is the <`>> element. +The parent element of the `` element is the <> element. @@ -639,7 +639,7 @@ Reference to a custom implementation of the `HeaderWriter` interface. ===== Parent Elements of
-The parent element of the `
` is the <`>> element. +The parent element of the `
` is the <> element. @@ -652,7 +652,7 @@ This element is required if you use the `IS_AUTHENTICATED_ANONYMOUSLY` attribute [[nsa-anonymous-parents]] ===== Parent Elements of -The parent element of the `` element is the <`>> element. +The parent element of the `` element is the <> element. @@ -736,7 +736,7 @@ Full details can be found in the <>. [[nsa-custom-filter-parents]] ===== Parent Elements of -The parent element of the `` is the <`>> element. +The parent element of the `` is the <> element. @@ -811,7 +811,7 @@ The class `DefaultLoginPageGeneratingFilter` class is responsible for rendering ===== Parent Elements of -The parent element of the `` element is the <`>> element. +The parent element of the `` element is the <> element. @@ -901,7 +901,7 @@ The <> feature configures authentication support by [[nsa-oauth2-login-parents]] ===== Parent Elements of -The parent element of the `` element is the <`>> element. +The parent element of the `` element is the <> element. [[nsa-oauth2-login-attributes]] ===== Attributes @@ -986,7 +986,7 @@ Configures <> support. [[nsa-oauth2-client-parents]] ===== Parent Elements of -The parent of the `` is the <`>> element. +The parent of the `` is the <> element. [[nsa-oauth2-client-attributes]] ===== Attributes @@ -1011,7 +1011,7 @@ Reference to the `OAuth2AuthorizedClientService`. [[nsa-oauth2-client-children]] ===== Child Elements of -The `` has one child element: <`>>. +The `` has one child element: <>. [[nsa-authorization-code-grant]] @@ -1129,7 +1129,7 @@ The `` element contains the configuration information for an OAuth 2.0 [[nsa-provider-parents]] ===== Parent Elements of -The parent element of the `` element is the <`>> element. +The parent element of the `` element is the <> element. [[nsa-provider-attributes]] @@ -1186,15 +1186,15 @@ In addition, either `` or `` must be specified. [[nsa-oauth2-resource-server-parents]] ===== Parents Elements of -The parent element of the `` is the <`>> element. +The parent element of the `` is the <> element. [[nsa-oauth2-resource-server-children]] ===== Child Elements of The `` element has the following child elements: -* <`>> -* <`>> +* <> +* <> [[nsa-oauth2-resource-server-attributes]] ===== Attributes @@ -1221,7 +1221,7 @@ The `` element represents an OAuth 2.0 Resource Server that authorizes JWTs [[nsa-jwt-parents]] ===== Parent Elements of -The parent element of the `` element is the <`>> element. +The parent element of the `` element is the <> element. [[nsa-jwt-attributes]] @@ -1279,7 +1279,7 @@ The latter is used as the configuration entry point only if form-based login is ===== Parent Elements of -The parent element of the `` element is the <`>> element. +The parent element of the `` element is the <> element. @@ -1329,8 +1329,8 @@ So, the most specific patterns should come first and the most general should com The parent elements of the `` element are: -* <`>> -* <`>> +* <> +* <> [[nsa-intercept-url-attributes]] @@ -1393,7 +1393,7 @@ The `` element a dds a `J2eePreAuthenticatedProcessingFilter` to the filter [[nsa-jee-parents]] ===== Parent Elements of -The parent element of the `` element is the <`>> element. +The parent element of the `` element is the <> element. [[nsa-jee-attributes]] @@ -1420,7 +1420,7 @@ It is configured by a `SecurityContextLogoutHandler`. [[nsa-logout-parents]] ===== Parent Elements of -The parent element of the `` element is the <`>> element. +The parent element of the `` element is the <> element. [[nsa-logout-attributes]] @@ -1471,7 +1471,7 @@ You can specify this reference by `id`, by using the `user-service-ref` attribut [[nsa-openid-login-parents]] ===== Parent Elements of -The parent element of the `` element is the <`>> element. +The parent element of the `` element is the <> element. [[nsa-openid-login-attributes]] @@ -1556,7 +1556,7 @@ Default: `username` [[nsa-openid-login-children]] ===== Child Elements of -The `` element has only one child attribute: <`>>. +The `` element has only one child attribute: <>. [[nsa-attribute-exchange]] @@ -1570,7 +1570,7 @@ This lets different attribute lists be fetched from different providers (Google, [[nsa-attribute-exchange-parents]] ===== Parent Elements of -The parent element of the `` element is the <`>> element. +The parent element of the `` element is the <> element. [[nsa-attribute-exchange-attributes]] @@ -1587,7 +1587,7 @@ A regular expression that is compared against the claimed identity when deciding [[nsa-attribute-exchange-children]] ===== Child Elements of -The `` element has a single child attribute: <`>>. +The `` element has a single child attribute: <>. [[nsa-openid-attribute]] @@ -1641,7 +1641,7 @@ You can find an example of overriding these values in <>. [[nsa-port-mappings-parents]] ===== Parent Element of -The parent element of the `` element is the <`>> element. +The parent element of the `` element is the <> element. [[nsa-port-mappings-children]] @@ -1658,7 +1658,7 @@ The `` element provides a method to map HTTP ports to HTTPS ports [[nsa-port-mapping-parents]] ===== Parent Elements of -The parent element of the `` element is the <`>> element. +The parent element of the `` element is the <> element. @@ -1686,7 +1686,7 @@ This filter is, in turn, configured with either a `TokenBasedRememberMeServices` [[nsa-remember-me-parents]] ===== Parent Elements of -The parent element of the `` element is the <`>> element. +The parent element of the `` element is the <> element. [[nsa-remember-me-attributes]] @@ -1777,7 +1777,7 @@ Sets the `RequestCache` instance, which is used by the `ExceptionTranslationFilt [[nsa-request-cache-parents]] ===== Parent Elements of -The parent element of the `` element is the <`>> element. +The parent element of the `` element is the <> element. [[nsa-request-cache-attributes]] ===== Attributes @@ -1798,7 +1798,7 @@ Session-management functionality is implemented by the addition of a `SessionMan ===== Parent Elements of -The parent element of the `` element is the <`>> element. +The parent element of the `` element is the <> element. [[nsa-session-management-attributes]] @@ -1844,7 +1844,7 @@ See the {security-api-url}org/springframework/security/web/session/SessionManage [[nsa-session-management-children]] ===== Child Elements of -The `` element has only one child element: <`>> +The `` element has only one child element: <> [[nsa-concurrency-control]] @@ -1858,7 +1858,7 @@ An instance of `SessionRegistry` (a `SessionRegistryImpl` instance unless the us [[nsa-concurrency-control-parents]] ===== Parent Elements of -The parent element of the `` element is the <`>> element. +The parent element of the `` element is the <> element. [[nsa-concurrency-control-attributes]] @@ -1912,7 +1912,7 @@ A `PreAuthenticatedAuthenticationProvider` is also created. It delegates the loa [[nsa-x509-parents]] ===== Parent Elements of -The parent element of the `` element is the <`>> element. +The parent element of the `` element is the <> element. [[nsa-x509-attributes]] @@ -1956,7 +1956,7 @@ Currently, the options are `ant` (for Ant path patterns), `regex` (for regular e [[nsa-filter-chain-map-children]] ===== Child Elements of -The `` element has one child element: <`>>. +The `` element has one child element: <>. [[nsa-filter-chain]] @@ -1969,7 +1969,7 @@ When multiple `` elements are assembled in a list, to configure a [[nsa-filter-chain-parents]] ===== Parent Elements of -The parent element of the `` element is the <`>> element. +The parent element of the `` element is the <> element. [[nsa-filter-chain-attributes]] @@ -1985,7 +1985,7 @@ A value of `none` means that no `Filter` should be used for this `FilterChain`. [[nsa-filter-chain-pattern]] `pattern`:: -A pattern that creates `RequestMatcher` in combination with the <`>> element. +A pattern that creates `RequestMatcher` in combination with the <> element. [[nsa-filter-chain-request-matcher-ref]] @@ -2028,7 +2028,7 @@ If the expression evaluates to `true`, access is granted. [[nsa-filter-security-metadata-source-children]] ===== Child Elements of -The `` has a single child element: <`>>. +The `` has a single child element: <>. [[nsa-websocket-security]] === WebSocket Security @@ -2080,8 +2080,8 @@ Changing the default lets other origins make SockJS connections. The `` element has the following child elements: -* <`>> -* <`>> +* <> +* <> [[nsa-intercept-message]] ==== Element @@ -2161,8 +2161,8 @@ It is the same as the `alias` element but provides a more consistent experience The `` element has the following child elements: -* <`>> -* <`>> +* <> +* <> @@ -2176,7 +2176,7 @@ You can define the `UserDetailsService` instance either by using an available na [[nsa-authentication-provider-parents]] ===== Parent Elements of -The parent element of the `` element is the <`>> element. +The parent element of the `` element is the <> element. [[nsa-authentication-provider-attributes]] @@ -2213,10 +2213,10 @@ A reference to a bean that implements `UserDetailsService`, which may be created The `` element has the following child elements: -* <`>> -* <`>> -* <`>> -* <`>> +* <> +* <> +* <> +* <> [[nsa-jdbc-user-service]] @@ -2303,8 +2303,8 @@ Authentication providers can optionally be configured to use a password encoder, The `` element has the following parent elements: -* <`>> -* <`>> +* <> +* <> @@ -2355,7 +2355,7 @@ username=password,grantedAuthority[,grantedAuthority][,enabled|disabled] [[nsa-user-service-children]] ===== Child Element of -The `` element has a single child element: <`>>. +The `` element has a single child element: <>. Multiple `` elements can be present. @@ -2367,7 +2367,7 @@ The `` represents a user in the application. [[nsa-user-parents]] ===== Parent Element of -The parent element of the `` element is the <`>> element. +The parent element of the `` element is the <> element. [[nsa-user-attributes]] @@ -2505,10 +2505,10 @@ Default: `disabled` The `` has the following child elements: -* <`>> -* <`>> -* <`>> -* <`>> +* <> +* <> +* <> +* <> [[nsa-after-invocation-provider]] @@ -2520,7 +2520,7 @@ You can define zero or more of these elements within the `global-method-security [[nsa-after-invocation-provider-parents]] ===== Parent Elements of -The parent element of the `` is the <`>> element. +The parent element of the `` is the <> element. [[nsa-after-invocation-provider-attributes]] @@ -2542,7 +2542,7 @@ It applies only if these annotations are enabled. [[nsa-pre-post-annotation-handling-parents]] ===== Parent Elements of -The parent element of the `` element is the <`>> element. +The parent element of the `` element is the <> element. [[nsa-pre-post-annotation-handling-children]] @@ -2550,9 +2550,9 @@ The parent element of the `` element is the <` element has the following children: -* <`>> -* <`>> -* <`>> +* <> +* <> +* <> @@ -2585,7 +2585,7 @@ The `` element customizes the `PostInvocationAdviceProvi [[nsa-post-invocation-advice-parents]] ===== Parent Elements of -The parent element of the `` element is the <`>> element. +The parent element of the `` element is the <> element. [[nsa-post-invocation-advice-attributes]] @@ -2606,7 +2606,7 @@ The `` element customizes the `PreInvocationAuthorization [[nsa-pre-invocation-advice-parents]] ===== Parent Elements of -The parent element of the `` is the <`>> element. +The parent element of the `` is the <> element. [[nsa-pre-invocation-advice-attributes]] @@ -2628,7 +2628,7 @@ You can find an example in the <>. [[nsa-protect-pointcut-parents]] ===== Parent Elements of -The parent element of the `` element is the <`>> element. +The parent element of the `` element is the <> element. @@ -2666,7 +2666,7 @@ Optional `AccessDecisionManager` bean ID to be used by the created method securi [[nsa-intercept-methods-children]] ===== Child Elements of -The parent element of the `` is the <`>> element. +The parent element of the `` is the <> element. [[nsa-method-security-metadata-source]] @@ -2695,7 +2695,7 @@ If the expression evaluates to `true`, access is granted. [[nsa-method-security-metadata-source-children]] ===== Child Elements of -The `` has a single child element: <`>>. +The `` has a single child element: <>. [[nsa-protect]] @@ -2709,8 +2709,8 @@ We strongly advise you NOT to mix "`protect`" declarations with any services pro The `` element has two parent elements: -* <`>> -* <`>> +* <> +* <> [[nsa-protect-attributes]] @@ -2810,7 +2810,7 @@ As with all namespace authentication providers, it must be included as a child o [[nsa-ldap-authentication-provider-parents]] ===== Parent Elements of -The parent element of the `` is the <`>> element. +The parent element of the `` is the <> element. [[nsa-ldap-authentication-provider-attributes]] @@ -2897,7 +2897,7 @@ If these attributes are not set and no `user-dn-pattern` has been supplied as an [[nsa-ldap-authentication-provider-children]] ===== Child Elements of -The `` has a single child element: <`>>. +The `` has a single child element: <>. [[nsa-password-compare]] @@ -2908,7 +2908,7 @@ The `` element is used as a child element to `` [[nsa-password-compare-parents]] ===== Parent Elements of -The parent element of the `` element is the <`>> element. +The parent element of the `` element is the <> element. [[nsa-password-compare-attributes]] @@ -2931,7 +2931,7 @@ Default: `userPassword` [[nsa-password-compare-children]] ===== Child Elements of -The `` element has a single child element: <`>>. +The `` element has a single child element: <>. [[nsa-ldap-user-service]] @@ -3003,7 +3003,7 @@ If set, the framework tries to load standard attributes for the defined class in [[nsa-ldap-user-service-user-search-base]] `user-search-base`:: Search base for user searches. -It is used only with a <`>> element. +It is used only with a <> element. Default: `""` diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authorization/acls.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authorization/acls.adoc index f55f59ec1b7..446a44b89c9 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/authorization/acls.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authorization/acls.adoc @@ -57,7 +57,7 @@ The tables are presented in order of size in a typical Spring Security ACL deplo [[acl_tables]] * `ACL_SID` lets us uniquely identify any principal or authority in the system ("`SID`" stands for "`Security IDentity`"). -The only columns are the ID, a textual representation of the SID, and a flag to indicate whether the textual representation refers to a principal name or a `GrantedAuthority`. +The only columns are the ID, a textual representation of the SID, and a flag to indicate whether the textual representation refers to a principal name or a `GrantedAuthority`. Thus, there is a single row for each unique principal or `GrantedAuthority`. When used in the context of receiving a permission, an SID is generally called a "`recipient`". diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authorization/authorize-requests.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authorization/authorize-requests.adoc index 48ad3a3e158..3c58059f4a4 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/authorization/authorize-requests.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authorization/authorize-requests.adoc @@ -73,7 +73,7 @@ We can configure Spring Security to have different rules by adding more rules in protected void configure(HttpSecurity http) throws Exception { http // ... - .authorizeRequests(authorize -> authorize // <1> + .authorizeRequests(authorize -> authorize // <1> .mvcMatchers("/resources/**", "/signup", "/about").permitAll() // <2> .mvcMatchers("/admin/**").hasRole("ADMIN") // <3> .mvcMatchers("/db/**").access("hasRole('ADMIN') and hasRole('DBA')") // <4> @@ -115,7 +115,6 @@ fun configure(http: HttpSecurity) { } } ---- -==== <1> Multiple authorization rules are specified. Each rule is considered in the order in which it is declared. <2> Specify multiple URL patterns that any user can access. @@ -126,3 +125,4 @@ Notice that, since we invoke the `hasRole` method, we need not specify the `ROLE Notice that, since we use the `hasRole` expression, we need not specify the `ROLE_` prefix. <5> Any URL that has not already been matched is denied access. This is a good strategy if you do not want to accidentally forget to update your authorization rules. +==== diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authorization/method-security.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authorization/method-security.adoc index 859b5f27ce7..a80fd7f9d64 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/authorization/method-security.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authorization/method-security.adoc @@ -20,10 +20,7 @@ This simplifies reuse and customization. 5. Complies with JSR-250 6. Enables `@PreAuthorize`, `@PostAuthorize`, `@PreFilter`, and `@PostFilter` by default -[NOTE] -==== -For earlier versions, please read about similar support with <>. -==== +NOTE: For earlier versions, please read about similar support with <>. For example, the following would enable Spring Security's `@PreAuthorize` annotation: diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/java-configuration/index.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/java-configuration/index.adoc index 7ffe185379f..a53ce7937b7 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/java-configuration/index.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/java-configuration/index.adoc @@ -8,13 +8,13 @@ If you are familiar with the <>, you should find quite a few similari NOTE: Spring Security provides https://github.com/spring-projects/spring-security-samples/tree/main/servlet/java-configuration[lots of sample applications] to demonstrate the use of Spring Security Java Configuration. +[[jc-hello-wsca]] == Hello Web Security Java Configuration The first step is to create our Spring Security Java Configuration. The configuration creates a Servlet Filter known as the `springSecurityFilterChain`, which is responsible for all the security (protecting the application URLs, validating submitted username and passwords, redirecting to the log in form, and so on) within your application. The following example shows the most basic example of a Spring Security Java Configuration: -[[jc-hello-wsca]] ==== [source,java] ---- @@ -68,6 +68,7 @@ The way in which we use `AbstractSecurityWebApplicationInitializer` differs depe * <> - Use these instructions if you are not already using Spring * <> - Use these instructions if you are already using Spring +[[abstractsecuritywebapplicationinitializer-without-existing-spring]] === AbstractSecurityWebApplicationInitializer without Existing Spring If you are not using Spring or Spring MVC, you need to pass the `WebSecurityConfig` to the superclass to ensure the configuration is picked up: @@ -92,6 +93,7 @@ The `SecurityWebApplicationInitializer`: * Automatically registers the `springSecurityFilterChain` Filter for every URL in your application. * Add a `ContextLoaderListener` that loads the <>. +[[abstractsecuritywebapplicationinitializer-with-spring-mvc]] === AbstractSecurityWebApplicationInitializer with Spring MVC If we use Spring elsewhere in our application, we probably already have a `WebApplicationInitializer` that is loading our Spring Configuration. diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/namespace/index.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/namespace/index.adoc index fc427d14ccf..85a56c47477 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/namespace/index.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/namespace/index.adoc @@ -62,7 +62,7 @@ xsi:schemaLocation="http://www.springframework.org/schema/beans We assume this syntax is being used from now on in this chapter. -=== Design of the Namespace +== Design of the Namespace The namespace is designed to capture the most common uses of the framework and provide a simplified and concise syntax for enabling them within an application. The design is based around the large-scale dependencies within the framework and can be divided up into the following areas: diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/oauth2/oauth2-login.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/oauth2/oauth2-login.adoc index b8fc76df6ea..e2cd5bdde1e 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/oauth2/oauth2-login.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/oauth2/oauth2-login.adoc @@ -1395,8 +1395,9 @@ spring: Also, you can configure `OidcClientInitiatedLogoutSuccessHandler`, which implements RP-Initiated Logout, as follows: -==== + .Java +==== [source,java,role="primary"] ---- @EnableWebSecurity @@ -1430,11 +1431,14 @@ public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter { } ---- +==== +[subs="none"] NOTE: `OidcClientInitiatedLogoutSuccessHandler` supports the `{baseUrl}` placeholder. If used, the application's base URL, such as `https://app.example.org`, replaces it at request time. .Kotlin +==== [source,kotlin,role="secondary"] ---- @EnableWebSecurity @@ -1463,8 +1467,9 @@ class OAuth2LoginSecurityConfig : WebSecurityConfigurerAdapter() { return oidcLogoutSuccessHandler } } - ---- +==== + +[subs="none"] NOTE: `OidcClientInitiatedLogoutSuccessHandler` supports the `{baseUrl}` placeholder. If used, the application's base URL, such as `https://app.example.org`, replaces it at request time. -==== diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/oauth2/oauth2-resourceserver.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/oauth2/oauth2-resourceserver.adoc index e284f1874d2..e51364d40a2 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/oauth2/oauth2-resourceserver.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/oauth2/oauth2-resourceserver.adoc @@ -1,4 +1,4 @@ -NML.[[oauth2resourceserver]] +[[oauth2resourceserver]] == OAuth 2.0 Resource Server :figures: images/servlet/oauth2 :icondir: images/icons diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/test/mockmvc.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/test/mockmvc.adoc index 6a8e3712b19..aa380f4b33d 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/test/mockmvc.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/test/mockmvc.adoc @@ -219,7 +219,7 @@ mvc [[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 the annotations described in <>. +As an alternative to using a `RequestPostProcessor` to create your user, you can use the annotations described in <>. The following example runs the test with a user whose username is `user`, whose password is `password`, and whose role is `ROLE_USER`: ==== From 93893ded53a1398611cce5dfa0d48ac382f6cd5a Mon Sep 17 00:00:00 2001 From: Jay Bryant Date: Wed, 2 Jun 2021 11:49:49 -0500 Subject: [PATCH 5/7] Accounted for feedback Incorporated suggested changes from a review. --- 0001-master-main.patch | 254 - ...kie-secure-flag-configurable-WebFlux.patch | 271 - 0003-Editing-pass.patch | 23196 ---------------- .../authentication/password-storage.adoc | 6 +- .../_includes/about/exploits/headers.adoc | 2 +- .../servlet/authentication/unpwd/form.adoc | 14 +- .../servlet/kotlin-configuration/index.adoc | 5 +- .../servlet/oauth2/oauth2-resourceserver.adoc | 6 +- 8 files changed, 16 insertions(+), 23738 deletions(-) delete mode 100644 0001-master-main.patch delete mode 100644 0002-Make-Csrf-cookie-secure-flag-configurable-WebFlux.patch delete mode 100644 0003-Editing-pass.patch diff --git a/0001-master-main.patch b/0001-master-main.patch deleted file mode 100644 index 943b460b697..00000000000 --- a/0001-master-main.patch +++ /dev/null @@ -1,254 +0,0 @@ -From 006b9b960797d279b31cf8c8d16f1549c5632b2c Mon Sep 17 00:00:00 2001 -From: Rob Winch -Date: Mon, 26 Apr 2021 16:50:35 -0500 -Subject: [PATCH 1/3] master->main - -Closes gh-9683 ---- - .github/workflows/continuous-integration-workflow.yml | 10 +++++----- - CONTRIBUTING.adoc | 6 +++--- - README.adoc | 6 +++--- - .../org/springframework/gradle/sagan/SaganApi.java | 2 +- - docs/guides/spring-security-docs-guides.gradle | 2 +- - docs/guides/src/docs/asciidoc/Guardfile | 2 +- - docs/manual/spring-security-docs-manual.gradle | 2 +- - .../src/docs/asciidoc/_includes/about/community.adoc | 2 +- - .../src/docs/asciidoc/_includes/reactive/x509.adoc | 2 +- - .../asciidoc/_includes/servlet/appendix/namespace.adoc | 2 +- - .../_includes/servlet/integrations/servlet-api.adoc | 1 - - .../_includes/servlet/integrations/websocket.adoc | 2 -- - .../_includes/servlet/java-configuration/index.adoc | 2 +- - .../_includes/servlet/kotlin-configuration/index.adoc | 2 +- - 14 files changed, 20 insertions(+), 23 deletions(-) - -diff --git a/.github/workflows/continuous-integration-workflow.yml b/.github/workflows/continuous-integration-workflow.yml -index 58358c6e59..65201e4596 100644 ---- a/.github/workflows/continuous-integration-workflow.yml -+++ b/.github/workflows/continuous-integration-workflow.yml -@@ -3,7 +3,7 @@ name: CI - on: - push: - branches: -- - master -+ - main - schedule: - - cron: '0 10 * * *' # Once per day at 10am UTC - workflow_dispatch: # Manual trigger -@@ -102,16 +102,16 @@ jobs: - uses: actions/setup-java@v1 - with: - java-version: '11' -- - name: Run Sonar on given (non-master) branch -- if: ${{ github.ref != 'refs/heads/master' }} -+ - name: Run Sonar on given (non-main) branch -+ if: ${{ github.ref != 'refs/heads/main' }} - run: | - export BRANCH=${GITHUB_REF#refs/heads/} - export GRADLE_ENTERPRISE_CACHE_USERNAME="$GRADLE_ENTERPRISE_CACHE_USER" - export GRADLE_ENTERPRISE_CACHE_PASSWORD="$GRADLE_ENTERPRISE_CACHE_PASSWORD" - export GRADLE_ENTERPRISE_ACCESS_KEY="$GRADLE_ENTERPRISE_SECRET_ACCESS_KEY" - ./gradlew sonarqube -PartifactoryUsername="$ARTIFACTORY_USERNAME" -PartifactoryPassword="$ARTIFACTORY_PASSWORD" -PexcludeProjects='**/samples/**' -Dsonar.projectKey="spring-security-${GITHUB_REF#refs/heads/}" -Dsonar.projectName="spring-security-${GITHUB_REF#refs/heads/}" -Dsonar.host.url="$SONAR_URL" -Dsonar.login="$SONAR_TOKEN" --stacktrace -- - name: Run Sonar on master -- if: ${{ github.ref == 'refs/heads/master' }} -+ - name: Run Sonar on main -+ if: ${{ github.ref == 'refs/heads/main' }} - run: | - export GRADLE_ENTERPRISE_CACHE_USERNAME="$GRADLE_ENTERPRISE_CACHE_USER" - export GRADLE_ENTERPRISE_CACHE_PASSWORD="$GRADLE_ENTERPRISE_CACHE_PASSWORD" -diff --git a/CONTRIBUTING.adoc b/CONTRIBUTING.adoc -index e951f69040..0599fb99ec 100644 ---- a/CONTRIBUTING.adoc -+++ b/CONTRIBUTING.adoc -@@ -4,7 +4,7 @@ _Please refer back to this document as a checklist before issuing any pull reque - - = Code of Conduct - --Please see our https://github.com/spring-projects/.github/blob/master/CODE_OF_CONDUCT.md[code of conduct]. -+Please see our https://github.com/spring-projects/.github/blob/main/CODE_OF_CONDUCT.md[code of conduct]. - - = Similar but different - -@@ -43,9 +43,9 @@ If you're considering anything more than correcting a typo or fixing a minor bug - - If you have not previously done so, please fill out and submit the https://cla.pivotal.io/sign/spring[Contributor License Agreement]. - --= Create your branch from master -+= Create your branch from main - --Create your topic branch to be submitted as a pull request from master. The Spring team will consider your pull request for backporting on a case-by-case basis; you don't need to worry about submitting anything for backporting. -+Create your topic branch to be submitted as a pull request from main. The Spring team will consider your pull request for backporting on a case-by-case basis; you don't need to worry about submitting anything for backporting. - - = Use short branch names - -diff --git a/README.adoc b/README.adoc -index 4fda007d1a..6cb3f95061 100644 ---- a/README.adoc -+++ b/README.adoc -@@ -1,6 +1,6 @@ - image::https://badges.gitter.im/Join%20Chat.svg[Gitter,link=https://gitter.im/spring-projects/spring-security?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge] - --image:https://github.com/spring-projects/spring-security/workflows/CI/badge.svg?branch=master["Build Status", link="https://github.com/spring-projects/spring-security/actions?query=workflow%3ACI"] -+image:https://github.com/spring-projects/spring-security/workflows/CI/badge.svg?branch=main["Build Status", link="https://github.com/spring-projects/spring-security/actions?query=workflow%3ACI"] - - image:https://img.shields.io/badge/Revved%20up%20by-Gradle%20Enterprise-06A0CE?logo=Gradle&labelColor=02303A["Revved up by Gradle Enterprise", link="https://ge.spring.io/scans?search.rootProjectNames=spring-security"] - -@@ -12,7 +12,7 @@ a minimum and also requires Java 8. - For a detailed list of features and access to the latest release, please visit https://spring.io/projects[Spring projects]. - - == Code of Conduct --Please see our https://github.com/spring-projects/.github/blob/master/CODE_OF_CONDUCT.md[code of conduct] -+Please see our https://github.com/spring-projects/.github/blob/main/CODE_OF_CONDUCT.md[code of conduct] - - == Downloading Artifacts - See https://docs.spring.io/spring-security/site/docs/current/reference/html5/#getting[Getting Spring Security] for how to obtain Spring Security. -@@ -60,7 +60,7 @@ Check out the https://stackoverflow.com/questions/tagged/spring-security[Spring - https://spring.io/services[Commercial support] is available too. - - == Contributing --https://help.github.com/articles/creating-a-pull-request[Pull requests] are welcome; see the https://github.com/spring-projects/spring-security/blob/master/CONTRIBUTING.adoc[contributor guidelines] for details. -+https://help.github.com/articles/creating-a-pull-request[Pull requests] are welcome; see the https://github.com/spring-projects/spring-security/blob/main/CONTRIBUTING.adoc[contributor guidelines] for details. - - == License - Spring Security is Open Source software released under the -diff --git a/buildSrc/src/main/java/org/springframework/gradle/sagan/SaganApi.java b/buildSrc/src/main/java/org/springframework/gradle/sagan/SaganApi.java -index d40f296c20..24eeb3111c 100644 ---- a/buildSrc/src/main/java/org/springframework/gradle/sagan/SaganApi.java -+++ b/buildSrc/src/main/java/org/springframework/gradle/sagan/SaganApi.java -@@ -23,7 +23,7 @@ import java.io.IOException; - import java.util.Base64; - - /** -- * Implements necessary calls to the Sagan API See https://github.com/spring-io/sagan/blob/master/sagan-site/src/docs/asciidoc/index.adoc -+ * Implements necessary calls to the Sagan API See https://spring.io/restdocs/index.html - */ - public class SaganApi { - private String baseUrl = "https://spring.io/api"; -diff --git a/docs/guides/spring-security-docs-guides.gradle b/docs/guides/spring-security-docs-guides.gradle -index 6c337c030a..8876dddd93 100644 ---- a/docs/guides/spring-security-docs-guides.gradle -+++ b/docs/guides/spring-security-docs-guides.gradle -@@ -28,7 +28,7 @@ ext.spec = copySpec { - } - - def getDownloadUrl() { -- snapshotBuild ? "https://github.com/spring-projects/spring-security/archive/master.zip" : "https://github.com/spring-projects/spring-security/archive/${project.version}.zip" -+ snapshotBuild ? "https://github.com/spring-projects/spring-security/archive/main.zip" : "https://github.com/spring-projects/spring-security/archive/${project.version}.zip" - } - - -diff --git a/docs/guides/src/docs/asciidoc/Guardfile b/docs/guides/src/docs/asciidoc/Guardfile -index ec57b640f2..1075c0114c 100644 ---- a/docs/guides/src/docs/asciidoc/Guardfile -+++ b/docs/guides/src/docs/asciidoc/Guardfile -@@ -5,7 +5,7 @@ guard 'shell' do - watch(/^.*\.asc$/) {|m| - Asciidoctor.render_file(m[0], :to_dir => "build/", :safe => Asciidoctor::SafeMode::UNSAFE, :attributes=> {'toc' => '', 'idprefix' => '', 'idseparator' => '-', 'copycss' => '', 'icons' => 'font', 'source-highlighter' => 'prettify', 'sectanchors' => '', 'toc-placement' => 'preamble', 'revnumber' => '3.2.0.CI-SNAPSHOT', - 'spring-security-version' => '3.2.0.CI-SNAPSHOT', -- 'download-url' => 'https://github.com/spring-projects/spring-security/archive/master.zip', -+ 'download-url' => 'https://github.com/spring-projects/spring-security/archive/main.zip', - 'include-maven-repository' => '_includes/maven-repository-snapshot.asc' }) - } - end -diff --git a/docs/manual/spring-security-docs-manual.gradle b/docs/manual/spring-security-docs-manual.gradle -index a0a2ececd9..75c245f7de 100644 ---- a/docs/manual/spring-security-docs-manual.gradle -+++ b/docs/manual/spring-security-docs-manual.gradle -@@ -14,7 +14,7 @@ asciidoctor { - } - - asciidoctorj { -- def ghTag = snapshotBuild ? 'master' : project.version -+ def ghTag = snapshotBuild ? 'main' : project.version - def ghUrl = "https://github.com/spring-projects/spring-security/tree/$ghTag" - attributes 'spring-security-version' : project.version, - 'spring-boot-version' : springBootVersion, -diff --git a/docs/manual/src/docs/asciidoc/_includes/about/community.adoc b/docs/manual/src/docs/asciidoc/_includes/about/community.adoc -index dc83c0c68c..893d17727b 100644 ---- a/docs/manual/src/docs/asciidoc/_includes/about/community.adoc -+++ b/docs/manual/src/docs/asciidoc/_includes/about/community.adoc -@@ -19,7 +19,7 @@ The following are some of the best ways to get help: - == Becoming Involved - We welcome your involvement in the Spring Security project. - There are many ways to contribute, including answering questions on Stack Overflow, writing new code, improving existing code, assisting with documentation, developing samples or tutorials, reporting bugs, or simply making suggestions. --For more information, see our https://github.com/spring-projects/spring-security/blob/master/CONTRIBUTING.adoc[Contributing] documentation. -+For more information, see our https://github.com/spring-projects/spring-security/blob/main/CONTRIBUTING.adoc[Contributing] documentation. - - [[community-source]] - == Source Code -diff --git a/docs/manual/src/docs/asciidoc/_includes/reactive/x509.adoc b/docs/manual/src/docs/asciidoc/_includes/reactive/x509.adoc -index 4dc59526cc..694b905093 100644 ---- a/docs/manual/src/docs/asciidoc/_includes/reactive/x509.adoc -+++ b/docs/manual/src/docs/asciidoc/_includes/reactive/x509.adoc -@@ -49,4 +49,4 @@ public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) { - - In this example, a username is extracted from the OU field of a client certificate instead of CN, and account lookup using `ReactiveUserDetailsService` is not performed at all. Instead, if the provided certificate issued to an OU named "Trusted Org Unit", a request will be authenticated. - --For an example of configuring Netty and `WebClient` or `curl` command-line tool to use mutual TLS and enable X.509 authentication, please refer to https://github.com/spring-projects/spring-security/tree/master/samples/boot/webflux-x509. -+For an example of configuring Netty and `WebClient` or `curl` command-line tool to use mutual TLS and enable X.509 authentication, please refer to https://github.com/spring-projects/spring-security-samples/tree/main/servlet/java-configuration/authentication/x509. -diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/appendix/namespace.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/appendix/namespace.adoc -index a9e321ff59..87d802ca8e 100644 ---- a/docs/manual/src/docs/asciidoc/_includes/servlet/appendix/namespace.adoc -+++ b/docs/manual/src/docs/asciidoc/_includes/servlet/appendix/namespace.adoc -@@ -4,7 +4,7 @@ This appendix provides a reference to the elements available in the security nam - If you haven't used the namespace before, please read the <> on namespace configuration, as this is intended as a supplement to the information there. - Using a good quality XML editor while editing a configuration based on the schema is recommended as this will provide contextual information on which elements and attributes are available as well as comments explaining their purpose. - The namespace is written in https://relaxng.org/[RELAX NG] Compact format and later converted into an XSD schema. --If you are familiar with this format, you may wish to examine the https://raw.githubusercontent.com/spring-projects/spring-security/master/config/src/main/resources/org/springframework/security/config/spring-security-4.1.rnc[schema file] directly. -+If you are familiar with this format, you may wish to examine the https://raw.githubusercontent.com/spring-projects/spring-security/main/config/src/main/resources/org/springframework/security/config/spring-security-4.1.rnc[schema file] directly. - - [[nsa-web]] - === Web Application Security -diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/servlet-api.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/servlet-api.adoc -index e57d545c15..5e4077c3f9 100644 ---- a/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/servlet-api.adoc -+++ b/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/servlet-api.adoc -@@ -1,7 +1,6 @@ - [[servletapi]] - == Servlet API integration - This section describes how Spring Security is integrated with the Servlet API. --The https://github.com/spring-projects/spring-security/tree/master/samples/xml/servletapi[servletapi-xml] sample application demonstrates the usage of each of these methods. - - - [[servletapi-25]] -diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/websocket.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/websocket.adoc -index fcd99840d9..ffcf46b5a4 100644 ---- a/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/websocket.adoc -+++ b/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/websocket.adoc -@@ -4,8 +4,6 @@ - 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. - --NOTE: You can find a complete working sample of WebSocket security at https://github.com/spring-projects/spring-session/tree/master/spring-session-samples/spring-session-sample-boot-websocket. -- - .Direct JSR-356 Support - **** - Spring Security does not provide direct JSR-356 support because doing so would provide little value. -diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/java-configuration/index.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/java-configuration/index.adoc -index 6367f402f6..3ba5432ddc 100644 ---- a/docs/manual/src/docs/asciidoc/_includes/servlet/java-configuration/index.adoc -+++ b/docs/manual/src/docs/asciidoc/_includes/servlet/java-configuration/index.adoc -@@ -7,7 +7,7 @@ Since Spring Security 3.2 there has been Spring Security Java Configuration supp - - If you are familiar with the <> then you should find quite a few similarities between it and the Security Java Configuration support. - --NOTE: Spring Security provides https://github.com/spring-projects/spring-security/tree/master/samples/javaconfig[lots of sample applications] which demonstrate the use of Spring Security Java Configuration. -+NOTE: Spring Security provides https://github.com/spring-projects/spring-security-samples/tree/main/servlet/java-configuration[lots of sample applications] which demonstrate the use of Spring Security Java Configuration. - - == Hello Web Security Java Configuration - -diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/kotlin-configuration/index.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/kotlin-configuration/index.adoc -index 2e38e0ec35..767ab7ed80 100644 ---- a/docs/manual/src/docs/asciidoc/_includes/servlet/kotlin-configuration/index.adoc -+++ b/docs/manual/src/docs/asciidoc/_includes/servlet/kotlin-configuration/index.adoc -@@ -4,7 +4,7 @@ - Spring Security Kotlin Configuration support has been available since Spring Security 5.3. - It enables users to easily configure Spring Security using a native Kotlin DSL. - --NOTE: Spring Security provides https://github.com/spring-projects/spring-security/tree/master/samples/boot/kotlin[a sample application] which demonstrates the use of Spring Security Kotlin Configuration. -+NOTE: Spring Security provides https://github.com/spring-projects/spring-security-samples/tree/main/servlet/spring-boot/kotlin/hello-security[a sample application] which demonstrates the use of Spring Security Kotlin Configuration. - - [[kotlin-config-httpsecurity]] - == HttpSecurity --- -2.24.1 - diff --git a/0002-Make-Csrf-cookie-secure-flag-configurable-WebFlux.patch b/0002-Make-Csrf-cookie-secure-flag-configurable-WebFlux.patch deleted file mode 100644 index 7f2cb6a5d32..00000000000 --- a/0002-Make-Csrf-cookie-secure-flag-configurable-WebFlux.patch +++ /dev/null @@ -1,271 +0,0 @@ -From e2993d93e109c1a3c9020b7ea9efb6e556751ed4 Mon Sep 17 00:00:00 2001 -From: Thomas Vitale -Date: Mon, 26 Apr 2021 18:13:20 +0200 -Subject: [PATCH 2/3] Make Csrf cookie secure flag configurable (WebFlux) - -Make the XSRF-TOKEN cookie secure flag configurable in CookieServerCsrfTokenRepository. - -Closes gh-9678 ---- - .../csrf/CookieServerCsrfTokenRepository.java | 30 ++++-- - .../CookieServerCsrfTokenRepositoryTests.java | 100 ++++++++++++++++-- - 2 files changed, 113 insertions(+), 17 deletions(-) - -diff --git a/web/src/main/java/org/springframework/security/web/server/csrf/CookieServerCsrfTokenRepository.java b/web/src/main/java/org/springframework/security/web/server/csrf/CookieServerCsrfTokenRepository.java -index 5910ff3e45..bc3a20e711 100644 ---- a/web/src/main/java/org/springframework/security/web/server/csrf/CookieServerCsrfTokenRepository.java -+++ b/web/src/main/java/org/springframework/security/web/server/csrf/CookieServerCsrfTokenRepository.java -@@ -1,5 +1,5 @@ - /* -- * Copyright 2002-2019 the original author or authors. -+ * Copyright 2002-2021 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. -@@ -34,6 +34,7 @@ import org.springframework.web.server.ServerWebExchange; - * AngularJS. When using with AngularJS be sure to use {@link #withHttpOnlyFalse()} . - * - * @author Eric Deandrea -+ * @author Thomas Vitale - * @since 5.1 - */ - public final class CookieServerCsrfTokenRepository implements ServerCsrfTokenRepository { -@@ -54,6 +55,8 @@ public final class CookieServerCsrfTokenRepository implements ServerCsrfTokenRep - - private boolean cookieHttpOnly = true; - -+ private Boolean secure; -+ - /** - * Factory method to conveniently create an instance that has - * {@link #setCookieHttpOnly(boolean)} set to false. -@@ -75,11 +78,16 @@ public final class CookieServerCsrfTokenRepository implements ServerCsrfTokenRep - public Mono saveToken(ServerWebExchange exchange, CsrfToken token) { - return Mono.fromRunnable(() -> { - String tokenValue = (token != null) ? token.getToken() : ""; -- int maxAge = !tokenValue.isEmpty() ? -1 : 0; -- String path = (this.cookiePath != null) ? this.cookiePath : getRequestContext(exchange.getRequest()); -- boolean secure = exchange.getRequest().getSslInfo() != null; -- ResponseCookie cookie = ResponseCookie.from(this.cookieName, tokenValue).domain(this.cookieDomain) -- .httpOnly(this.cookieHttpOnly).maxAge(maxAge).path(path).secure(secure).build(); -+ // @formatter:off -+ ResponseCookie cookie = ResponseCookie -+ .from(this.cookieName, tokenValue) -+ .domain(this.cookieDomain) -+ .httpOnly(this.cookieHttpOnly) -+ .maxAge(!tokenValue.isEmpty() ? -1 : 0) -+ .path((this.cookiePath != null) ? this.cookiePath : getRequestContext(exchange.getRequest())) -+ .secure((this.secure != null) ? this.secure : (exchange.getRequest().getSslInfo() != null)) -+ .build(); -+ // @formatter:on - exchange.getResponse().addCookie(cookie); - }); - } -@@ -146,6 +154,16 @@ public final class CookieServerCsrfTokenRepository implements ServerCsrfTokenRep - this.cookieDomain = cookieDomain; - } - -+ /** -+ * Sets the cookie secure flag. If not set, the value depends on -+ * {@link ServerHttpRequest#getSslInfo()}. -+ * @param secure The value for the secure flag -+ * @since 5.5 -+ */ -+ public void setSecure(boolean secure) { -+ this.secure = secure; -+ } -+ - private CsrfToken createCsrfToken() { - return createCsrfToken(createNewToken()); - } -diff --git a/web/src/test/java/org/springframework/security/web/server/csrf/CookieServerCsrfTokenRepositoryTests.java b/web/src/test/java/org/springframework/security/web/server/csrf/CookieServerCsrfTokenRepositoryTests.java -index d16f131920..7160337053 100644 ---- a/web/src/test/java/org/springframework/security/web/server/csrf/CookieServerCsrfTokenRepositoryTests.java -+++ b/web/src/test/java/org/springframework/security/web/server/csrf/CookieServerCsrfTokenRepositoryTests.java -@@ -1,5 +1,5 @@ - /* -- * Copyright 2002-2018 the original author or authors. -+ * Copyright 2002-2021 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. -@@ -16,12 +16,15 @@ - - package org.springframework.security.web.server.csrf; - -+import java.security.cert.X509Certificate; - import java.time.Duration; - -+import org.junit.Before; - import org.junit.Test; - - import org.springframework.http.HttpCookie; - import org.springframework.http.ResponseCookie; -+import org.springframework.http.server.reactive.SslInfo; - import org.springframework.mock.http.server.reactive.MockServerHttpRequest; - import org.springframework.mock.web.server.MockServerWebExchange; - import org.springframework.util.StringUtils; -@@ -30,13 +33,14 @@ import static org.assertj.core.api.Assertions.assertThat; - - /** - * @author Eric Deandrea -+ * @author Thomas Vitale - * @since 5.1 - */ - public class CookieServerCsrfTokenRepositoryTests { - -- private MockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get("/someUri")); -+ private CookieServerCsrfTokenRepository csrfTokenRepository; - -- private CookieServerCsrfTokenRepository csrfTokenRepository = new CookieServerCsrfTokenRepository(); -+ private MockServerHttpRequest.BaseBuilder request; - - private String expectedHeaderName = CookieServerCsrfTokenRepository.DEFAULT_CSRF_HEADER_NAME; - -@@ -56,6 +60,12 @@ public class CookieServerCsrfTokenRepositoryTests { - - private String expectedCookieValue = "csrfToken"; - -+ @Before -+ public void setUp() { -+ this.csrfTokenRepository = new CookieServerCsrfTokenRepository(); -+ this.request = MockServerHttpRequest.get("/someUri"); -+ } -+ - @Test - public void generateTokenWhenDefaultThenDefaults() { - generateTokenAndAssertExpectedValues(); -@@ -82,8 +92,9 @@ public class CookieServerCsrfTokenRepositoryTests { - - @Test - public void saveTokenWhenNoSubscriptionThenNotWritten() { -- this.csrfTokenRepository.saveToken(this.exchange, createToken()); -- assertThat(this.exchange.getResponse().getCookies().getFirst(this.expectedCookieName)).isNull(); -+ MockServerWebExchange exchange = MockServerWebExchange.from(this.request); -+ this.csrfTokenRepository.saveToken(exchange, createToken()); -+ assertThat(exchange.getResponse().getCookies().getFirst(this.expectedCookieName)).isNull(); - } - - @Test -@@ -112,6 +123,56 @@ public class CookieServerCsrfTokenRepositoryTests { - saveAndAssertExpectedValues(createToken()); - } - -+ @Test -+ public void saveTokenWhenSslInfoPresentThenSecure() { -+ this.request.sslInfo(new MockSslInfo()); -+ MockServerWebExchange exchange = MockServerWebExchange.from(this.request); -+ this.csrfTokenRepository.saveToken(exchange, createToken()).block(); -+ ResponseCookie cookie = exchange.getResponse().getCookies().getFirst(this.expectedCookieName); -+ assertThat(cookie).isNotNull(); -+ assertThat(cookie.isSecure()).isTrue(); -+ } -+ -+ @Test -+ public void saveTokenWhenSslInfoNullThenNotSecure() { -+ MockServerWebExchange exchange = MockServerWebExchange.from(this.request); -+ this.csrfTokenRepository.saveToken(exchange, createToken()).block(); -+ ResponseCookie cookie = exchange.getResponse().getCookies().getFirst(this.expectedCookieName); -+ assertThat(cookie).isNotNull(); -+ assertThat(cookie.isSecure()).isFalse(); -+ } -+ -+ @Test -+ public void saveTokenWhenSecureFlagTrueThenSecure() { -+ MockServerWebExchange exchange = MockServerWebExchange.from(this.request); -+ this.csrfTokenRepository.setSecure(true); -+ this.csrfTokenRepository.saveToken(exchange, createToken()).block(); -+ ResponseCookie cookie = exchange.getResponse().getCookies().getFirst(this.expectedCookieName); -+ assertThat(cookie).isNotNull(); -+ assertThat(cookie.isSecure()).isTrue(); -+ } -+ -+ @Test -+ public void saveTokenWhenSecureFlagFalseThenNotSecure() { -+ MockServerWebExchange exchange = MockServerWebExchange.from(this.request); -+ this.csrfTokenRepository.setSecure(false); -+ this.csrfTokenRepository.saveToken(exchange, createToken()).block(); -+ ResponseCookie cookie = exchange.getResponse().getCookies().getFirst(this.expectedCookieName); -+ assertThat(cookie).isNotNull(); -+ assertThat(cookie.isSecure()).isFalse(); -+ } -+ -+ @Test -+ public void saveTokenWhenSecureFlagFalseAndSslInfoThenNotSecure() { -+ MockServerWebExchange exchange = MockServerWebExchange.from(this.request); -+ this.request.sslInfo(new MockSslInfo()); -+ this.csrfTokenRepository.setSecure(false); -+ this.csrfTokenRepository.saveToken(exchange, createToken()).block(); -+ ResponseCookie cookie = exchange.getResponse().getCookies().getFirst(this.expectedCookieName); -+ assertThat(cookie).isNotNull(); -+ assertThat(cookie.isSecure()).isFalse(); -+ } -+ - @Test - public void loadTokenWhenCookieExistThenTokenFound() { - loadAndAssertExpectedValues(); -@@ -127,7 +188,8 @@ public class CookieServerCsrfTokenRepositoryTests { - - @Test - public void loadTokenWhenNoCookiesThenNullToken() { -- CsrfToken csrfToken = this.csrfTokenRepository.loadToken(this.exchange).block(); -+ MockServerWebExchange exchange = MockServerWebExchange.from(this.request); -+ CsrfToken csrfToken = this.csrfTokenRepository.loadToken(exchange).block(); - assertThat(csrfToken).isNull(); - } - -@@ -180,8 +242,8 @@ public class CookieServerCsrfTokenRepositoryTests { - private void loadAndAssertExpectedValues() { - MockServerHttpRequest.BodyBuilder request = MockServerHttpRequest.post("/someUri") - .cookie(new HttpCookie(this.expectedCookieName, this.expectedCookieValue)); -- this.exchange = MockServerWebExchange.from(request); -- CsrfToken csrfToken = this.csrfTokenRepository.loadToken(this.exchange).block(); -+ MockServerWebExchange exchange = MockServerWebExchange.from(request); -+ CsrfToken csrfToken = this.csrfTokenRepository.loadToken(exchange).block(); - if (StringUtils.hasText(this.expectedCookieValue)) { - assertThat(csrfToken).isNotNull(); - assertThat(csrfToken.getHeaderName()).isEqualTo(this.expectedHeaderName); -@@ -198,8 +260,9 @@ public class CookieServerCsrfTokenRepositoryTests { - this.expectedMaxAge = Duration.ofSeconds(0); - this.expectedCookieValue = ""; - } -- this.csrfTokenRepository.saveToken(this.exchange, token).block(); -- ResponseCookie cookie = this.exchange.getResponse().getCookies().getFirst(this.expectedCookieName); -+ MockServerWebExchange exchange = MockServerWebExchange.from(this.request); -+ this.csrfTokenRepository.saveToken(exchange, token).block(); -+ ResponseCookie cookie = exchange.getResponse().getCookies().getFirst(this.expectedCookieName); - assertThat(cookie).isNotNull(); - assertThat(cookie.getMaxAge()).isEqualTo(this.expectedMaxAge); - assertThat(cookie.getDomain()).isEqualTo(this.expectedDomain); -@@ -211,7 +274,8 @@ public class CookieServerCsrfTokenRepositoryTests { - } - - private void generateTokenAndAssertExpectedValues() { -- CsrfToken csrfToken = this.csrfTokenRepository.generateToken(this.exchange).block(); -+ MockServerWebExchange exchange = MockServerWebExchange.from(this.request); -+ CsrfToken csrfToken = this.csrfTokenRepository.generateToken(exchange).block(); - assertThat(csrfToken).isNotNull(); - assertThat(csrfToken.getHeaderName()).isEqualTo(this.expectedHeaderName); - assertThat(csrfToken.getParameterName()).isEqualTo(this.expectedParameterName); -@@ -226,4 +290,18 @@ public class CookieServerCsrfTokenRepositoryTests { - return new DefaultCsrfToken(headerName, parameterName, tokenValue); - } - -+ static class MockSslInfo implements SslInfo { -+ -+ @Override -+ public String getSessionId() { -+ return "sessionId"; -+ } -+ -+ @Override -+ public X509Certificate[] getPeerCertificates() { -+ return new X509Certificate[] {}; -+ } -+ -+ } -+ - } --- -2.24.1 - diff --git a/0003-Editing-pass.patch b/0003-Editing-pass.patch deleted file mode 100644 index 8507dffbc10..00000000000 --- a/0003-Editing-pass.patch +++ /dev/null @@ -1,23196 +0,0 @@ -From db91a88e63fc810ca52e75bfc13b09a14a94b0ef Mon Sep 17 00:00:00 2001 -From: Jay Bryant -Date: Wed, 21 Apr 2021 16:01:26 -0500 -Subject: [PATCH 3/3] Editing pass - -I went through everything to get it to fit with Spring's docuemntation standard. -Lots of small changes for punctuation, grammar, usage, voice, and so on. -Also added some links, mostly to the API Javadoc. ---- - .../authentication/password-storage.adoc | 165 +- - .../about/authentication/supported.adoc | 4 +- - .../_includes/about/exploits/csrf.adoc | 188 +- - .../_includes/about/exploits/headers.adoc | 218 +- - .../_includes/about/exploits/http.adoc | 20 +- - .../_includes/about/exploits/index.adoc | 2 +- - .../asciidoc/_includes/about/features.adoc | 1 + - .../about/getting-spring-security.adoc | 60 +- - .../asciidoc/_includes/about/modules.adoc | 30 +- - .../_includes/reactive/exploits/csrf.adoc | 125 +- - .../_includes/reactive/exploits/headers.adoc | 69 +- - .../_includes/reactive/exploits/http.adoc | 14 +- - .../asciidoc/_includes/reactive/method.adoc | 13 +- - .../reactive/oauth2/access-token.adoc | 11 +- - .../_includes/reactive/oauth2/login.adoc | 49 +- - .../reactive/oauth2/resource-server.adoc | 380 +-- - .../registered-oauth2-authorized-client.adoc | 23 +- - .../asciidoc/_includes/reactive/rsocket.adoc | 115 +- - .../asciidoc/_includes/reactive/test.adoc | 292 ++- - .../_includes/reactive/webclient.adoc | 34 +- - .../asciidoc/_includes/reactive/webflux.adoc | 37 +- - .../asciidoc/_includes/reactive/x509.adoc | 15 +- - .../servlet/appendix/database-schema.adoc | 85 +- - .../_includes/servlet/appendix/faq.adoc | 483 ++-- - .../_includes/servlet/appendix/index.adoc | 2 + - .../_includes/servlet/appendix/namespace.adoc | 2052 +++++++++-------- - .../architecture/delegating-filter-proxy.adoc | 16 +- - .../exception-translation-filter.adoc | 22 +- - .../architecture/filter-chain-proxy.adoc | 2 + - .../servlet/architecture/filters.adoc | 20 +- - .../_includes/servlet/architecture/index.adoc | 4 +- - .../architecture/security-filter-chain.adoc | 40 +- - .../architecture/security-filters.adoc | 62 +- - .../servlet/authentication/anonymous.adoc | 74 +- - ...ract-authentication-processing-filter.adoc | 20 +- - .../authentication-entry-point.adoc | 10 +- - .../architecture/authentication-manager.adoc | 4 +- - .../architecture/authentication-provider.adoc | 4 +- - .../architecture/authentication.adoc | 16 +- - .../architecture/granted-authority.adoc | 18 +- - .../architecture/provider-manager.adoc | 26 +- - .../architecture/security-context-holder.adoc | 34 +- - .../_includes/servlet/authentication/cas.adoc | 286 +-- - .../servlet/authentication/events.adoc | 14 +- - .../servlet/authentication/index.adoc | 44 +- - .../servlet/authentication/jaas.adoc | 92 +- - .../servlet/authentication/logout.adoc | 65 +- - .../servlet/authentication/openid.adoc | 40 +- - .../servlet/authentication/preauth.adoc | 88 +- - .../servlet/authentication/rememberme.adoc | 75 +- - .../servlet/authentication/runas.adoc | 38 +- - .../authentication/session-management.adoc | 161 +- - .../servlet/authentication/unpwd/basic.adoc | 43 +- - .../unpwd/dao-authentication-provider.adoc | 12 +- - .../servlet/authentication/unpwd/digest.adoc | 20 +- - .../servlet/authentication/unpwd/form.adoc | 91 +- - .../authentication/unpwd/in-memory.adoc | 15 +- - .../servlet/authentication/unpwd/index.adoc | 10 +- - .../servlet/authentication/unpwd/jdbc.adoc | 30 +- - .../servlet/authentication/unpwd/ldap.adoc | 100 +- - .../unpwd/password-encoder.adoc | 4 +- - .../unpwd/user-details-service.adoc | 4 +- - .../servlet/authentication/x509.adoc | 53 +- - .../_includes/servlet/authorization/acls.adoc | 197 +- - .../servlet/authorization/architecture.adoc | 145 +- - .../authorization/authorize-requests.adoc | 45 +- - .../authorization/expression-based.adoc | 212 +- - .../servlet/authorization/index.adoc | 7 +- - .../authorization/method-security.adoc | 87 +- - .../servlet/authorization/secure-objects.adoc | 55 +- - .../_includes/servlet/crypto/index.adoc | 80 +- - .../_includes/servlet/exploits/csrf.adoc | 156 +- - .../_includes/servlet/exploits/firewall.adoc | 90 +- - .../_includes/servlet/exploits/headers.adoc | 82 +- - .../_includes/servlet/exploits/http.adoc | 10 +- - .../_includes/servlet/exploits/index.adoc | 2 + - .../_includes/servlet/hello/index.adoc | 12 +- - .../servlet/integrations/concurrency.adoc | 116 +- - .../_includes/servlet/integrations/cors.adoc | 20 +- - .../_includes/servlet/integrations/data.adoc | 19 +- - .../_includes/servlet/integrations/index.adoc | 2 + - .../servlet/integrations/jackson.adoc | 14 +- - .../servlet/integrations/jsp-taglibs.adoc | 94 +- - .../servlet/integrations/localization.adoc | 32 +- - .../_includes/servlet/integrations/mvc.adoc | 153 +- - .../servlet/integrations/servlet-api.adoc | 100 +- - .../servlet/integrations/websocket.adoc | 204 +- - .../servlet/java-configuration/index.adoc | 139 +- - .../servlet/kotlin-configuration/index.adoc | 39 +- - .../_includes/servlet/namespace/index.adoc | 216 +- - .../_includes/servlet/oauth2/index.adoc | 2 + - .../servlet/oauth2/oauth2-client.adoc | 334 ++- - .../servlet/oauth2/oauth2-login.adoc | 172 +- - .../servlet/oauth2/oauth2-resourceserver.adoc | 529 ++--- - .../_includes/servlet/saml2/index.adoc | 5 +- - .../_includes/servlet/saml2/saml2-login.adoc | 405 ++-- - .../_includes/servlet/test/index.adoc | 5 +- - .../_includes/servlet/test/method.adoc | 177 +- - .../_includes/servlet/test/mockmvc.adoc | 488 ++-- - docs/manual/src/docs/asciidoc/index.adoc | 7 +- - 100 files changed, 5530 insertions(+), 5066 deletions(-) - -diff --git a/docs/manual/src/docs/asciidoc/_includes/about/authentication/password-storage.adoc b/docs/manual/src/docs/asciidoc/_includes/about/authentication/password-storage.adoc -index 7770eb6b5a..a0cec811ed 100644 ---- a/docs/manual/src/docs/asciidoc/_includes/about/authentication/password-storage.adoc -+++ b/docs/manual/src/docs/asciidoc/_includes/about/authentication/password-storage.adoc -@@ -1,70 +1,69 @@ - [[authentication-password-storage]] - = Password Storage - --Spring Security's `PasswordEncoder` interface is used to perform a one way transformation of a password to allow the password to be stored securely. --Given `PasswordEncoder` is a one way transformation, it is not intended when the password transformation needs to be two way (i.e. storing credentials used to authenticate to a database). --Typically `PasswordEncoder` is used for storing a password that needs to be compared to a user provided password at the time of authentication. -+Spring Security's `PasswordEncoder` interface is used to perform a one-way transformation of a password to let the password be stored securely. -+Given `PasswordEncoder` is a one-way transformation, it is not useful when the password transformation needs to be two-way (such as storing credentials used to authenticate to a database). -+Typically, `PasswordEncoder` is used for storing a password that needs to be compared to a user-provided password at the time of authentication. - - [[authentication-password-storage-history]] - == Password Storage History - --Throughout the years the standard mechanism for storing passwords has evolved. --In the beginning passwords were stored in plain text. -+Throughout the years, the standard mechanism for storing passwords has evolved. -+In the beginning, passwords were stored in plain text. - The passwords were assumed to be safe because the data store the passwords were saved in required credentials to access it. --However, malicious users were able to find ways to get large "data dumps" of usernames and passwords using attacks like SQL Injection. --As more and more user credentials became public security experts realized we needed to do more to protect users' passwords. -+However, malicious users were able to find ways to get large "`data dumps`" of usernames and passwords by using attacks such as SQL Injection. -+As more and more user credentials became public, security experts realized that we needed to do more to protect users' passwords. - --Developers were then encouraged to store passwords after running them through a one way hash such as SHA-256. -+Developers were then encouraged to store passwords after running them through a one way hash, such as SHA-256. - When a user tried to authenticate, the hashed password would be compared to the hash of the password that they typed. --This meant that the system only needed to store the one way hash of the password. --If a breach occurred, then only the one way hashes of the passwords were exposed. --Since the hashes were one way and it was computationally difficult to guess the passwords given the hash, it would not be worth the effort to figure out each password in the system. --To defeat this new system malicious users decided to create lookup tables known as https://en.wikipedia.org/wiki/Rainbow_table[Rainbow Tables]. -+This meant that the system only needed to store the one-way hash of the password. -+If a breach occurred, only the one-way hashes of the passwords were exposed. -+Since the hashes were one-way and it was computationally difficult to guess the passwords given the hash, it would not be worth the effort to figure out each password in the system. -+To defeat this new system, malicious users decided to create lookup tables known as https://en.wikipedia.org/wiki/Rainbow_table[Rainbow Tables]. - Rather than doing the work of guessing each password every time, they computed the password once and stored it in a lookup table. - - To mitigate the effectiveness of Rainbow Tables, developers were encouraged to use salted passwords. --Instead of using just the password as input to the hash function, random bytes (known as salt) would be generated for every users' password. --The salt and the user's password would be ran through the hash function which produced a unique hash. -+Instead of using just the password as input to the hash function, random bytes (known as salt) would be generated for every user's password. -+The salt and the user's password would be run through the hash function to produce a unique hash. - The salt would be stored alongside the user's password in clear text. --Then when a user tried to authenticate, the hashed password would be compared to the hash of the stored salt and the password that they typed. --The unique salt meant that Rainbow Tables were no longer effective because the hash was different for every salt and password combination. -+Then, when a user tried to authenticate, the hashed password would be compared to the hash of the stored salt and the password that they typed. -+The unique salt meant that Rainbow Tables were no longer effective, because the hash was different for every salt and password combination. - --In modern times we realize that cryptographic hashes (like SHA-256) are no longer secure. -+In modern times, we realize that cryptographic hashes (like SHA-256) are no longer secure. - The reason is that with modern hardware we can perform billions of hash calculations a second. - This means that we can crack each password individually with ease. - - Developers are now encouraged to leverage adaptive one-way functions to store a password. --Validation of passwords with adaptive one-way functions are intentionally resource (i.e. CPU, memory, etc) intensive. --An adaptive one-way function allows configuring a "work factor" which can grow as hardware gets better. --It is recommended that the "work factor" be tuned to take about 1 second to verify a password on your system. --This trade off is to make it difficult for attackers to crack the password, but not so costly it puts excessive burden on your own system. --Spring Security has attempted to provide a good starting point for the "work factor", but users are encouraged to customize the "work factor" for their own system since the performance will vary drastically from system to system. -+Validation of passwords with adaptive one-way functions are intentionally resource-intensive (they intentionally use a lot of CPU, memory, or other resources). -+An adaptive one-way function allows configuring a "`work factor`" that can grow as hardware gets better. -+We recommend that the "`work factor`" be tuned to take about one second to verify a password on your system. -+This trade off is to make it difficult for attackers to crack the password, but not so costly that it puts excessive burden on your own system or irritates users. -+Spring Security has attempted to provide a good starting point for the "`work factor`", but we encourage users to customize the "`work factor`" for their own system, since the performance varies drastically from system to system. - Examples of adaptive one-way functions that should be used include <>, <>, <>, and <>. - --Because adaptive one-way functions are intentionally resource intensive, validating a username and password for every request will degrade performance of an application significantly. --There is nothing Spring Security (or any other library) can do to speed up the validation of the password since security is gained by making the validation resource intensive. --Users are encouraged to exchange the long term credentials (i.e. username and password) for a short term credential (i.e. session, OAuth Token, etc). -+Because adaptive one-way functions are intentionally resource intensive, validating a username and password for every request can significantly degrade the performance of an application. -+There is nothing Spring Security (or any other library) can do to speed up the validation of the password, since security is gained by making the validation resource intensive. -+Users are encouraged to exchange the long term credentials (that is, username and password) for a short term credential (such as a session, and OAuth Token, and so on). - The short term credential can be validated quickly without any loss in security. - -- - [[authentication-password-storage-dpe]] - == DelegatingPasswordEncoder - --Prior to Spring Security 5.0 the default `PasswordEncoder` was `NoOpPasswordEncoder` which required plain text passwords. --Based upon the <> section you might expect that the default `PasswordEncoder` is now something like `BCryptPasswordEncoder`. -+Prior to Spring Security 5.0, the default `PasswordEncoder` was `NoOpPasswordEncoder`, which required plain-text passwords. -+Based on the <> section, you might expect that the default `PasswordEncoder` would now be something like `BCryptPasswordEncoder`. - However, this ignores three real world problems: - --- There are many applications using old password encodings that cannot easily migrate -+- Many applications use old password encodings that cannot easily migrate. - - The best practice for password storage will change again. --- As a framework Spring Security cannot make breaking changes frequently -+- As a framework, Spring Security cannot make breaking changes frequently. - --Instead Spring Security introduces `DelegatingPasswordEncoder` which solves all of the problems by: -+Instead Spring Security introduces `DelegatingPasswordEncoder`, which solves all of the problems by: - --- Ensuring that passwords are encoded using the current password storage recommendations -+- Ensuring that passwords are encoded by using the current password storage recommendations - - Allowing for validating passwords in modern and legacy formats - - Allowing for upgrading the encoding in the future - --You can easily construct an instance of `DelegatingPasswordEncoder` using `PasswordEncoderFactories`. -+You can easily construct an instance of `DelegatingPasswordEncoder` by using `PasswordEncoderFactories`: - - .Create Default DelegatingPasswordEncoder - ==== -@@ -82,7 +81,7 @@ val passwordEncoder: PasswordEncoder = PasswordEncoderFactories.createDelegating - ---- - ==== - --Alternatively, you may create your own custom instance. For example: -+Alternatively, you can create your own custom instance: - - .Create Custom DelegatingPasswordEncoder - ==== -@@ -129,11 +128,11 @@ The general format for a password is: - ---- - ==== - --Such that `id` is an identifier used to look up which `PasswordEncoder` should be used and `encodedPassword` is the original encoded password for the selected `PasswordEncoder`. --The `id` must be at the beginning of the password, start with `{` and end with `}`. --If the `id` cannot be found, the `id` will be null. --For example, the following might be a list of passwords encoded using different `id`. --All of the original passwords are "password". -+`id` is an identifier that is used to look up which `PasswordEncoder` should be used and `encodedPassword` is the original encoded password for the selected `PasswordEncoder`. -+The `id` must be at the beginning of the password, start with `{`, and end with `}`. -+If the `id` cannot be found, the `id` is set to null. -+For example, the following might be a list of passwords encoded using different `id` values. -+All of the original passwords are `password`. - - .DelegatingPasswordEncoder Encoded Passwords Example - ==== -@@ -147,16 +146,16 @@ All of the original passwords are "password". - ---- - ==== - --<1> The first password would have a `PasswordEncoder` id of `bcrypt` and encodedPassword of `$2a$10$dXJ3SW6G7P50lGmMkkmwe.20cQQubK3.HZWzG3YB1tlRy.fqvM/BG`. --When matching it would delegate to `BCryptPasswordEncoder` --<2> The second password would have a `PasswordEncoder` id of `noop` and encodedPassword of `password`. --When matching it would delegate to `NoOpPasswordEncoder` --<3> The third password would have a `PasswordEncoder` id of `pbkdf2` and encodedPassword of `5d923b44a6d129f3ddf3e3c8d29412723dcbde72445e8ef6bf3b508fbf17fa4ed4d6b99ca763d8dc`. --When matching it would delegate to `Pbkdf2PasswordEncoder` --<4> The fourth password would have a `PasswordEncoder` id of `scrypt` and encodedPassword of `$e0801$8bWJaSu2IKSn9Z9kM+TPXfOc/9bdYSrN1oD9qfVThWEwdRTnO7re7Ei+fUZRJ68k9lTyuTeUp4of4g24hHnazw==$OAOec05+bXxvuu/1qZ6NUR+xQYvYv7BeL1QxwRpY5Pc=` --When matching it would delegate to `SCryptPasswordEncoder` --<5> The final password would have a `PasswordEncoder` id of `sha256` and encodedPassword of `97cde38028ad898ebc02e690819fa220e88c62e0699403e94fff291cfffaf8410849f27605abcbc0`. --When matching it would delegate to `StandardPasswordEncoder` -+<1> The first password has a `PasswordEncoder` id of `bcrypt` and an encoded password value of `$2a$10$dXJ3SW6G7P50lGmMkkmwe.20cQQubK3.HZWzG3YB1tlRy.fqvM/BG`. -+When matching, it would delegate to `BCryptPasswordEncoder` -+<2> The second password has a `PasswordEncoder` id of `noop` and encoded password value of `password`. -+When matching, it would delegate to `NoOpPasswordEncoder` -+<3> The third password has a `PasswordEncoder` id of `pbkdf2` and encoded password value of `5d923b44a6d129f3ddf3e3c8d29412723dcbde72445e8ef6bf3b508fbf17fa4ed4d6b99ca763d8dc`. -+When matching, it would delegate to `Pbkdf2PasswordEncoder` -+<4> The fourth password has a `PasswordEncoder` id of `scrypt` and encoded password value of `$e0801$8bWJaSu2IKSn9Z9kM+TPXfOc/9bdYSrN1oD9qfVThWEwdRTnO7re7Ei+fUZRJ68k9lTyuTeUp4of4g24hHnazw==$OAOec05+bXxvuu/1qZ6NUR+xQYvYv7BeL1QxwRpY5Pc=` -+When matching, it would delegate to `SCryptPasswordEncoder` -+<5> The final password has a `PasswordEncoder` id of `sha256` and encoded password value of `97cde38028ad898ebc02e690819fa220e88c62e0699403e94fff291cfffaf8410849f27605abcbc0`. -+When matching, it would delegate to `StandardPasswordEncoder` - - [NOTE] - ==== -@@ -169,9 +168,9 @@ For example, BCrypt passwords often start with `$2a$`. - [[authentication-password-storage-dpe-encoding]] - === Password Encoding - --The `idForEncode` passed into the constructor determines which `PasswordEncoder` will be used for encoding passwords. --In the `DelegatingPasswordEncoder` we constructed above, that means that the result of encoding `password` would be delegated to `BCryptPasswordEncoder` and be prefixed with `+{bcrypt}+`. --The end result would look like: -+The `idForEncode` passed into the constructor determines which `PasswordEncoder` is used for encoding passwords. -+In the `DelegatingPasswordEncoder` we constructed earlier, that means that the result of encoding `password` is delegated to `BCryptPasswordEncoder` and be prefixed with `+{bcrypt}+`. -+The end result looks like the following example: - - .DelegatingPasswordEncoder Encode Example - ==== -@@ -184,15 +183,15 @@ The end result would look like: - [[authentication-password-storage-dpe-matching]] - === Password Matching - --Matching is done based upon the `+{id}+` and the mapping of the `id` to the `PasswordEncoder` provided in the constructor. -+Matching is based upon the `+{id}+` and the mapping of the `id` to the `PasswordEncoder` provided in the constructor. - Our example in <> provides a working example of how this is done. --By default, the result of invoking `matches(CharSequence, String)` with a password and an `id` that is not mapped (including a null id) will result in an `IllegalArgumentException`. --This behavior can be customized using `DelegatingPasswordEncoder.setDefaultPasswordEncoderForMatches(PasswordEncoder)`. -+By default, the result of invoking `matches(CharSequence, String)` with a password and an `id` that is not mapped (including a null id) results in an `IllegalArgumentException`. -+This behavior can be customized by using `DelegatingPasswordEncoder.setDefaultPasswordEncoderForMatches(PasswordEncoder)`. - --By using the `id` we can match on any password encoding, but encode passwords using the most modern password encoding. --This is important, because unlike encryption, password hashes are designed so that there is no simple way to recover the plaintext. --Since there is no way to recover the plaintext, it makes it difficult to migrate the passwords. --While it is simple for users to migrate `NoOpPasswordEncoder`, we chose to include it by default to make it simple for the getting started experience. -+By using the `id`, we can match on any password encoding but encode passwords by using the most modern password encoding. -+This is important, because unlike encryption, password hashes are designed so that there is no simple way to recover the plain text. -+Since there is no way to recover the plain text, it is difficult to migrate the passwords. -+While it is simple for users to migrate `NoOpPasswordEncoder`, we chose to include it by default to make it simple for the getting-started experience. - - [[authentication-password-storage-dep-getting-started]] - === Getting Started Experience -@@ -227,7 +226,7 @@ println(user.password) - ---- - ==== - --If you are creating multiple users, you can also reuse the builder. -+If you are creating multiple users, you can also reuse the builder: - - .withDefaultPasswordEncoder Reusing the Builder - ==== -@@ -273,7 +272,7 @@ For production, you should <>: -+For example, the following example encodes the password of `password` for use with <>: - - .Spring Boot CLI encodepassword Example - ==== -@@ -287,44 +286,48 @@ spring encodepassword password - [[authentication-password-storage-dpe-troubleshoot]] - === Troubleshooting - --The following error occurs when one of the passwords that are stored has no id as described in <>. -+The following error occurs when one of the passwords that are stored has no `id`, as described in <>. - -+==== - ---- - java.lang.IllegalArgumentException: There is no PasswordEncoder mapped for the id "null" - at org.springframework.security.crypto.password.DelegatingPasswordEncoder$UnmappedIdPasswordEncoder.matches(DelegatingPasswordEncoder.java:233) - at org.springframework.security.crypto.password.DelegatingPasswordEncoder.matches(DelegatingPasswordEncoder.java:196) - ---- -+==== - --The easiest way to resolve the error is to switch to explicitly provide the `PasswordEncoder` that you passwords are encoded with. - The easiest way to resolve it is to figure out how your passwords are currently being stored and explicitly provide the correct `PasswordEncoder`. - --If you are migrating from Spring Security 4.2.x you can revert to the previous behavior by <>. -+If you are migrating from Spring Security 4.2.x, you can revert to the previous behavior by <>. - --Alternatively, you can prefix all of your passwords with the correct id and continue to use `DelegatingPasswordEncoder`. -+Alternatively, you can prefix all of your passwords with the correct `id` and continue to use `DelegatingPasswordEncoder`. - For example, if you are using BCrypt, you would migrate your password from something like: - -+==== - ---- - $2a$10$dXJ3SW6G7P50lGmMkkmwe.20cQQubK3.HZWzG3YB1tlRy.fqvM/BG - ---- -+==== - - to - -- -+==== - [source,attrs="-attributes"] - ---- - {bcrypt}$2a$10$dXJ3SW6G7P50lGmMkkmwe.20cQQubK3.HZWzG3YB1tlRy.fqvM/BG - ---- -+==== - --For a complete listing of the mappings refer to the Javadoc on --https://docs.spring.io/spring-security/site/docs/5.0.x/api/org/springframework/security/crypto/factory/PasswordEncoderFactories.html[PasswordEncoderFactories]. -+For a complete listing of the mappings, see the Javadoc for -+https://docs.spring.io/spring-security/site/docs/5.0.x/api/org/springframework/security/crypto/factory/PasswordEncoderFactories.html[`PasswordEncoderFactories`]. - - [[authentication-password-storage-bcrypt]] - == BCryptPasswordEncoder - - The `BCryptPasswordEncoder` implementation uses the widely supported https://en.wikipedia.org/wiki/Bcrypt[bcrypt] algorithm to hash the passwords. --In order to make it more resistent to password cracking, bcrypt is deliberately slow. -+To make it more resistant to password cracking, bcrypt is deliberately slow. - Like other adaptive one-way functions, it should be tuned to take about 1 second to verify a password on your system. --The default implementation of `BCryptPasswordEncoder` uses strength 10 as mentioned in the Javadoc of https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/crypto/bcrypt/BCryptPasswordEncoder.html[BCryptPasswordEncoder]. You are encouraged to -+The default implementation of `BCryptPasswordEncoder` uses strength 10 as mentioned in the Javadoc of https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/crypto/bcrypt/BCryptPasswordEncoder.html[`BCryptPasswordEncoder`]. You are encouraged to - tune and test the strength parameter on your own system so that it takes roughly 1 second to verify a password. - - .BCryptPasswordEncoder -@@ -353,7 +356,7 @@ assertTrue(encoder.matches("myPassword", result)) - - The `Argon2PasswordEncoder` implementation uses the https://en.wikipedia.org/wiki/Argon2[Argon2] algorithm to hash the passwords. - Argon2 is the winner of the https://en.wikipedia.org/wiki/Password_Hashing_Competition[Password Hashing Competition]. --In order to defeat password cracking on custom hardware, Argon2 is a deliberately slow algorithm that requires large amounts of memory. -+To defeat password cracking on custom hardware, Argon2 is a deliberately slow algorithm that requires large amounts of memory. - Like other adaptive one-way functions, it should be tuned to take about 1 second to verify a password on your system. - The current implementation of the `Argon2PasswordEncoder` requires BouncyCastle. - -@@ -382,7 +385,7 @@ assertTrue(encoder.matches("myPassword", result)) - == Pbkdf2PasswordEncoder - - The `Pbkdf2PasswordEncoder` implementation uses the https://en.wikipedia.org/wiki/PBKDF2[PBKDF2] algorithm to hash the passwords. --In order to defeat password cracking PBKDF2 is a deliberately slow algorithm. -+To defeat password cracking, PBKDF2 is a deliberately slow algorithm. - Like other adaptive one-way functions, it should be tuned to take about 1 second to verify a password on your system. - This algorithm is a good choice when FIPS certification is required. - -@@ -410,8 +413,8 @@ assertTrue(encoder.matches("myPassword", result)) - [[authentication-password-storage-scrypt]] - == SCryptPasswordEncoder - --The `SCryptPasswordEncoder` implementation uses https://en.wikipedia.org/wiki/Scrypt[scrypt] algorithm to hash the passwords. --In order to defeat password cracking on custom hardware scrypt is a deliberately slow algorithm that requires large amounts of memory. -+The `SCryptPasswordEncoder` implementation uses the https://en.wikipedia.org/wiki/Scrypt[scrypt] algorithm to hash the passwords. -+To defeat password cracking on custom hardware, scrypt is a deliberately slow algorithm that requires large amounts of memory. - Like other adaptive one-way functions, it should be tuned to take about 1 second to verify a password on your system. - - .SCryptPasswordEncoder -@@ -436,20 +439,19 @@ assertTrue(encoder.matches("myPassword", result)) - ==== - - [[authentication-password-storage-other]] --== Other PasswordEncoders -+== Other Password Encoders - - There are a significant number of other `PasswordEncoder` implementations that exist entirely for backward compatibility. - They are all deprecated to indicate that they are no longer considered secure. --However, there are no plans to remove them since it is difficult to migrate existing legacy systems. -+However, there are no plans to remove them, since it is difficult to migrate existing legacy systems. - - [[authentication-password-storage-configuration]] - == Password Storage Configuration - - Spring Security uses <> by default. --However, this can be customized by exposing a `PasswordEncoder` as a Spring bean. -- -+However, you can customize this by exposing a `PasswordEncoder` as a Spring bean. - --If you are migrating from Spring Security 4.2.x you can revert to the previous behavior by exposing a `NoOpPasswordEncoder` bean. -+If you are migrating from Spring Security 4.2.x, you can revert to the previous behavior by exposing a `NoOpPasswordEncoder` bean. - - [WARNING] - ==== -@@ -485,7 +487,4 @@ fun passwordEncoder(): PasswordEncoder { - ---- - ==== - --[NOTE] --==== --XML Configuration requires the `NoOpPasswordEncoder` bean name to be `passwordEncoder`. --==== -+NOTE: XML Configuration requires the `NoOpPasswordEncoder` bean name to be `passwordEncoder`. -diff --git a/docs/manual/src/docs/asciidoc/_includes/about/authentication/supported.adoc b/docs/manual/src/docs/asciidoc/_includes/about/authentication/supported.adoc -index 85bd943456..67c03c68fe 100644 ---- a/docs/manual/src/docs/asciidoc/_includes/about/authentication/supported.adoc -+++ b/docs/manual/src/docs/asciidoc/_includes/about/authentication/supported.adoc -@@ -1,5 +1,5 @@ - [[authentication-support]] - = Authentication Support - --Spring Security provides built in support for authenticating users. --Refer to the sections on authentication for <> and WebFlux for details on what is supported for each stack. -+Spring Security provides built-in support for authenticating users. -+See the sections on authentication for <> and <> for details on what is supported for each stack. -diff --git a/docs/manual/src/docs/asciidoc/_includes/about/exploits/csrf.adoc b/docs/manual/src/docs/asciidoc/_includes/about/exploits/csrf.adoc -index 0a7a98b561..67728e135b 100644 ---- a/docs/manual/src/docs/asciidoc/_includes/about/exploits/csrf.adoc -+++ b/docs/manual/src/docs/asciidoc/_includes/about/exploits/csrf.adoc -@@ -1,21 +1,15 @@ --// FIXME: Add links to Servlet and WebFlux support -- - [[csrf]] - = Cross Site Request Forgery (CSRF) - - Spring provides comprehensive support for protecting against https://en.wikipedia.org/wiki/Cross-site_request_forgery[Cross Site Request Forgery (CSRF)] attacks. --In the following sections we will explore: -+In the following sections, we explore: - - * <> - * <> - * <> - --// FIXME: Add WebFlux csrf documentation (the link below is broken) --[NOTE] --==== --This portion of the documentation discusses the general topic of CSRF protection. --Refer to the relevant sections for specific information on CSRF protection for <> and <> based applications. --==== -+NOTE: This portion of the documentation discusses the general topic of CSRF protection. -+See the relevant sections for specific information on CSRF protection for <>- and <>-based applications. - - [[csrf-explained]] - == What is a CSRF Attack? -@@ -85,52 +79,49 @@ You like to win money, so you click on the submit button. - In the process, you have unintentionally transferred $100 to a malicious user. - This happens because, while the evil website cannot see your cookies, the cookies associated with your bank are still sent along with the request. - --Worst yet, this whole process could have been automated using JavaScript. --This means you didn't even need to click on the button. -+Worse yet, this whole process could have been automated by using JavaScript. -+This means you did not even need to click on the button. - Furthermore, it could just as easily happen when visiting an honest site that is a victim of a https://www.owasp.org/index.php/Cross-site_Scripting_(XSS)[XSS attack]. - So how do we protect our users from such attacks? - - [[csrf-protection]] - == Protecting Against CSRF Attacks - The reason that a CSRF attack is possible is that the HTTP request from the victim's website and the request from the attacker's website are exactly the same. --This means there is no way to reject requests coming from the evil website and allow requests coming from the bank's website. --To protect against CSRF attacks we need to ensure there is something in the request that the evil site is unable to provide so we can differentiate the two requests. -+This means there is no way to reject requests coming from the evil website and allow only requests coming from the bank's website. -+To protect against CSRF attacks, we need to ensure there is something in the request that the evil site is unable to provide so we can differentiate the two requests. - - Spring provides two mechanisms to protect against CSRF attacks: - - * The <> - * Specifying the <> on your session cookie - --[NOTE] --==== --Both protections require that <> --==== -+NOTE: Both protections require that <>. - - [[csrf-protection-idempotent]] - === Safe Methods Must be Idempotent - --In order for <> against CSRF to work, the application must ensure that https://tools.ietf.org/html/rfc7231#section-4.2.1["safe" HTTP methods are idempotent]. --This means that requests with the HTTP method `GET`, `HEAD`, `OPTIONS`, and `TRACE` should not change the state of the application. -+For <> against CSRF to work, the application must ensure that https://tools.ietf.org/html/rfc7231#section-4.2.1["safe" HTTP methods are idempotent]. -+This means that requests with the HTTP `GET`, `HEAD`, `OPTIONS`, and `TRACE` methods should not change the state of the application. - - [[csrf-protection-stp]] - === Synchronizer Token Pattern - The predominant and most comprehensive way to protect against CSRF attacks is to use the https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)_Prevention_Cheat_Sheet#General_Recommendation:_Synchronizer_Token_Pattern[Synchronizer Token Pattern]. --This solution is to ensure that each HTTP request requires, in addition to our session cookie, a secure random generated value called a CSRF token must be present in the HTTP request. -+This solution is to ensure that each HTTP request requires, in addition to our session cookie, a secure random generated value called a CSRF token be present in the HTTP request. - - When an HTTP request is submitted, the server must look up the expected CSRF token and compare it against the actual CSRF token in the HTTP request. - If the values do not match, the HTTP request should be rejected. - - The key to this working is that the actual CSRF token should be in a part of the HTTP request that is not automatically included by the browser. --For example, requiring the actual CSRF token in an HTTP parameter or an HTTP header will protect against CSRF attacks. -+For example, requiring the actual CSRF token in an HTTP parameter or an HTTP header protects against CSRF attacks. - Requiring the actual CSRF token in a cookie does not work because cookies are automatically included in the HTTP request by the browser. - --We can relax the expectations to only require the actual CSRF token for each HTTP request that updates state of the application. -+We can relax the expectations to require only the actual CSRF token for each HTTP request that updates the state of the application. - For that to work, our application must ensure that <>. --This improves usability since we want to allow linking to our website using links from external sites. --Additionally, we do not want to include the random token in HTTP GET as this can cause the tokens to be leaked. -+This improves usability, since we want to allow linking to our website from external sites. -+Additionally, we do not want to include the random token in HTTP GET, as this can cause the tokens to be leaked. - --Let's take a look at how <> would change when using the Synchronizer Token Pattern. --Assume the actual CSRF token is required to be in an HTTP parameter named `_csrf`. -+Consider how <> would change when we use the Synchronizer Token Pattern. -+Assume that the actual CSRF token is required to be in an HTTP parameter named `_csrf`. - Our application's transfer form would look like: - - .Synchronizer Token Form -@@ -173,22 +164,19 @@ amount=100.00&routingNumber=1234&account=9876&_csrf=4bfd1575-3ad1-4d21-96c7-4ef2 - ==== - - --You will notice that the HTTP request now contains the `_csrf` parameter with a secure random value. --The evil website will not be able to provide the correct value for the `_csrf` parameter (which must be explicitly provided on the evil website) and the transfer will fail when the server compares the actual CSRF token to the expected CSRF token. -+Notice that the HTTP request now contains the `_csrf` parameter with a secure random value. -+The evil website cannot provide the correct value for the `_csrf` parameter (which must be explicitly provided on the evil website), and the transfer fails when the server compares the actual CSRF token to the expected CSRF token. - - [[csrf-protection-ssa]] - === SameSite Attribute - An emerging way to protect against <> is to specify the https://tools.ietf.org/html/draft-west-first-party-cookies[SameSite Attribute] on cookies. - A server can specify the `SameSite` attribute when setting a cookie to indicate that the cookie should not be sent when coming from external sites. - --[NOTE] --==== --Spring Security does not directly control the creation of the session cookie, so it does not provide support for the SameSite attribute. --https://spring.io/projects/spring-session[Spring Session] provides support for the `SameSite` attribute in servlet based applications. --Spring Framework's https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/server/session/CookieWebSessionIdResolver.html[CookieWebSessionIdResolver] provides out of the box support for the `SameSite` attribute in WebFlux based applications. --==== -+NOTE: Spring Security does not directly control the creation of the session cookie, so it does not provide support for the SameSite attribute. -+https://spring.io/projects/spring-session[Spring Session] provides support for the `SameSite` attribute in servlet-based applications. -+Spring Framework's https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/server/session/CookieWebSessionIdResolver.html[`CookieWebSessionIdResolver`] provides support for the `SameSite` attribute in WebFlux-based applications. - --An example, HTTP response header with the `SameSite` attribute might look like: -+An example of an HTTP response header with the `SameSite` attribute might look like: - - .SameSite HTTP response - ==== -@@ -200,49 +188,45 @@ Set-Cookie: JSESSIONID=randomid; Domain=bank.example.com; Secure; HttpOnly; Same - - Valid values for the `SameSite` attribute are: - --* `Strict` - when specified any request coming from the https://tools.ietf.org/html/draft-west-first-party-cookies-07#section-2.1[same-site] will include the cookie. --Otherwise, the cookie will not be included in the HTTP request. --* `Lax` - when specified cookies will be sent when coming from the https://tools.ietf.org/html/draft-west-first-party-cookies-07#section-2.1[same-site] or when the request comes from top-level navigations and the <>. --Otherwise, the cookie will not be included in the HTTP request. -+* `Strict`: When specified, any request coming from the https://tools.ietf.org/html/draft-west-first-party-cookies-07#section-2.1[same-site] includes the cookie. -+Otherwise, the cookie is not included in the HTTP request. -+* `Lax`: When specified, cookies are sent when coming from the https://tools.ietf.org/html/draft-west-first-party-cookies-07#section-2.1[same-site] or when the request comes from top-level navigations and the <>. -+Otherwise, the cookie is not included in the HTTP request. - --Let's take a look at how <> could be protected using the `SameSite` attribute. -+Consider how <> could be protected using the `SameSite` attribute. - The bank application can protect against CSRF by specifying the `SameSite` attribute on the session cookie. - --With the `SameSite` attribute set on our session cookie, the browser will continue to send the `JSESSIONID` cookie with requests coming from the banking website. --However, the browser will no longer send the `JSESSIONID` cookie with a transfer request coming from the evil website. -+With the `SameSite` attribute set on our session cookie, the browser continues to send the `JSESSIONID` cookie with requests coming from the banking website. -+However, the browser no longer sends the `JSESSIONID` cookie with a transfer request coming from the evil website. - Since the session is no longer present in the transfer request coming from the evil website, the application is protected from the CSRF attack. - --There are some important https://tools.ietf.org/html/draft-west-first-party-cookies-07#section-5[considerations] that one should be aware about when using `SameSite` attribute to protect against CSRF attacks. -- -+There are some important https://tools.ietf.org/html/draft-west-first-party-cookies-07#section-5[considerations] to be aware of when using `SameSite` attribute to protect against CSRF attacks. - Setting the `SameSite` attribute to `Strict` provides a stronger defense but can confuse users. --Consider a user that stays logged into a social media site hosted at https://social.example.com. -+Consider a user who stays logged into a social media site hosted at https://social.example.com. - The user receives an email at https://email.example.org that includes a link to the social media site. - If the user clicks on the link, they would rightfully expect to be authenticated to the social media site. --However, if the `SameSite` attribute is `Strict` the cookie would not be sent and so the user would not be authenticated. -+However, if the `SameSite` attribute is `Strict`, the cookie would not be sent and the user would not be authenticated. - --[NOTE] --==== --We could improve the protection and usability of `SameSite` protection against CSRF attacks by implementing https://github.com/spring-projects/spring-security/issues/7537[gh-7537]. --==== -+NOTE: We could improve the protection and usability of `SameSite` protection against CSRF attacks by implementing https://github.com/spring-projects/spring-security/issues/7537[gh-7537]. - --Another obvious consideration is that in order for the `SameSite` attribute to protect users, the browser must support the `SameSite` attribute. -+Another obvious consideration is that, in order for the `SameSite` attribute to protect users, the browser must support the `SameSite` attribute. - Most modern browsers do https://developer.mozilla.org/en-US/docs/Web/HTTP/headers/Set-Cookie#Browser_compatibility[support the SameSite attribute]. - However, older browsers that are still in use may not. - --For this reason, it is generally recommended to use the `SameSite` attribute as a defense in depth rather than the sole protection against CSRF attacks. -+For this reason, we generally recommend using the `SameSite` attribute as a defense in depth rather than the sole protection against CSRF attacks. - - [[csrf-when]] - == When to use CSRF protection - When should you use CSRF protection? - Our recommendation is to use CSRF protection for any request that could be processed by a browser by normal users. --If you are only creating a service that is used by non-browser clients, you will likely want to disable CSRF protection. -+If you are creating a service that is used only by non-browser clients, you likely want to disable CSRF protection. - - [[csrf-when-json]] - === CSRF protection and JSON --A common question is "do I need to protect JSON requests made by javascript?" --The short answer is, it depends. --However, you must be very careful as there are CSRF exploits that can impact JSON requests. --For example, a malicious user can create a http://blog.opensecurityresearch.com/2012/02/json-csrf-with-parameter-padding.html[CSRF with JSON using the following form]: -+A common question is "`do I need to protect JSON requests made by JavaScript?`" -+The short answer is: It depends. -+However, you must be very careful, as there are CSRF exploits that can impact JSON requests. -+For example, a malicious user can create a http://blog.opensecurityresearch.com/2012/02/json-csrf-with-parameter-padding.html[CSRF with JSON by using the following form]: - - .CSRF with JSON form - ==== -@@ -257,7 +241,7 @@ For example, a malicious user can create a http://blog.opensecurityresearch.com/ - ==== - - --This will produce the following JSON structure -+This produces the following JSON structure - - .CSRF with JSON request - ==== -@@ -271,8 +255,8 @@ This will produce the following JSON structure - ---- - ==== - --If an application were not validating the Content-Type, then it would be exposed to this exploit. --Depending on the setup, a Spring MVC application that validates the Content-Type could still be exploited by updating the URL suffix to end with `.json` as shown below: -+If an application were not validating the `Content-Type` header, it would be exposed to this exploit. -+Depending on the setup, a Spring MVC application that validates the Content-Type could still be exploited by updating the URL suffix to end with `.json`, as follows: - - .CSRF with JSON Spring MVC form - ==== -@@ -289,15 +273,15 @@ Depending on the setup, a Spring MVC application that validates the Content-Type - [[csrf-when-stateless]] - === CSRF and Stateless Browser Applications - What if my application is stateless? --That doesn't necessarily mean you are protected. -+That does not necessarily mean you are protected. - In fact, if a user does not need to perform any actions in the web browser for a given request, they are likely still vulnerable to CSRF attacks. - --For example, consider an application that uses a custom cookie that contains all the state within it for authentication instead of the JSESSIONID. --When the CSRF attack is made the custom cookie will be sent with the request in the same manner that the JSESSIONID cookie was sent in our previous example. --This application will be vulnerable to CSRF attacks. -+For example, consider an application that uses a custom cookie that contains all the state within it for authentication (instead of the JSESSIONID). -+When the CSRF attack is made, the custom cookie is sent with the request in the same manner that the JSESSIONID cookie was sent in our previous example. -+This application is vulnerable to CSRF attacks. - - Applications that use basic authentication are also vulnerable to CSRF attacks. --The application is vulnerable since the browser will automatically include the username and password in any requests in the same manner that the JSESSIONID cookie was sent in our previous example. -+The application is vulnerable since the browser automatically includes the username and password in any requests in the same manner that the JSESSIONID cookie was sent in our previous example. - - [[csrf-considerations]] - == CSRF Considerations -@@ -308,89 +292,87 @@ There are a few special considerations to consider when implementing protection - [[csrf-considerations-login]] - === Logging In - --In order to protect against https://en.wikipedia.org/wiki/Cross-site_request_forgery#Forging_login_requests[forging log in requests] the log in HTTP request should be protected against CSRF attacks. --Protecting against forging log in requests is necessary so that a malicious user cannot read a victim's sensitive information. -+To protect against https://en.wikipedia.org/wiki/Cross-site_request_forgery#Forging_login_requests[forging login requests], the login HTTP request should be protected against CSRF attacks. -+Protecting against forging login requests is necessary so that a malicious user cannot read a victim's sensitive information. - The attack is performed as follows: - --* A malicious user performs a CSRF log in using the malicious user's credentials. -+. A malicious user performs a CSRF login with the malicious user's credentials. - The victim is now authenticated as the malicious user. --* The malicious user then tricks the victim to visit the compromised website and enter sensitive information --* The information is associated to the malicious user's account so the malicious user can log in with their own credentials and view the vicitim's sensitive information -+. The malicious user then tricks the victim into visiting the compromised website and entering sensitive information. -+. The information is associated to the malicious user's account so the malicious user can log in with their own credentials and view the victim's sensitive information. - --A possible complication to ensuring log in HTTP requests are protected against CSRF attacks is that the user might experience a session timeout that causes the request to be rejected. --A session timeout is surprising to users who do not expect to need to have a session in order to log in. -+A possible complication to ensuring login HTTP requests are protected against CSRF attacks is that the user might experience a session timeout that causes the request to be rejected. -+A session timeout is surprising to users who do not expect to need to have a session to log in. - For more information refer to <>. - - [[csrf-considerations-logout]] - === Logging Out - --In order to protect against forging log out requests, the log out HTTP request should be protected against CSRF attacks. --Protecting against forging log out requests is necessary so a malicious user cannot read a victim's sensitive information. --For details on the attack refer to https://labs.detectify.com/2017/03/15/loginlogout-csrf-time-to-reconsider/[this blog post]. -+To protect against forging logout requests, the logout HTTP request should be protected against CSRF attacks. -+Protecting against forging logout requests is necessary so that a malicious user cannot read a victim's sensitive information. -+For details on the attack, see https://labs.detectify.com/2017/03/15/loginlogout-csrf-time-to-reconsider/[this blog post]. - --A possible complication to ensuring log out HTTP requests are protected against CSRF attacks is that the user might experience a session timeout that causes the request to be rejected. --A session timeout is surprising to users who do not expect to need to have a session in order to log out. --For more information refer to <>. -+A possible complication to ensuring logout HTTP requests are protected against CSRF attacks is that the user might experience a session timeout that causes the request to be rejected. -+A session timeout is surprising to users who do not expect to have a session to log out. -+For more information, see <>. - - [[csrf-considerations-timeouts]] - === CSRF and Session Timeouts - More often than not, the expected CSRF token is stored in the session. --This means that as soon as the session expires the server will not find an expected CSRF token and reject the HTTP request. --There are a number of options to solve timeouts each of which come with trade offs. -+This means that, as soon as the session expires, the server does not find an expected CSRF token and rejects the HTTP request. -+There are a number of options (each of which come with trade offs) to solve timeouts: - - * The best way to mitigate the timeout is by using JavaScript to request a CSRF token on form submission. - The form is then updated with the CSRF token and submitted. - * Another option is to have some JavaScript that lets the user know their session is about to expire. - The user can click a button to continue and refresh the session. - * Finally, the expected CSRF token could be stored in a cookie. --This allows the expected CSRF token to outlive the session. -+This lets the expected CSRF token outlive the session. - + --One might ask why the expected CSRF token isn't stored in a cookie by default. -+One might ask why the expected CSRF token is not stored in a cookie by default. - This is because there are known exploits in which headers (for example, to specify the cookies) can be set by another domain. --This is the same reason Ruby on Rails https://weblog.rubyonrails.org/2011/2/8/csrf-protection-bypass-in-ruby-on-rails/[no longer skips CSRF checks when the header X-Requested-With is present]. -+This is the same reason Ruby on Rails https://weblog.rubyonrails.org/2011/2/8/csrf-protection-bypass-in-ruby-on-rails/[no longer skips a CSRF checks when the header X-Requested-With is present]. - See http://lists.webappsec.org/pipermail/websecurity_lists.webappsec.org/2011-February/007533.html[this webappsec.org thread] for details on how to perform the exploit. - Another disadvantage is that by removing the state (that is, the timeout), you lose the ability to forcibly invalidate the token if it is compromised. - --// FIXME: Document timeout with lengthy form expire. We do not want to automatically replay that request because it can lead to exploit -+// FIXME: Document timeout with lengthy form expire. We do not want to automatically replay that request because it can lead to an exploit. - - [[csrf-considerations-multipart]] - === Multipart (file upload) - --Protecting multipart requests (file uploads) from CSRF attacks causes a https://en.wikipedia.org/wiki/Chicken_or_the_egg[chicken and the egg] problem. --In order to prevent a CSRF attack from occurring, the body of the HTTP request must be read to obtain actual CSRF token. --However, reading the body means that the file will be uploaded which means an external site can upload a file. -+Protecting multipart requests (file uploads) from CSRF attacks causes a https://en.wikipedia.org/wiki/Chicken_or_the_egg[chicken or the egg] problem. -+To prevent a CSRF attack from occurring, the body of the HTTP request must be read to obtain the actual CSRF token. -+However, reading the body means that the file is uploaded, which means an external site can upload a file. - --There are two options to using CSRF protection with multipart/form-data. --Each option has its trade-offs. -+There are two options to using CSRF protection with multipart/form-data: - - * <> - * <> - --[NOTE] --==== --Before you integrate Spring Security's CSRF protection with multipart file upload, ensure that you can upload without the CSRF protection first. --More information about using multipart forms with Spring can be found within the https://docs.spring.io/spring/docs/5.2.x/spring-framework-reference/web.html#mvc-multipart[1.1.11. Multipart Resolver] section of the Spring reference and the https://docs.spring.io/spring/docs/5.2.x/javadoc-api/org/springframework/web/multipart/support/MultipartFilter.html[MultipartFilter javadoc]. --==== -+Each option has its trade-offs. -+ -+NOTE: Before you integrate Spring Security's CSRF protection with multipart file upload, you should first ensure that you can upload without the CSRF protection. -+More information about using multipart forms with Spring, see the https://docs.spring.io/spring/docs/5.2.x/spring-framework-reference/web.html#mvc-multipart[1.1.11. Multipart Resolver] section of the Spring reference and the https://docs.spring.io/spring/docs/5.2.x/javadoc-api/org/springframework/web/multipart/support/MultipartFilter.html[`MultipartFilter` Javadoc]. - - [[csrf-considerations-multipart-body]] - ==== Place CSRF Token in the Body - The first option is to include the actual CSRF token in the body of the request. --By placing the CSRF token in the body, the body will be read before authorization is performed. -+By placing the CSRF token in the body, the body is read before authorization is performed. - This means that anyone can place temporary files on your server. --However, only authorized users will be able to submit a File that is processed by your application. --In general, this is the recommended approach because the temporary file upload should have a negligible impact on most servers. -+However, only authorized users can submit a file that is processed by your application. -+In general, this is the recommended approach, because the temporary file upload should have a negligible impact on most servers. - - [[csrf-considerations-multipart-url]] - ==== Include CSRF Token in URL --If allowing unauthorized users to upload temporary files is not acceptable, an alternative is to include the expected CSRF token as a query parameter in the action attribute of the form. -+If letting unauthorized users upload temporary files is not acceptable, an alternative is to include the expected CSRF token as a query parameter in the action attribute of the form. - The disadvantage to this approach is that query parameters can be leaked. - More generally, it is considered best practice to place sensitive data within the body or headers to ensure it is not leaked. --Additional information can be found in https://www.w3.org/Protocols/rfc2616/rfc2616-sec15.html#sec15.1.3[RFC 2616 Section 15.1.3 Encoding Sensitive Information in URI's]. -+You can find additional information in https://www.w3.org/Protocols/rfc2616/rfc2616-sec15.html#sec15.1.3[RFC 2616 Section 15.1.3 Encoding Sensitive Information in URI's]. - - [[csrf-considerations-override-method]] - ==== HiddenHttpMethodFilter --In some applications a form parameter can be used to override the HTTP method. --For example, the form below could be used to treat the HTTP method as a `delete` rather than a `post`. -+Some applications can use a form parameter to override the HTTP method. -+For example, the following form can treat the HTTP method as a `delete` rather than a `post`. - - .CSRF Hidden HTTP Method Form - ==== -@@ -409,5 +391,5 @@ For example, the form below could be used to treat the HTTP method as a `delete` - - Overriding the HTTP method occurs in a filter. - That filter must be placed before Spring Security's support. --Note that overriding only happens on a `post`, so this is actually unlikely to cause any real problems. --However, it is still best practice to ensure it is placed before Spring Security's filters. -+Note that overriding happens only on a `post`, so this is actually unlikely to cause any real problems. -+However, it is still best practice to ensure that it is placed before Spring Security's filters. -diff --git a/docs/manual/src/docs/asciidoc/_includes/about/exploits/headers.adoc b/docs/manual/src/docs/asciidoc/_includes/about/exploits/headers.adoc -index ee3639d937..babd63026f 100644 ---- a/docs/manual/src/docs/asciidoc/_includes/about/exploits/headers.adoc -+++ b/docs/manual/src/docs/asciidoc/_includes/about/exploits/headers.adoc -@@ -1,23 +1,17 @@ - [[headers]] - = Security HTTP Response Headers - --[NOTE] --==== --This portion of the documentation discusses the general topic of Security HTTP Response Headers. --Refer to the relevant sections for specific information on Security HTTP Response Headers <> and <> based applications. --==== -+NOTE: This portion of the documentation discusses the general topic of Security HTTP Response Headers. -+See the relevant sections for specific information on Security HTTP Response Headers in <>- and <>-based applications. - --There are many https://www.owasp.org/index.php/OWASP_Secure_Headers_Project#tab=Headers[HTTP response headers] that can be used to increase the security of web applications. --This section is dedicated to the various HTTP response headers that Spring Security provides explicit support for. --If necessary, Spring Security can also be configured to provide <>. -+You can use https://www.owasp.org/index.php/OWASP_Secure_Headers_Project#tab=Headers[HTTP response headers] in many ways to increase the security of web applications. -+This section is dedicated to the various HTTP response headers for which Spring Security provides explicit support. -+If necessary, you can also configure Spring Security to provide <>. - - [[headers-default]] - == Default Security Headers - --[NOTE] --==== --Refer to the relevant sections to see how to customize the defaults for both <> and <> based applications. --==== -+NOTE: See the relevant sections for how to customize the defaults for both <>- and <>-based applications. - - Spring Security provides a default set of security related HTTP response headers to provide secure defaults. - -@@ -37,10 +31,10 @@ X-XSS-Protection: 1; mode=block - ---- - ==== - --NOTE: Strict-Transport-Security is only added on HTTPS requests -+NOTE: Strict-Transport-Security is added only on HTTPS requests - - If the defaults do not meet your needs, you can easily remove, modify, or add headers from these defaults. --For additional details on each of these headers, refer to the corresponding sections: -+For additional details on each of these headers, see the corresponding sections: - - * <> - * <> -@@ -51,14 +45,11 @@ For additional details on each of these headers, refer to the corresponding sect - [[headers-cache-control]] - == Cache Control - --[NOTE] --==== --Refer to the relevant sections to see how to customize the defaults for both <> and <> based applications. --==== -+NOTE: See the relevant sections for how to customize the defaults for both <>- and <>-based applications. - --Spring Security's default is to disable caching to protect user's content. -+Spring Security's default is to disable caching to protect the user's content. - --If a user authenticates to view sensitive information and then logs out, we don't want a malicious user to be able to click the back button to view the sensitive information. -+If a user authenticates to view sensitive information and then logs out, we do not want a malicious user to be able to click the back button to view the sensitive information. - The cache control headers that are sent by default are: - - .Default Cache Control HTTP Response Headers -@@ -71,35 +62,29 @@ Expires: 0 - ---- - ==== - --In order to be secure by default, Spring Security adds these headers by default. --However, if your application provides its own cache control headers Spring Security will back out of the way. --This allows for applications to ensure that static resources like CSS and JavaScript can be cached. -+To be secure by default, Spring Security adds these headers by default. -+However, if your application provides its own cache control headers, Spring Security backs out of the way. -+This allows for applications to ensure that static resources (such as CSS and JavaScript) can be cached. - - - [[headers-content-type-options]] - == Content Type Options - --[NOTE] --==== --Refer to the relevant sections to see how to customize the defaults for both <> and <> based applications. --==== -+NOTE: See the relevant sections for how to customize the defaults for both <>- and <>-based applications. - --Historically browsers, including Internet Explorer, would try to guess the content type of a request using https://en.wikipedia.org/wiki/Content_sniffing[content sniffing]. --This allowed browsers to improve the user experience by guessing the content type on resources that had not specified the content type. -+Historically, browsers, including Internet Explorer, would try to guess the content type of a request by using https://en.wikipedia.org/wiki/Content_sniffing[content sniffing]. -+This let browsers improve the user experience by guessing the content type on resources that had not specified the content type. - For example, if a browser encountered a JavaScript file that did not have the content type specified, it would be able to guess the content type and then run it. - --[NOTE] --==== --There are many additional things one should do (i.e. only display the document in a distinct domain, ensure Content-Type header is set, sanitize the document, etc) when allowing content to be uploaded. -+NOTE: There are many additional things one should do (such as only display the document in a distinct domain, ensure Content-Type header is set, sanitize the document, and others) when allowing content to be uploaded. - However, these measures are out of the scope of what Spring Security provides. --It is also important to point out when disabling content sniffing, you must specify the content type in order for things to work properly. --==== -+It is also important to point out that, when disabling content sniffing, you must specify the content type in order for things to work properly. - --The problem with content sniffing is that this allowed malicious users to use polyglots (i.e. a file that is valid as multiple content types) to perform XSS attacks. -+The problem with content sniffing is that this allowed malicious users to use polyglots (that is, a file that is valid as multiple content types) to perform XSS attacks. - For example, some sites may allow users to submit a valid postscript document to a website and view it. --A malicious user might create a http://webblaze.cs.berkeley.edu/papers/barth-caballero-song.pdf[postscript document that is also a valid JavaScript file] and perform a XSS attack with it. -+A malicious user might create a http://webblaze.cs.berkeley.edu/papers/barth-caballero-song.pdf[postscript document that is also a valid JavaScript file] and perform an XSS attack with it. - --Spring Security disables content sniffing by default by adding the following header to HTTP responses: -+By default, Spring Security disables content sniffing by adding the following header to HTTP responses: - - .nosniff HTTP Response Header - ==== -@@ -112,28 +97,22 @@ X-Content-Type-Options: nosniff - [[headers-hsts]] - == HTTP Strict Transport Security (HSTS) - --[NOTE] --==== --Refer to the relevant sections to see how to customize the defaults for both <> and <> based applications. --==== -+NOTE: Refer to the relevant sections to see how to customize the defaults for both <> and <> based applications. - --When you type in your bank's website, do you enter mybank.example.com or do you enter https://mybank.example.com[]? --If you omit the https protocol, you are potentially vulnerable to https://en.wikipedia.org/wiki/Man-in-the-middle_attack[Man in the Middle attacks]. --Even if the website performs a redirect to https://mybank.example.com a malicious user could intercept the initial HTTP request and manipulate the response (e.g. redirect to https://mibank.example.com and steal their credentials). -+When you type in your bank's website, do you enter `mybank.example.com` or do you enter `https://mybank.example.com`? -+If you omit the `https` protocol, you are potentially vulnerable to https://en.wikipedia.org/wiki/Man-in-the-middle_attack[Man-in-the-Middle attacks]. -+Even if the website performs a redirect to https://mybank.example.com, a malicious user could intercept the initial HTTP request and manipulate the response (for example, redirect to https://mibank.example.com and steal their credentials). - --Many users omit the https protocol and this is why https://tools.ietf.org/html/rfc6797[HTTP Strict Transport Security (HSTS)] was created. --Once mybank.example.com is added as a https://tools.ietf.org/html/rfc6797#section-5.1[HSTS host], a browser can know ahead of time that any request to mybank.example.com should be interpreted as https://mybank.example.com. --This greatly reduces the possibility of a Man in the Middle attack occurring. -+Many users omit the `https` protocol, and this is why https://tools.ietf.org/html/rfc6797[HTTP Strict Transport Security (HSTS)] was created. -+Once `mybank.example.com` is added as a https://tools.ietf.org/html/rfc6797#section-5.1[HSTS host], a browser can know ahead of time that any request to mybank.example.com should be interpreted as https://mybank.example.com. -+This greatly reduces the possibility of a Man-in-the-Middle attack occurring. - --[NOTE] --==== --In accordance with https://tools.ietf.org/html/rfc6797#section-7.2[RFC6797], the HSTS header is only injected into HTTPS responses. --In order for the browser to acknowledge the header, the browser must first trust the CA that signed the SSL certificate used to make the connection (not just the SSL certificate). --==== -+NOTE: In accordance with https://tools.ietf.org/html/rfc6797#section-7.2[RFC6797], the HSTS header is injected only into HTTPS responses. -+For the browser to acknowledge the header, the browser must first trust the CA that signed the SSL certificate used to make the connection (not just the SSL certificate). - - One way for a site to be marked as a HSTS host is to have the host preloaded into the browser. --Another is to add the `Strict-Transport-Security` header to the response. --For example, Spring Security's default behavior is to add the following header which instructs the browser to treat the domain as an HSTS host for a year (there are approximately 31536000 seconds in a year): -+Another way is to add the `Strict-Transport-Security` header to the response. -+For example, Spring Security's default behavior is to add the following header, which instructs the browser to treat the domain as an HSTS host for a year (there are 31536000 seconds in a non-leap year): - - - .Strict Transport Security HTTP Response Header -@@ -144,99 +123,83 @@ Strict-Transport-Security: max-age=31536000 ; includeSubDomains ; preload - ---- - ==== - --The optional `includeSubDomains` directive instructs the browser that subdomains (e.g. secure.mybank.example.com) should also be treated as an HSTS domain. -+The optional `includeSubDomains` directive instructs the browser that subdomains (such as `secure.mybank.example.com`) should also be treated as an HSTS domain. - --The optional `preload` directive instructs the browser that domain should be preloaded in browser as HSTS domain. --For more details on HSTS preload please see https://hstspreload.org. -+The optional `preload` directive instructs the browser that the domain should be preloaded in browser as an HSTS domain. -+For more details on HSTS preload, see https://hstspreload.org. - - [[headers-hpkp]] - == HTTP Public Key Pinning (HPKP) - --[NOTE] --==== --In order to remain passive Spring Security still provides <>, but for the reasons listed above HPKP is no longer recommended by the security team. --==== -+NOTE: To remain passive, Spring Security still provides <>. However, for the reasons listed earlier, HPKP is no longer recommended by the Spring Security team. - --https://developer.mozilla.org/en-US/docs/Web/HTTP/Public_Key_Pinning[HTTP Public Key Pinning (HPKP)] specifies to a web client which public key to use with certain web server to prevent Man in the Middle (MITM) attacks with forged certificates. -+https://developer.mozilla.org/en-US/docs/Web/HTTP/Public_Key_Pinning[HTTP Public Key Pinning (HPKP)] specifies to a web client which public key to use with a certain web server to prevent Man-in-the-Middle (MITM) attacks with forged certificates. - When used correctly, HPKP could add additional layers of protection against compromised certificates. --However, due to the complexity of HPKP many experts no longer recommend using it and https://www.chromestatus.com/feature/5903385005916160[Chrome has even removed support] for it. -+However, due to the complexity of HPKP, many experts no longer recommend using it and https://www.chromestatus.com/feature/5903385005916160[Chrome has even removed support] for it. - - [[headers-hpkp-deprecated]] --For additional details around why HPKP is no longer recommended read https://blog.qualys.com/ssllabs/2016/09/06/is-http-public-key-pinning-dead[ --Is HTTP Public Key Pinning Dead?] and https://scotthelme.co.uk/im-giving-up-on-hpkp/[I'm giving up on HPKP]. -+For additional details around why HPKP is no longer recommended, read https://blog.qualys.com/ssllabs/2016/09/06/is-http-public-key-pinning-dead[Is HTTP Public Key Pinning Dead?] and https://scotthelme.co.uk/im-giving-up-on-hpkp/[I'm giving up on HPKP]. - - [[headers-frame-options]] - == X-Frame-Options - --[NOTE] --==== --Refer to the relevant sections to see how to customize the defaults for both <> and <> based applications. --==== -+NOTE: See the relevant sections to see how to customize the defaults for both <> and <> based applications. - --Allowing your website to be added to a frame can be a security issue. --For example, using clever CSS styling users could be tricked into clicking on something that they were not intending. -+Letting your website be added to a frame can be a security issue. -+For example, by using clever CSS styling, users could be tricked into clicking on something that they were not intending. - For example, a user that is logged into their bank might click a button that grants access to other users. - This sort of attack is known as https://en.wikipedia.org/wiki/Clickjacking[Clickjacking]. - --[NOTE] --==== --Another modern approach to dealing with clickjacking is to use <>. --==== -+NOTE: Another modern approach to dealing with clickjacking is to use <>. - - There are a number ways to mitigate clickjacking attacks. --For example, to protect legacy browsers from clickjacking attacks you can use https://www.owasp.org/index.php/Clickjacking_Defense_Cheat_Sheet#Best-for-now_Legacy_Browser_Frame_Breaking_Script[frame breaking code]. -+For example, to protect legacy browsers from clickjacking attacks, you can use https://www.owasp.org/index.php/Clickjacking_Defense_Cheat_Sheet#Best-for-now_Legacy_Browser_Frame_Breaking_Script[frame breaking code]. - While not perfect, the frame breaking code is the best you can do for the legacy browsers. - - A more modern approach to address clickjacking is to use https://developer.mozilla.org/en-US/docs/HTTP/X-Frame-Options[X-Frame-Options] header. --By default Spring Security disables rendering pages within an iframe using with the following header: -+By default, Spring Security disables rendering pages within an iframe by using with the following header: - -+==== - [source] - ---- - X-Frame-Options: DENY - ---- -+==== - - [[headers-xss-protection]] - == X-XSS-Protection - --[NOTE] --==== --Refer to the relevant sections to see how to customize the defaults for both <> and <> based applications. --==== -+NOTE: See the relevant sections to see how to customize the defaults for both <>- and <>-based applications. - --Some browsers have built in support for filtering out https://www.owasp.org/index.php/Testing_for_Reflected_Cross_site_scripting_(OWASP-DV-001)[reflected XSS attacks]. --This is by no means foolproof, but does assist in XSS protection. -+Some browsers have built-in support for filtering out https://www.owasp.org/index.php/Testing_for_Reflected_Cross_site_scripting_(OWASP-DV-001)[reflected XSS attacks]. -+This is by no means foolproof but does assist in XSS protection. - - The filtering is typically enabled by default, so adding the header typically just ensures it is enabled and instructs the browser what to do when a XSS attack is detected. - For example, the filter might try to change the content in the least invasive way to still render everything. --At times, this type of replacement can become a https://hackademix.net/2009/11/21/ies-xss-filter-creates-xss-vulnerabilities/[XSS vulnerability in itself]. -+At times, this type of replacement can become an https://hackademix.net/2009/11/21/ies-xss-filter-creates-xss-vulnerabilities/[XSS vulnerability in itself]. - Instead, it is best to block the content rather than attempt to fix it. --By default Spring Security blocks the content using the following header: -+By default, Spring Security blocks the content by using the following header: - -+==== - [source] - ---- - X-XSS-Protection: 1; mode=block - ---- -- -+==== - - [[headers-csp]] - == Content Security Policy (CSP) - --[NOTE] --==== --Refer to the relevant sections to see how to configure both <> and <> based applications. --==== -+NOTE: See the relevant sections to see how to configure both <>- and <>-based applications. - --https://www.w3.org/TR/CSP2/[Content Security Policy (CSP)] is a mechanism that web applications can leverage to mitigate content injection vulnerabilities, such as cross-site scripting (XSS). -+https://www.w3.org/TR/CSP2/[Content Security Policy (CSP)] is a mechanism that web applications can use to mitigate content injection vulnerabilities, such as cross-site scripting (XSS). - CSP is a declarative policy that provides a facility for web application authors to declare and ultimately inform the client (user-agent) about the sources from which the web application expects to load resources. - --[NOTE] --==== --Content Security Policy is not intended to solve all content injection vulnerabilities. --Instead, CSP can be leveraged to help reduce the harm caused by content injection attacks. -+NOTE: Content Security Policy is not intended to solve all content injection vulnerabilities. -+Instead, you can use CSP to help reduce the harm caused by content injection attacks. - As a first line of defense, web application authors should validate their input and encode their output. --==== - --A web application may employ the use of CSP by including one of the following HTTP headers in the response: -+A web application can use CSP by including one of the following HTTP headers in the response: - - * `Content-Security-Policy` - * `Content-Security-Policy-Report-Only` -@@ -244,7 +207,7 @@ A web application may employ the use of CSP by including one of the following HT - Each of these headers are used as a mechanism to deliver a security policy to the client. - A security policy contains a set of security policy directives, each responsible for declaring the restrictions for a particular resource representation. - --For example, a web application can declare that it expects to load scripts from specific, trusted sources, by including the following header in the response: -+For example, a web application can declare that it expects to load scripts from specific, trusted sources by including the following header in the response: - - .Content Security Policy Example - ==== -@@ -254,10 +217,10 @@ Content-Security-Policy: script-src https://trustedscripts.example.com - ---- - ==== - --An attempt to load a script from another source other than what is declared in the `script-src` directive will be blocked by the user-agent. --Additionally, if the https://www.w3.org/TR/CSP2/#directive-report-uri[report-uri] directive is declared in the security policy, then the violation will be reported by the user-agent to the declared URL. -+An attempt to load a script from another source other than what is declared in the `script-src` directive is blocked by the user-agent. -+Additionally, if the https://www.w3.org/TR/CSP2/#directive-report-uri[report-uri] directive is declared in the security policy, the violation will be reported by the user-agent to the declared URL. - --For example, if a web application violates the declared security policy, the following response header will instruct the user-agent to send violation reports to the URL specified in the policy's `report-uri` directive. -+For example, if a web application violates the declared security policy, the following response header instructs the user-agent to send violation reports to the URL specified in the policy's `report-uri` directive. - - .Content Security Policy with report-uri - ==== -@@ -267,13 +230,13 @@ Content-Security-Policy: script-src https://trustedscripts.example.com; report-u - ---- - ==== - --https://www.w3.org/TR/CSP2/#violation-reports[Violation reports] are standard JSON structures that can be captured either by the web application's own API or by a publicly hosted CSP violation reporting service, such as, https://report-uri.io/. -+https://www.w3.org/TR/CSP2/#violation-reports[Violation reports] are standard JSON structures that can be captured either by the web application's own API or by a publicly hosted CSP violation reporting service, such as https://report-uri.io/. - --The `Content-Security-Policy-Report-Only` header provides the capability for web application authors and administrators to monitor security policies, rather than enforce them. --This header is typically used when experimenting and/or developing security policies for a site. -+The `Content-Security-Policy-Report-Only` header provides the capability for web application authors and administrators to monitor security policies rather than enforce them. -+This header is typically used when experimenting or developing security policies for a site. - When a policy is deemed effective, it can be enforced by using the `Content-Security-Policy` header field instead. - --Given the following response header, the policy declares that scripts may be loaded from one of two possible sources. -+Given the following response header, the policy declares that scripts can be loaded from one of two possible sources. - - .Content Security Policy Report Only - ==== -@@ -283,10 +246,10 @@ Content-Security-Policy-Report-Only: script-src 'self' https://trustedscripts.ex - ---- - ==== - --If the site violates this policy, by attempting to load a script from _evil.com_, the user-agent will send a violation report to the declared URL specified by the _report-uri_ directive, but still allow the violating resource to load nevertheless. -+If the site violates this policy, by attempting to load a script from evil.com, the user-agent sends a violation report to the declared URL specified by the `report-uri` directive but still lets the violating resource load. - - Applying Content Security Policy to a web application is often a non-trivial undertaking. --The following resources may provide further assistance in developing effective security policies for your site. -+The following resources may provide further assistance in developing effective security policies for your site: - - https://www.html5rocks.com/en/tutorials/security/content-security-policy/[An Introduction to Content Security Policy] - -@@ -297,15 +260,12 @@ https://www.w3.org/TR/CSP2/[W3C Candidate Recommendation] - [[headers-referrer]] - == Referrer Policy - --[NOTE] --==== --Refer to the relevant sections to see how to configure both <> and <> based applications. --==== -+NOTE: See the relevant sections to see how to configure both <>- and <>-based applications. - --https://www.w3.org/TR/referrer-policy[Referrer Policy] is a mechanism that web applications can leverage to manage the referrer field, which contains the last -+https://www.w3.org/TR/referrer-policy[Referrer Policy] is a mechanism that web applications can use to manage the referrer field, which contains the last - page the user was on. - --Spring Security's approach is to use https://www.w3.org/TR/referrer-policy/[Referrer Policy] header, which provides different https://www.w3.org/TR/referrer-policy/#referrer-policies[policies]: -+Spring Security's approach is to use the https://www.w3.org/TR/referrer-policy/[Referrer Policy] header, which provides different https://www.w3.org/TR/referrer-policy/#referrer-policies[policies]: - - .Referrer Policy Example - ==== -@@ -320,12 +280,9 @@ The Referrer-Policy response header instructs the browser to let the destination - [[headers-feature]] - == Feature Policy - --[NOTE] --==== --Refer to the relevant sections to see how to configure both <> and <> based applications. --==== -+NOTE: See the relevant sections to see how to configure both <>- and <>-based applications. - --https://wicg.github.io/feature-policy/[Feature Policy] is a mechanism that allows web developers to selectively enable, disable, and modify the behavior of certain APIs and web features in the browser. -+https://wicg.github.io/feature-policy/[Feature Policy] is a mechanism that lets web developers selectively enable, disable, and modify the behavior of certain APIs and web features in the browser. - - .Feature Policy Example - ==== -@@ -335,19 +292,16 @@ Feature-Policy: geolocation 'self' - ---- - ==== - --With Feature Policy, developers can opt-in to a set of "policies" for the browser to enforce on specific features used throughout your site. -+With Feature Policy, developers can opt-in to a set of "`policies`" for the browser to enforce on specific features used throughout your site. - These policies restrict what APIs the site can access or modify the browser's default behavior for certain features. - - - [[headers-permissions]] - == Permissions Policy - --[NOTE] --==== --Refer to the relevant sections to see how to configure both <> and <> based applications. --==== -+NOTE: See the relevant sections to see how to configure both <>- and <>-based applications. - --https://w3c.github.io/webappsec-permissions-policy/[Permissions Policy] is a mechanism that allows web developers to selectively enable, disable, and modify the behavior of certain APIs and web features in the browser. -+https://w3c.github.io/webappsec-permissions-policy/[Permissions Policy] is a mechanism that lets web developers selectively enable, disable, and modify the behavior of certain APIs and web features in the browser. - - .Permissions Policy Example - ==== -@@ -357,24 +311,23 @@ Permissions-Policy: geolocation=(self) - ---- - ==== - --With Permissions Policy, developers can opt-in to a set of "policies" for the browser to enforce on specific features used throughout your site. -+With a Permissions Policy, developers can opt-in to a set of "`policies`" for the browser to enforce on specific features used throughout your site. - These policies restrict what APIs the site can access or modify the browser's default behavior for certain features. - - - [[headers-clear-site-data]] - == Clear Site Data - --[NOTE] --==== --Refer to the relevant sections to see how to configure both <> and <> based applications. --==== -+NOTE: See the relevant sections to see how to configure both <> and <> based applications. - --https://www.w3.org/TR/clear-site-data/[Clear Site Data] is a mechanism by which any browser-side data - cookies, local storage, and the like - can be removed when an HTTP response contains this header: -+https://www.w3.org/TR/clear-site-data/[Clear Site Data] is a mechanism by which any browser-side data (cookies, local storage, and the like) can be removed when an HTTP response contains this header: - -+==== - [source] - ---- - Clear-Site-Data: "cache", "cookies", "storage", "executionContexts" - ---- -+==== - - This is a nice clean-up action to perform on logout. - -@@ -382,10 +335,7 @@ This is a nice clean-up action to perform on logout. - [[headers-custom]] - == Custom Headers - --[NOTE] --==== --Refer to the relevant sections to see how to configure both <> based applications. --==== -+NOTE: See the relevant sections to see how to configure both <> based applications. - - Spring Security has mechanisms to make it convenient to add the more common security headers to your application. - However, it also provides hooks to enable adding custom headers. -diff --git a/docs/manual/src/docs/asciidoc/_includes/about/exploits/http.adoc b/docs/manual/src/docs/asciidoc/_includes/about/exploits/http.adoc -index 5d0dfa6c32..68f6631e6f 100644 ---- a/docs/manual/src/docs/asciidoc/_includes/about/exploits/http.adoc -+++ b/docs/manual/src/docs/asciidoc/_includes/about/exploits/http.adoc -@@ -1,7 +1,7 @@ - [[http]] - = HTTP - --All HTTP based communication, including https://www.troyhunt.com/heres-why-your-static-website-needs-https/[static resources], should be protected https://cheatsheetseries.owasp.org/cheatsheets/Transport_Layer_Protection_Cheat_Sheet.html[using TLS]. -+All HTTP-based communication, including https://www.troyhunt.com/heres-why-your-static-website-needs-https/[static resources], should be protected by https://cheatsheetseries.owasp.org/cheatsheets/Transport_Layer_Protection_Cheat_Sheet.html[using TLS]. - - As a framework, Spring Security does not handle HTTP connections and thus does not provide support for HTTPS directly. - However, it does provide a number of features that help with HTTPS usage. -@@ -9,7 +9,7 @@ However, it does provide a number of features that help with HTTPS usage. - [[http-redirect]] - == Redirect to HTTPS - --When a client uses HTTP, Spring Security can be configured to redirect to HTTPS both <> and <> environments. -+When a client uses HTTP, you can configure Spring Security to redirect to HTTPS in both <> and <> environments. - - [[http-hsts]] - == Strict Transport Security -@@ -19,14 +19,14 @@ Spring Security provides support for <> - [[http-proxy-server]] - == 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 --Without proper configuration, the application server will not know that the load balancer exists and treat the request as though https://192.168.1:8080 was requested by the client. -+When using a proxy server, it is important to ensure that you have configured your application properly. -+For example, many applications 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 -+Without proper configuration, the application server can not know that the load balancer exists and treats the request as though https://192.168.1:8080 was requested by the client. - --To fix this you can use https://tools.ietf.org/html/rfc7239[RFC 7239] to specify that a load balancer is being used. --To make the application aware of this, you need to either configure your application server aware of the X-Forwarded headers. --For example Tomcat uses the https://tomcat.apache.org/tomcat-8.0-doc/api/org/apache/catalina/valves/RemoteIpValve.html[RemoteIpValve] and Jetty uses https://download.eclipse.org/jetty/stable-9/apidocs/org/eclipse/jetty/server/ForwardedRequestCustomizer.html[ForwardedRequestCustomizer]. --Alternatively, Spring users can leverage https://github.com/spring-projects/spring-framework/blob/v4.3.3.RELEASE/spring-web/src/main/java/org/springframework/web/filter/ForwardedHeaderFilter.java[ForwardedHeaderFilter]. -+To fix this, you can use https://tools.ietf.org/html/rfc7239[RFC 7239] to specify that a load balancer is being used. -+To make the application aware of this, you need to configure your application server to be aware of the X-Forwarded headers. -+For example, Tomcat uses https://tomcat.apache.org/tomcat-8.0-doc/api/org/apache/catalina/valves/RemoteIpValve.html[`RemoteIpValve`] and Jetty uses https://download.eclipse.org/jetty/stable-9/apidocs/org/eclipse/jetty/server/ForwardedRequestCustomizer.html[`ForwardedRequestCustomizer`]. -+Alternatively, Spring users can use https://github.com/spring-projects/spring-framework/blob/v4.3.3.RELEASE/spring-web/src/main/java/org/springframework/web/filter/ForwardedHeaderFilter.java[`ForwardedHeaderFilter`]. - --Spring Boot users may use the `server.use-forward-headers` property to configure the application. -+Spring Boot users can use the `server.use-forward-headers` property to configure the application. - See the https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#howto-use-tomcat-behind-a-proxy-server[Spring Boot documentation] for further details. -diff --git a/docs/manual/src/docs/asciidoc/_includes/about/exploits/index.adoc b/docs/manual/src/docs/asciidoc/_includes/about/exploits/index.adoc -index bb8abc73dc..eb5ef9b637 100644 ---- a/docs/manual/src/docs/asciidoc/_includes/about/exploits/index.adoc -+++ b/docs/manual/src/docs/asciidoc/_includes/about/exploits/index.adoc -@@ -3,7 +3,7 @@ - - Spring Security provides protection against common exploits. - Whenever possible, the protection is enabled by default. --Below you will find high level description of the various exploits that Spring Security protects against. -+This section describes the various exploits that Spring Security protects against. - - include::csrf.adoc[leveloffset=+1] - -diff --git a/docs/manual/src/docs/asciidoc/_includes/about/features.adoc b/docs/manual/src/docs/asciidoc/_includes/about/features.adoc -index c08113ae5e..9ce044b519 100644 ---- a/docs/manual/src/docs/asciidoc/_includes/about/features.adoc -+++ b/docs/manual/src/docs/asciidoc/_includes/about/features.adoc -@@ -1,6 +1,7 @@ - [[features]] - = Features - -+// FIXME: Add a link for authorization - Spring Security provides comprehensive support for <>, authorization, and protection against <>. - It also provides integration with other libraries to simplify its usage. - -diff --git a/docs/manual/src/docs/asciidoc/_includes/about/getting-spring-security.adoc b/docs/manual/src/docs/asciidoc/_includes/about/getting-spring-security.adoc -index c2b64f113a..464ee567dc 100644 ---- a/docs/manual/src/docs/asciidoc/_includes/about/getting-spring-security.adoc -+++ b/docs/manual/src/docs/asciidoc/_includes/about/getting-spring-security.adoc -@@ -1,7 +1,7 @@ - [[getting]] - = Getting Spring Security - --This section discusses all you need to know about getting the Spring Security binaries. -+This section describes how to get the Spring Security binaries. - See <> for how to obtain the source code. - - == Release Numbering -@@ -10,7 +10,7 @@ Spring Security versions are formatted as MAJOR.MINOR.PATCH such that: - - * MAJOR versions may contain breaking changes. - Typically, these are done to provide improved security to match modern security practices. --* MINOR versions contain enhancements but are considered passive updates -+* MINOR versions contain enhancements but are considered passive updates. - * PATCH level should be perfectly compatible, forwards and backwards, with the possible exception of changes that fix bugs. - - -@@ -18,13 +18,13 @@ Typically, these are done to provide improved security to match modern security - == Usage with Maven - - As most open source projects, Spring Security deploys its dependencies as Maven artifacts. --The topics in this section provide detail on how to consume Spring Security when using Maven. -+The topics in this section describe how to consume Spring Security when using Maven. - - [[getting-maven-boot]] - === Spring Boot with Maven - --Spring Boot provides a `spring-boot-starter-security` starter that aggregates Spring Security-related dependencies together. --The simplest and preferred way to use the starter is to use https://docs.spring.io/initializr/docs/current/reference/htmlsingle/[Spring Initializr] by using an IDE integration (https://joshlong.com/jl/blogPost/tech_tip_geting_started_with_spring_boot.html[Eclipse], https://www.jetbrains.com/help/idea/spring-boot.html#d1489567e2[IntelliJ], https://github.com/AlexFalappa/nb-springboot/wiki/Quick-Tour[NetBeans]) or through https://start.spring.io. -+Spring Boot provides a `spring-boot-starter-security` starter that aggregates Spring Security-related dependencies. -+The simplest and preferred way to use the starter is to use https://docs.spring.io/initializr/docs/current/reference/htmlsingle/[Spring Initializr] by using an IDE integration in (https://joshlong.com/jl/blogPost/tech_tip_geting_started_with_spring_boot.html[Eclipse] or https://www.jetbrains.com/help/idea/spring-boot.html#d1489567e2[IntelliJ], https://github.com/AlexFalappa/nb-springboot/wiki/Quick-Tour[NetBeans]) or through https://start.spring.io. - - Alternatively, you can manually add the starter, as the following example shows: - -@@ -44,7 +44,7 @@ Alternatively, you can manually add the starter, as the following example shows: - ==== - - Since Spring Boot provides a Maven BOM to manage dependency versions, you do not need to specify a version. --If you wish to override the Spring Security version, you may do so by providing a Maven property, as the following example shows: -+If you wish to override the Spring Security version, you can do so by providing a Maven property: - - .pom.xml - ==== -@@ -57,9 +57,9 @@ If you wish to override the Spring Security version, you may do so by providing - ---- - ==== - --Since Spring Security makes breaking changes only in major releases, it is safe to use a newer version of Spring Security with Spring Boot. -+Since Spring Security makes breaking changes only in major releases, you can safely use a newer version of Spring Security with Spring Boot. - However, at times, you may need to update the version of Spring Framework as well. --You can do so by adding a Maven property, as the following example shows: -+You can do so by adding a Maven property: - - .pom.xml - ==== -@@ -72,12 +72,12 @@ You can do so by adding a Maven property, as the following example shows: - ---- - ==== - --If you use additional features (such as LDAP, OpenID, and others), you need to also include the appropriate <>. -+If you use additional features (such as LDAP, OpenID, and others), you need to also include the appropriate <>. - - [[getting-maven-no-boot]] - === Maven Without Spring Boot - --When you use Spring Security without Spring Boot, the preferred way is to use Spring Security's BOM to ensure a consistent version of Spring Security is used throughout the entire project. The following example shows how to do so: -+When you use Spring Security without Spring Boot, the preferred way is to use Spring Security's BOM to ensure that a consistent version of Spring Security is used throughout the entire project. The following example shows how to do so: - - .pom.xml - ==== -@@ -98,7 +98,7 @@ When you use Spring Security without Spring Boot, the preferred way is to use Sp - ---- - ==== - --A minimal Spring Security Maven set of dependencies typically looks like the following: -+A minimal Spring Security Maven set of dependencies typically looks like the following example: - - .pom.xml - ==== -@@ -118,11 +118,11 @@ A minimal Spring Security Maven set of dependencies typically looks like the fol - ---- - ==== - --If you use additional features (such as LDAP, OpenID, and others), you need to also include the appropriate <>. -+If you use additional features (such as LDAP, OpenID, and others), you need to also include the appropriate <>. - - Spring Security builds against Spring Framework {spring-core-version} but should generally work with any newer version of Spring Framework 5.x. - Many users are likely to run afoul of the fact that Spring Security's transitive dependencies resolve Spring Framework {spring-core-version}, which can cause strange classpath problems. --The easiest way to resolve this is to use the `spring-framework-bom` within the `` section of your `pom.xml` as the following example shows: -+The easiest way to resolve this is to use the `spring-framework-bom` within the `` section of your `pom.xml`: - - .pom.xml - ==== -@@ -150,9 +150,9 @@ For additional details about how dependencies are resolved, see https://maven.ap - - [[maven-repositories]] - === Maven Repositories --All GA releases (that is, versions ending in .RELEASE) are deployed to Maven Central, so no additional Maven repositories need to be declared in your pom. -+All GA releases (that is, versions ending in .RELEASE) are deployed to Maven Central, so you need not declare additional Maven repositories in your pom. - --If you use a SNAPSHOT version, you need to ensure that you have the Spring Snapshot repository defined, as the following example shows: -+If you use a SNAPSHOT version, you need to ensure that you have the Spring Snapshot repository defined: - - .pom.xml - ==== -@@ -190,15 +190,15 @@ If you use a milestone or release candidate version, you need to ensure that you - == Gradle - - As most open source projects, Spring Security deploys its dependencies as Maven artifacts, which allows for first-class Gradle support. --The following topics provide detail on how to consume Spring Security when using Gradle. -+The following topics describe how to consume Spring Security when using Gradle. - - [[getting-gradle-boot]] - === Spring Boot with Gradle - --Spring Boot provides a `spring-boot-starter-security` starter that aggregates Spring Security related dependencies together. --The simplest and preferred method to use the starter is to use https://docs.spring.io/initializr/docs/current/reference/htmlsingle/[Spring Initializr] by using an IDE integration (https://joshlong.com/jl/blogPost/tech_tip_geting_started_with_spring_boot.html[Eclipse], https://www.jetbrains.com/help/idea/spring-boot.html#d1489567e2[IntelliJ], https://github.com/AlexFalappa/nb-springboot/wiki/Quick-Tour[NetBeans]) or through https://start.spring.io. -+Spring Boot provides a `spring-boot-starter-security` starter that aggregates Spring Security related dependencies. -+The simplest and preferred method to use the starter is to use https://docs.spring.io/initializr/docs/current/reference/htmlsingle/[Spring Initializr] by using an IDE integration in (https://joshlong.com/jl/blogPost/tech_tip_geting_started_with_spring_boot.html[Eclipse] or https://www.jetbrains.com/help/idea/spring-boot.html#d1489567e2[IntelliJ], https://github.com/AlexFalappa/nb-springboot/wiki/Quick-Tour[NetBeans]) or through https://start.spring.io. - --Alternatively, you can manually add the starter, as the following example shows: -+Alternatively, you can manually add the starter: - - .build.gradle - ==== -@@ -212,7 +212,7 @@ dependencies { - ==== - - Since Spring Boot provides a Maven BOM to manage dependency versions, you need not specify a version. --If you wish to override the Spring Security version, you may do so by providing a Gradle property, as the following example shows: -+If you wish to override the Spring Security version, you can do so by providing a Gradle property: - - .build.gradle - ==== -@@ -223,9 +223,9 @@ ext['spring-security.version']='{spring-security-version}' - ---- - ==== - --Since Spring Security makes breaking changes only in major releases, it is safe to use a newer version of Spring Security with Spring Boot. -+Since Spring Security makes breaking changes only in major releases, you can safely use a newer version of Spring Security with Spring Boot. - However, at times, you may need to update the version of Spring Framework as well. --You can do so by adding a Gradle property, as the following example shows: -+You can do so by adding a Gradle property: - - .build.gradle - ==== -@@ -236,12 +236,12 @@ ext['spring.version']='{spring-core-version}' - ---- - ==== - --If you use additional features (such as LDAP, OpenID, and others), you need to also include the appropriate <>. -+If you use additional features (such as LDAP, OpenID, and others), you need to also include the appropriate <>. - - === Gradle Without Spring Boot - - When you use Spring Security without Spring Boot, the preferred way is to use Spring Security's BOM to ensure a consistent version of Spring Security is used throughout the entire project. --You can do so by using the https://github.com/spring-gradle-plugins/dependency-management-plugin[Dependency Management Plugin], as the following example shows: -+You can do so by using the https://github.com/spring-gradle-plugins/dependency-management-plugin[Dependency Management Plugin]: - - .build.gradle - ==== -@@ -260,7 +260,7 @@ dependencyManagement { - ---- - ==== - --A minimal Spring Security Maven set of dependencies typically looks like the following: -+A minimal Spring Security Maven set of dependencies typically looks like the following example: - - .build.gradle - ==== -@@ -274,12 +274,12 @@ dependencies { - ---- - ==== - --If you use additional features (such as LDAP, OpenID, and others), you need to also include the appropriate <>. -+If you use additional features (such as LDAP, OpenID, and others), you need to also include the appropriate <>. - - Spring Security builds against Spring Framework {spring-core-version} but should generally work with any newer version of Spring Framework 5.x. - Many users are likely to run afoul of the fact that Spring Security's transitive dependencies resolve Spring Framework {spring-core-version}, which can cause strange classpath problems. - The easiest way to resolve this is to use the `spring-framework-bom` within your `` section of your `pom.xml`. --You can do so by using the https://github.com/spring-gradle-plugins/dependency-management-plugin[Dependency Management Plugin], as the following example shows: -+You can do so by using the https://github.com/spring-gradle-plugins/dependency-management-plugin[Dependency Management Plugin]: - - .build.gradle - ==== -@@ -302,7 +302,7 @@ The preceding example ensures that all the transitive dependencies of Spring Sec - - [[gradle-repositories]] - === Gradle Repositories --All GA releases (that is, versions ending in .RELEASE) are deployed to Maven Central, so using the mavenCentral() repository is sufficient for GA releases. The following example shows how to do so: -+All GA releases (that is, versions ending in .RELEASE) are deployed to Maven Central, so using the `mavenCentral()` repository is sufficient for GA releases. The following example shows how to do so: - - .build.gradle - ==== -@@ -314,7 +314,7 @@ repositories { - ---- - ==== - --If you use a SNAPSHOT version, you need to ensure you have the Spring Snapshot repository defined, as the following example shows: -+If you use a SNAPSHOT version, you need to ensure that you have the Spring Snapshot repository defined: - - .build.gradle - ==== -@@ -326,7 +326,7 @@ repositories { - ---- - ==== - --If you use a milestone or release candidate version, you need to ensure that you have the Spring Milestone repository defined, as the following example shows: -+If you use a milestone or release candidate version, you need to ensure that you have the Spring Milestone repository defined: - - .build.gradle - ==== -diff --git a/docs/manual/src/docs/asciidoc/_includes/about/modules.adoc b/docs/manual/src/docs/asciidoc/_includes/about/modules.adoc -index 3503fea601..fd0c274581 100644 ---- a/docs/manual/src/docs/asciidoc/_includes/about/modules.adoc -+++ b/docs/manual/src/docs/asciidoc/_includes/about/modules.adoc -@@ -8,13 +8,13 @@ Even if you do not use Maven, we recommend that you consult the `pom.xml` files - Another good idea is to examine the libraries that are included in the sample applications. - - This section provides a reference of the modules in Spring Security and the additional dependencies that they require in order to function in a running application. --We don't include dependencies that are only used when building or testing Spring Security itself. --Nor do we include transitive dependencies which are required by external dependencies. -+We do not include dependencies that are used only when building or testing Spring Security itself. -+Nor do we include transitive dependencies that are required by external dependencies. - --The version of Spring required is listed on the project website, so the specific versions are omitted for Spring dependencies below. --Note that some of the dependencies listed as "optional" below may still be required for other non-security functionality in a Spring application. --Also dependencies listed as "optional" may not actually be marked as such in the project's Maven POM files if they are used in most applications. --They are "optional" only in the sense that you don't need them unless you are using the specified functionality. -+The version of Spring required is listed on the project website, so the specific versions are omitted for Spring dependencies in the examples. -+Note that some of the dependencies listed as "`optional`" in the examples may still be required for other non-security functionality in a Spring application. -+Also dependencies listed as "`optional`" may not actually be marked as such in the project's Maven POM files if they are used in most applications. -+They are "`optional`" only in the sense that you do not need them unless you use the specified functionality. - - Where a module depends on another Spring Security module, the non-optional dependencies of the module it depends on are also assumed to be required and are not listed separately. - -@@ -85,7 +85,7 @@ The main package is `org.springframework.security.remoting`. - - | spring-web - | --| Required for clients which use HTTP remoting support. -+| Required for clients that use HTTP remoting support. - |=== - - [[spring-security-web]] -@@ -109,7 +109,7 @@ The main package is `org.springframework.security.web`. - - | spring-jdbc - | --| Required for JDBC-based persistent remember-me token repository (optional). -+| Required for a JDBC-based persistent remember-me token repository (optional). - - | spring-tx - | -@@ -170,10 +170,9 @@ The top-level package is `org.springframework.security.ldap`. - | - | Data exception classes are required. - --| apache-ds footnote:[The modules `apacheds-core`, `apacheds-core-entry`, `apacheds-protocol-shared`, `apacheds-protocol-ldap` and `apacheds-server-jndi` are required. --] -+| apache-ds - | 1.5.5 --| Required if you are using an embedded LDAP server (optional). -+| Required if you are using an embedded LDAP server (optional). If you use `apache-ds`, the `apacheds-core`, `apacheds-core-entry`, `apacheds-protocol-shared`, `apacheds-protocol-ldap` and `apacheds-server-jndi` modules are required. - - | shared-ldap - | 0.9.15 -@@ -188,7 +187,7 @@ Used for decoding LDAP password policy controls if you are using password-policy - [[spring-security-oauth2-core]] - == OAuth 2.0 Core -- `spring-security-oauth2-core.jar` - `spring-security-oauth2-core.jar` contains core classes and interfaces that provide support for the OAuth 2.0 Authorization Framework and for OpenID Connect Core 1.0. --It is required by applications that use OAuth 2.0 or OpenID Connect Core 1.0, such as client, resource server, and authorization server. -+It is required by applications that use OAuth 2.0 or OpenID Connect Core 1.0, such as the client, the resource server, and the authorization server. - The top-level package is `org.springframework.security.oauth2.core`. - - -@@ -218,7 +217,7 @@ It contains the following top-level packages: - [[spring-security-oauth2-resource-server]] - == OAuth 2.0 Resource Server -- `spring-security-oauth2-resource-server.jar` - `spring-security-oauth2-resource-server.jar` contains Spring Security's support for OAuth 2.0 Resource Servers. --It is used to protect APIs via OAuth 2.0 Bearer Tokens. -+It is used to protect APIs by using OAuth 2.0 Bearer Tokens. - The top-level package is `org.springframework.security.oauth2.server.resource`. - - [[spring-security-acl]] -@@ -237,7 +236,7 @@ The top-level package is `org.springframework.security.acls`. - - | ehcache - | 1.6.2 --| Required if the Ehcache-based ACL cache implementation is used (optional if you are using your own implementation). -+| Required if the Ehcache-based ACL cache implementation is used (optional if you use your own implementation). - - | spring-jdbc - | -@@ -278,8 +277,7 @@ This is the basis of the Spring Security integration. - - [[spring-security-openid]] - == OpenID -- `spring-security-openid.jar` --[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. -+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. - - This module contains OpenID web authentication support. - It is used to authenticate users against an external OpenID server. -diff --git a/docs/manual/src/docs/asciidoc/_includes/reactive/exploits/csrf.adoc b/docs/manual/src/docs/asciidoc/_includes/reactive/exploits/csrf.adoc -index c3a92fea4f..b0f8024220 100644 ---- a/docs/manual/src/docs/asciidoc/_includes/reactive/exploits/csrf.adoc -+++ b/docs/manual/src/docs/asciidoc/_includes/reactive/exploits/csrf.adoc -@@ -7,32 +7,32 @@ This section discusses Spring Security's <> --* <> --* <> -+* <> -+* <> -+* <> - - [[webflux-csrf-idempotent]] --=== Use proper HTTP verbs -+=== Use Proper HTTP Verbs - The first step to protecting against CSRF attacks is to ensure your website uses proper HTTP verbs. - This is covered in detail in <>. - - [[webflux-csrf-configure]] - === Configure CSRF Protection - The next step is to configure Spring Security's CSRF protection within your application. --Spring Security's CSRF protection is enabled by default, but you may need to customize the configuration. --Below are a few common customizations. -+By default, Spring Security's CSRF protection is enabled, but you may need to customize the configuration. -+The next few subsections cover a few common customizations. - - [[webflux-csrf-configure-custom-repository]] - ==== Custom CsrfTokenRepository - --By default Spring Security stores the expected CSRF token in the `WebSession` using `WebSessionServerCsrfTokenRepository`. --There can be cases where users will want to configure a custom `ServerCsrfTokenRepository`. --For example, it might be desirable to persist the `CsrfToken` in a cookie to <>. -+By default, Spring Security stores the expected CSRF token in the `WebSession` by using `WebSessionServerCsrfTokenRepository`. -+Sometimes, you may need to configure a custom `ServerCsrfTokenRepository`. -+For example, you may want to persist the `CsrfToken` in a cookie to <>. - --By default the `CookieServerCsrfTokenRepository` will write to a cookie named `XSRF-TOKEN` and read it from a header named `X-XSRF-TOKEN` or the HTTP parameter `_csrf`. -+By default, the `CookieServerCsrfTokenRepository` writes to a cookie named `XSRF-TOKEN` and read its from a header named `X-XSRF-TOKEN` or the HTTP `_csrf` parameter. - These defaults come from https://docs.angularjs.org/api/ng/service/$http#cross-site-request-forgery-xsrf-protection[AngularJS] - --You can configure `CookieServerCsrfTokenRepository` in Java Configuration using: -+You can configure `CookieServerCsrfTokenRepository` in Java Configuration: - - .Store CSRF Token in a Cookie - ==== -@@ -63,19 +63,16 @@ fun springSecurityFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain - ----- - ==== - --[NOTE] --==== --The sample explicitly sets `cookieHttpOnly=false`. --This is necessary to allow JavaScript (i.e. AngularJS) to read it. --If you do not need the ability to read the cookie with JavaScript directly, it is recommended to omit `cookieHttpOnly=false` (by using `new CookieServerCsrfTokenRepository()` instead) to improve security. --==== -+NOTE: The preceding sample explicitly sets `cookieHttpOnly=false`. -+This is necessary to let JavaScript (in this case, AngularJS) to read it. -+If you do not need the ability to read the cookie with JavaScript directly, we recommend to omitting `cookieHttpOnly=false` (by using `new CookieServerCsrfTokenRepository()` instead) to improve security. - - [[webflux-csrf-configure-disable]] - ==== Disable CSRF Protection --CSRF protection is enabled by default. --However, it is simple to disable CSRF protection if it <>. -+By default, CSRF protection is enabled. -+However, you can disable CSRF protection if it <>. - --The Java configuration below will disable CSRF protection. -+The following Java configuration disables CSRF protection: - - .Disable CSRF Configuration - ==== -@@ -109,15 +106,15 @@ fun springSecurityFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain - [[webflux-csrf-include]] - === Include the CSRF Token - --In order for the <> to protect against CSRF attacks, we must include the actual CSRF token in the HTTP request. --This must be included in a part of the request (i.e. form parameter, HTTP header, etc) that is not automatically included in the HTTP request by the browser. -+For the <> to protect against CSRF attacks, we must include the actual CSRF token in the HTTP request. -+It must be included in a part of the request (a form parameter, an HTTP header, or other option) that is not automatically included in the HTTP request by the browser. - --Spring Security's https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/web/server/csrf/CsrfWebFilter.html[CsrfWebFilter] exposes a https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/web/csrf/CsrfToken.html[Mono] as a `ServerWebExchange` attribute named `org.springframework.security.web.server.csrf.CsrfToken`. --This means that any view technology can access the `Mono` to expose the expected token as either a <> or <>. -+Spring Security's https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/web/server/csrf/CsrfWebFilter.html[`CsrfWebFilter`] exposes a https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/web/csrf/CsrfToken.html[`Mono`] as a `ServerWebExchange` attribute named `org.springframework.security.web.server.csrf.CsrfToken`. -+This means that any view technology can access the `Mono` to expose the expected token as either a <> or a <>. - - [[webflux-csrf-include-subscribe]] - If your view technology does not provide a simple way to subscribe to the `Mono`, a common pattern is to use Spring's `@ControllerAdvice` to expose the `CsrfToken` directly. --For example, the following code will place the `CsrfToken` on the default attribute name (`_csrf`) used by Spring Security's <> to automatically include the CSRF token as a hidden input. -+The following example places the `CsrfToken` on the default attribute name (`_csrf`) used by Spring Security's <> to automatically include the CSRF token as a hidden input: - - .`CsrfToken` as `@ModelAttribute` - ==== -@@ -155,8 +152,8 @@ Fortunately, Thymeleaf provides <> t - - [[webflux-csrf-include-form]] - ==== Form URL Encoded --In order to post an HTML form the CSRF token must be included in the form as a hidden input. --For example, the rendered HTML might look like: -+To post an HTML form, the CSRF token must be included in the form as a hidden input. -+The following example shows what the rendered HTML might look like: - - .CSRF Token HTML - ==== -@@ -168,22 +165,22 @@ For example, the rendered HTML might look like: - ---- - ==== - --Next we will discuss various ways of including the CSRF token in a form as a hidden input. -+Next, we discuss various ways of including the CSRF token in a form as a hidden input. - - [[webflux-csrf-include-form-auto]] - ===== Automatic CSRF Token Inclusion - --Spring Security's CSRF support provides integration with Spring's https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/reactive/result/view/RequestDataValueProcessor.html[RequestDataValueProcessor] via its https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/web/reactive/result/view/CsrfRequestDataValueProcessor.html[CsrfRequestDataValueProcessor]. --In order for `CsrfRequestDataValueProcessor` to work, the `Mono` must be subscribed to and the `CsrfToken` must be <> that matches https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/web/reactive/result/view/CsrfRequestDataValueProcessor.html#DEFAULT_CSRF_ATTR_NAME[DEFAULT_CSRF_ATTR_NAME]. -+Spring Security's CSRF support provides integration with Spring's https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/reactive/result/view/RequestDataValueProcessor.html[`RequestDataValueProcessor`] through its https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/web/reactive/result/view/CsrfRequestDataValueProcessor.html[`CsrfRequestDataValueProcessor`]. -+For `CsrfRequestDataValueProcessor` to work, the `Mono` must be subscribed to and the `CsrfToken` must be <> that matches https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/web/reactive/result/view/CsrfRequestDataValueProcessor.html#DEFAULT_CSRF_ATTR_NAME[`DEFAULT_CSRF_ATTR_NAME`]. - --Fortunately, Thymeleaf https://www.thymeleaf.org/doc/tutorials/2.1/thymeleafspring.html#integration-with-requestdatavalueprocessor[provides support] to take care of all the boilerplate for you by integrating with `RequestDataValueProcessor` to ensure that forms that have an unsafe HTTP method (i.e. post) will automatically include the actual CSRF token. -+Fortunately, Thymeleaf https://www.thymeleaf.org/doc/tutorials/2.1/thymeleafspring.html#integration-with-requestdatavalueprocessor[takes care of all the boilerplate] for you by integrating with `RequestDataValueProcessor` to ensure that forms that have an unsafe HTTP method (POST) automatically include the actual CSRF token. - - [[webflux-csrf-include-form-attr]] - ===== CsrfToken Request Attribute - - If the <> for including the actual CSRF token in the request do not work, you can take advantage of the fact that the `Mono` <> as a `ServerWebExchange` attribute named `org.springframework.security.web.server.csrf.CsrfToken`. - --The Thymeleaf sample below assumes that you <> the `CsrfToken` on an attribute named `_csrf`. -+The following Thymeleaf sample assumes that you <> the `CsrfToken` on an attribute named `_csrf`: - - .CSRF Token in Form with Request Attribute - ==== -@@ -202,19 +199,19 @@ The Thymeleaf sample below assumes that you <> to store the expected CSRF token in a cookie. --By storing the expected CSRF in a cookie, JavaScript frameworks like https://docs.angularjs.org/api/ng/service/$http#cross-site-request-forgery-xsrf-protection[AngularJS] will automatically include the actual CSRF token in the HTTP request headers. -+You can <> Spring Security to store the expected CSRF token in a cookie. -+By storing the expected CSRF in a cookie, JavaScript frameworks, such as https://docs.angularjs.org/api/ng/service/$http#cross-site-request-forgery-xsrf-protection[AngularJS], automatically include the actual CSRF token in the HTTP request headers. - - [[webflux-csrf-include-ajax-meta]] --===== Meta tags -+===== Meta Tags - - An alternative pattern to <> is to include the CSRF token within your `meta` tags. - The HTML might look something like this: -@@ -233,8 +230,8 @@ The HTML might look something like this: - ---- - ==== - --Once the meta tags contained the CSRF token, the JavaScript code would read the meta tags and include the CSRF token as a header. --If you were using jQuery, this could be done with the following: -+Once the meta tags contain the CSRF token, the JavaScript code can read the meta tags and include the CSRF token as a header. -+If you use jQuery, you could read the meta tags with the following code: - - .AJAX send CSRF Token - ==== -@@ -250,8 +247,8 @@ $(function () { - ---- - ==== - --The sample below assumes that you <> the `CsrfToken` on an attribute named `_csrf`. --An example of doing this with Thymeleaf is shown below: -+The following sample assumes that you <> the `CsrfToken` on an attribute named `_csrf`. -+The following example does this with Thymeleaf: - - .CSRF meta tag JSP - ==== -@@ -272,28 +269,28 @@ An example of doing this with Thymeleaf is shown below: - == CSRF Considerations - There are a few special considerations to consider when implementing protection against CSRF attacks. - This section discusses those considerations as it pertains to WebFlux environments. --Refer to <> for a more general discussion. -+See <> for a more general discussion. - - - [[webflux-considerations-csrf-login]] - === Logging In - --It is important to <> requests to protect against forging log in attempts. --Spring Security's WebFlux support does this out of the box. -+You should <> requests to protect against forged login attempts. -+Spring Security's WebFlux support automatically does this. - - [[webflux-considerations-csrf-logout]] - === Logging Out - --It is important to <> requests to protect against forging log out attempts. --By default Spring Security's `LogoutWebFilter` only processes HTTP post requests. --This ensures that log out requires a CSRF token and that a malicious user cannot forcibly log out your users. -+You should <> requests to protect against forging logout attempts. -+By default, Spring Security's `LogoutWebFilter` processes only HTTP post requests. -+This ensures that logout requires a CSRF token and that a malicious user cannot forcibly log out your users. - - The easiest approach is to use a form to log out. --If you really want a link, you can use JavaScript to have the link perform a POST (i.e. maybe on a hidden form). --For browsers with JavaScript that is disabled, you can optionally have the link take the user to a log out confirmation page that will perform the POST. -+If you really want a link, you can use JavaScript to have the link perform a POST (maybe on a hidden form). -+For browsers with JavaScript that is disabled, you can optionally have the link take the user to a logout confirmation page that performs the POST. - --If you really want to use HTTP GET with logout you can do so, but remember this is generally not recommended. --For example, the following Java Configuration will perform logout with the URL `/logout` is requested with any HTTP method: -+If you really want to use HTTP GET with logout, you can do so, but remember that doing so is generally not recommended. -+For example, the following Java Configuration logs out when the `/logout` URL is requested with any HTTP method: - - // FIXME: This should be a link to log out documentation - -@@ -330,16 +327,16 @@ fun springSecurityFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain - [[webflux-considerations-csrf-timeouts]] - === CSRF and Session Timeouts - --By default Spring Security stores the CSRF token in the `WebSession`. --This can lead to a situation where the session expires which means there is not an expected CSRF token to validate against. -+By default, Spring Security stores the CSRF token in the `WebSession`. -+This arrangement can lead to a situation where the session expires, which means that there is not an expected CSRF token to validate against. - --We've already discussed <> to session timeouts. -+We have already discussed <> to session timeouts. - This section discusses the specifics of CSRF timeouts as it pertains to the WebFlux support. - --It is simple to change storage of the expected CSRF token to be in a cookie. --For details, refer to the <> section. -+You can change storage of the expected CSRF token to be in a cookie. -+For details, see the <> section. - --// FIXME: We should add a custom AccessDeniedHandler section in the reference and update the links above -+// FIXME: We should add a custom AccessDeniedHandler section in the reference and update the earlier links - - // FIXME: We need a WebFlux multipart body vs action story. WebFlux always has multipart enabled. - [[webflux-csrf-considerations-multipart]] -@@ -347,17 +344,14 @@ For details, refer to the <> section. - We have <> how protecting multipart requests (file uploads) from CSRF attacks causes a https://en.wikipedia.org/wiki/Chicken_or_the_egg[chicken and the egg] problem. - This section discusses how to implement placing the CSRF token in the <> and <> within a WebFlux application. - --[NOTE] --==== --More information about using multipart forms with Spring can be found within the https://docs.spring.io/spring/docs/5.2.x/spring-framework-reference/web-reactive.html#webflux-multipart[Multipart Data] section of the Spring reference. --==== -+NOTE: For more information about using multipart forms with Spring, see the https://docs.spring.io/spring/docs/5.2.x/spring-framework-reference/web-reactive.html#webflux-multipart[Multipart Data] section of the Spring reference. - - [[webflux-csrf-considerations-multipart-body]] - ==== Place CSRF Token in the Body - - We have <> the trade-offs of placing the CSRF token in the body. - --In a WebFlux application, this can be configured with the following configuration: -+In a WebFlux application, you can do so with the following configuration: - - .Enable obtaining CSRF token from multipart/form-data - ==== -@@ -393,7 +387,7 @@ fun springSecurityFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain - - We have <> the trade-offs of placing the CSRF token in the URL. - Since the `CsrfToken` is exposed as an `ServerHttpRequest` <>, we can use that to create an `action` with the CSRF token in it. --An example with Thymeleaf is shown below: -+The following example uses Thymeleaf: - - .CSRF Token in Action - ==== -@@ -409,4 +403,5 @@ An example with Thymeleaf is shown below: - === HiddenHttpMethodFilter - We have <> overriding the HTTP method. - --In a Spring WebFlux application, overriding the HTTP method is done using https://docs.spring.io/spring-framework/docs/5.2.x/javadoc-api/org/springframework/web/filter/reactive/HiddenHttpMethodFilter.html[HiddenHttpMethodFilter]. -+In a Spring WebFlux application, overriding the HTTP method is done by using https://docs.spring.io/spring-framework/docs/5.2.x/javadoc-api/org/springframework/web/filter/reactive/HiddenHttpMethodFilter.html[`HiddenHttpMethodFilter`]. -+// FIXME: Add an example. -diff --git a/docs/manual/src/docs/asciidoc/_includes/reactive/exploits/headers.adoc b/docs/manual/src/docs/asciidoc/_includes/reactive/exploits/headers.adoc -index 2ee82ad2a6..64b86ebda1 100644 ---- a/docs/manual/src/docs/asciidoc/_includes/reactive/exploits/headers.adoc -+++ b/docs/manual/src/docs/asciidoc/_includes/reactive/exploits/headers.adoc -@@ -1,19 +1,19 @@ - [[webflux-headers]] - = Security HTTP Response Headers - --<> can be used to increase the security of web applications. --This section is dedicated to WebFlux based support for Security HTTP Response Headers. -+You can use <> to increase the security of web applications. -+This section is dedicated to WebFlux-based support for Security HTTP Response Headers. - - [[webflux-headers-default]] - == Default Security Headers - - Spring Security provides a <> to provide secure defaults. --While each of these headers are considered best practice, it should be noted that not all clients utilize the headers, so additional testing is encouraged. -+While each of these headers are considered best practice, it should be noted that not all clients use the headers, so additional testing is encouraged. - - You can customize specific headers. --For example, assume that you want the defaults except you wish to specify `SAMEORIGIN` for <>. -+For example, assume that you want the defaults but you wish to specify `SAMEORIGIN` for <>. - --You can easily do this with the following Configuration: -+You can do so with the following configuration: - - .Customize Default Security Headers - ==== -@@ -50,8 +50,7 @@ fun webFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain { - ---- - ==== - --If you do not want the defaults to be added and want explicit control over what should be used, you can disable the defaults. --An example is provided below: -+If you do not want the defaults to be added and want explicit control over what should be used, you can disable the defaults: - - .Disable HTTP Security Response Headers - ==== -@@ -85,13 +84,13 @@ fun webFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain { - [[webflux-headers-cache-control]] - == Cache Control - --Spring Security includes <> headers by default. -+Spring Security includes <> headers by default. - --However, if you actually want to cache specific responses, your application can selectively add them to the https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/http/server/reactive/ServerHttpResponse.html[ServerHttpResponse] to override the header set by Spring Security. --This is useful to ensure things like CSS, JavaScript, and images are properly cached. -+However, if you actually want to cache specific responses, your application can selectively add them to the https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/http/server/reactive/ServerHttpResponse.html[`ServerHttpResponse`] to override the header set by Spring Security. -+This is useful to ensure that such things as CSS, JavaScript, and images are properly cached. - --When using Spring WebFluxZz, this is typically done within your configuration. --Details on how to do this can be found in the https://docs.spring.io/spring/docs/5.0.0.RELEASE/spring-framework-reference/web-reactive.html#webflux-config-static-resources[Static Resources] portion of the Spring Reference documentation -+When using Spring WebFlux, you typically do so within your configuration. -+You can find details on how to do so in the https://docs.spring.io/spring/docs/5.0.0.RELEASE/spring-framework-reference/web-reactive.html#webflux-config-static-resources[Static Resources] portion of the Spring Reference documentation - - If necessary, you can also disable Spring Security's cache control HTTP response headers. - -@@ -131,8 +130,8 @@ fun webFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain { - - [[webflux-headers-content-type-options]] - == Content Type Options --Spring Security includes <> headers by default. --However, you can disable it with: -+By default, Spring Security includes <> headers. -+However, you can disable it: - - .Content Type Options Disabled - ==== -@@ -169,9 +168,9 @@ fun webFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain { - - [[webflux-headers-hsts]] - == HTTP Strict Transport Security (HSTS) --Spring Security provides the <> header by default. -+By default, Spring Security provides the <> header. - However, you can customize the results explicitly. --For example, the following is an example of explicitly providing HSTS: -+For example, the following example explicitly provides HSTS: - - .Strict Transport Security - ==== -@@ -214,9 +213,9 @@ fun webFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain { - - [[webflux-headers-frame-options]] - == X-Frame-Options --By default, Spring Security disables rendering within an iframe using <>. -+By default, Spring Security disables rendering within an iframe by using <>. - --You can customize frame options to use the same origin using the following: -+You can customize frame options to use the same origin: - - .X-Frame-Options: SAMEORIGIN - ==== -@@ -255,8 +254,8 @@ fun webFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain { - - [[webflux-headers-xss-protection]] - == X-XSS-Protection --By default, Spring Security instructs browsers to block reflected XSS attacks using the <. --You can disable `X-XSS-Protection` with the following Configuration: -+By default, Spring Security instructs browsers to block reflected XSS attacks by using the <. -+You can disable `X-XSS-Protection`: - - .X-XSS-Protection Customization - ==== -@@ -293,10 +292,10 @@ fun webFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain { - - [[webflux-headers-csp]] - == Content Security Policy (CSP) --Spring Security does not add <> by default, because a reasonable default is impossible to know without context of the application. --The web application author must declare the security policy(s) to enforce and/or monitor for the protected resources. -+By default, Spring Security does not add <>, because a reasonable default is impossible to know without the context of the application. -+The web application author must declare the security policies to enforce and monitor the protected resources. - --For example, given the following security policy: -+For example, consider the following security policy: - - .Content Security Policy Example - ==== -@@ -306,7 +305,7 @@ Content-Security-Policy: script-src 'self' https://trustedscripts.example.com; o - ---- - ==== - --You can enable the CSP header as shown below: -+Given the preceding policy, you can enable the CSP header: - - .Content Security Policy - ==== -@@ -385,8 +384,8 @@ fun webFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain { - [[webflux-headers-referrer]] - == Referrer Policy - --Spring Security does not add <> headers by default. --You can enable the Referrer Policy header using configuration as shown below: -+By default, Spring Security does not add <> headers. -+You can enable the Referrer Policy header: - - .Referrer Policy Configuration - ==== -@@ -427,8 +426,8 @@ fun webFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain { - [[webflux-headers-feature]] - == Feature Policy - --Spring Security does not add <> headers by default. --The following `Feature-Policy` header: -+By default, Spring Security does not add <> headers. -+Consider the following `Feature-Policy` header: - - .Feature-Policy Example - ==== -@@ -438,7 +437,7 @@ Feature-Policy: geolocation 'self' - ---- - ==== - --You can enable the Feature Policy header as shown below: -+You can enable the preceding Feature Policy header: - - .Feature-Policy Configuration - ==== -@@ -475,8 +474,8 @@ fun webFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain { - [[webflux-headers-permissions]] - == Permissions Policy - --Spring Security does not add <> headers by default. --The following `Permissions-Policy` header: -+By default, Spring Security does not add <> headers. -+Consider the following `Permissions-Policy` header: - - .Permissions-Policy Example - ==== -@@ -486,7 +485,7 @@ Permissions-Policy: geolocation=(self) - ---- - ==== - --You can enable the Permissions Policy header as shown below: -+You can enable the preceding Permissions Policy header: - - .Permissions-Policy Configuration - ==== -@@ -527,8 +526,8 @@ fun webFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain { - [[webflux-headers-clear-site-data]] - == Clear Site Data - --Spring Security does not add <> headers by default. --The following Clear-Site-Data header: -+By default, Spring Security does not add <> headers. -+Consider the following `Clear-Site-Data` header: - - .Clear-Site-Data Example - ==== -@@ -537,7 +536,7 @@ Clear-Site-Data: "cache", "cookies" - ---- - ==== - --can be sent on log out with the following configuration: -+You can send the `Clear-Site-Data` header on logout: - - .Clear-Site-Data Configuration - ==== -diff --git a/docs/manual/src/docs/asciidoc/_includes/reactive/exploits/http.adoc b/docs/manual/src/docs/asciidoc/_includes/reactive/exploits/http.adoc -index 387a05a719..3022716e87 100644 ---- a/docs/manual/src/docs/asciidoc/_includes/reactive/exploits/http.adoc -+++ b/docs/manual/src/docs/asciidoc/_includes/reactive/exploits/http.adoc -@@ -1,16 +1,16 @@ - [[webflux-http]] - = HTTP - --All HTTP based communication should be protected <>. -+All HTTP-based communication should be protected with <>. - --Below you can find details around WebFlux specific features that assist with HTTPS usage. -+This section covers details about using WebFlux-specific features that assist with HTTPS usage. - - [[webflux-http-redirect]] - == Redirect to HTTPS - --If a client makes a request using HTTP rather than HTTPS, Spring Security can be configured to redirect to HTTPS. -+If a client makes a request using HTTP rather than HTTPS, you can configure Spring Security to redirect to HTTPS. - --For example, the following Java configuration will redirect any HTTP requests to HTTPS: -+The following Java configuration redirects any HTTP requests to HTTPS: - - .Redirect to HTTPS - ==== -@@ -39,9 +39,9 @@ fun springSecurityFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain - ---- - ==== - --The configuration can easily be wrapped around an if statement to only be turned on in production. --Alternatively, it can be enabled by looking for a property about the request that only happens in production. --For example, if the production environment adds a header named `X-Forwarded-Proto` the following Java Configuration could be used: -+You can wrap the configuration can be wrapped around an `if` statement to be turned on only in production. -+Alternatively, you can enable it by looking for a property about the request that happens only in production. -+For example, if the production environment adds a header named `X-Forwarded-Proto`, you should use the following Java Configuration: - - .Redirect to HTTPS when X-Forwarded - ==== -diff --git a/docs/manual/src/docs/asciidoc/_includes/reactive/method.adoc b/docs/manual/src/docs/asciidoc/_includes/reactive/method.adoc -index 08e8ba2fa7..f2f60c3caa 100644 ---- a/docs/manual/src/docs/asciidoc/_includes/reactive/method.adoc -+++ b/docs/manual/src/docs/asciidoc/_includes/reactive/method.adoc -@@ -1,14 +1,13 @@ - [[jc-erms]] - = EnableReactiveMethodSecurity - --Spring Security supports method security using https://projectreactor.io/docs/core/release/reference/#context[Reactor's Context] which is setup using `ReactiveSecurityContextHolder`. --For example, this demonstrates how to retrieve the currently logged in user's message. -+Spring Security supports method security by using https://projectreactor.io/docs/core/release/reference/#context[Reactor's Context], which is set up by `ReactiveSecurityContextHolder`. -+The following example shows how to retrieve the currently logged in user's message: - - [NOTE] - ==== - For this to work the return type of the method must be a `org.reactivestreams.Publisher` (i.e. `Mono`/`Flux`) or the function must be a Kotlin coroutine function. - This is necessary to integrate with Reactor's `Context`. --==== - - ==== - .Java -@@ -27,6 +26,7 @@ StepVerifier.create(messageByUsername) - .expectNext("Hi user") - .verifyComplete(); - ---- -+==== - - .Kotlin - [source,kotlin,role="secondary"] -@@ -55,6 +55,7 @@ Mono findMessageByUsername(String username) { - return Mono.just("Hi " + username); - } - ---- -+==== - - .Kotlin - [source,kotlin,role="secondary"] -@@ -88,6 +89,7 @@ public class SecurityConfig { - } - } - ---- -+==== - - .Kotlin - [source,kotlin,role="secondary"] -@@ -125,6 +127,7 @@ public class HelloWorldMessageService { - } - } - ---- -+==== - - .Kotlin - [source,kotlin,role="secondary"] -@@ -162,7 +165,7 @@ It is important to note that any of the expressions in standard method security - However, at this time we only support return type of `Boolean` or `boolean` of the expression. - This means that the expression must not block. - --When integrating with <>, the Reactor Context is automatically established by Spring Security according to the authenticated user. -+When integrating with <>, the Reactor Context is automatically established by Spring Security according to the authenticated user: - - ==== - .Java -@@ -198,8 +201,8 @@ public class SecurityConfig { - return new MapReactiveUserDetailsService(rob, admin); - } - } -- - ---- -+==== - - .Kotlin - [source,kotlin,role="secondary"] -diff --git a/docs/manual/src/docs/asciidoc/_includes/reactive/oauth2/access-token.adoc b/docs/manual/src/docs/asciidoc/_includes/reactive/oauth2/access-token.adoc -index ac732704a2..9c1fc38adf 100644 ---- a/docs/manual/src/docs/asciidoc/_includes/reactive/oauth2/access-token.adoc -+++ b/docs/manual/src/docs/asciidoc/_includes/reactive/oauth2/access-token.adoc -@@ -2,8 +2,9 @@ - = OAuth2 Client - - Spring Security's OAuth Support allows obtaining an access token without authenticating. --A basic configuration with Spring Boot can be seen below: -+The following example shows basic configuration with Spring Boot: - -+==== - [source,yml] - ---- - spring: -@@ -16,10 +17,11 @@ spring: - client-secret: replace-with-client-secret - scope: read:user,public_repo - ---- -+==== - --You will need to replace the `client-id` and `client-secret` with values registered with GitHub. -+You need to replace the `client-id` and `client-secret` with values registered with GitHub. - --The next step is to instruct Spring Security that you wish to act as an OAuth2 Client so that you can obtain an access token. -+The next step is to instruct Spring Security that you wish to act as an OAuth2 Client so that you can obtain an access token: - - .OAuth2 Client - ==== -@@ -35,7 +37,6 @@ SecurityWebFilterChain configure(ServerHttpSecurity http) throws Exception { - } - ---- - -- - .Kotlin - [source,kotlin,role="secondary"] - ---- -@@ -49,4 +50,4 @@ fun webFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain { - ---- - ==== - --You can now leverage Spring Security's <> or <> support to obtain and use the access token. -+You can now use Spring Security's <> or <> support to obtain and use the access token. -diff --git a/docs/manual/src/docs/asciidoc/_includes/reactive/oauth2/login.adoc b/docs/manual/src/docs/asciidoc/_includes/reactive/oauth2/login.adoc -index 5883986d8a..71c262889d 100644 ---- a/docs/manual/src/docs/asciidoc/_includes/reactive/oauth2/login.adoc -+++ b/docs/manual/src/docs/asciidoc/_includes/reactive/oauth2/login.adoc -@@ -1,9 +1,9 @@ - [[webflux-oauth2-login]] - = OAuth 2.0 Login - --The OAuth 2.0 Login feature provides an application with the capability to have users log in to the application by using their existing account at an OAuth 2.0 Provider (e.g. -+The OAuth 2.0 Login feature provides an application with the ability to have users log in to the application by using their existing account at an OAuth 2.0 Provider (such as - GitHub) or OpenID Connect 1.0 Provider (such as Google). --OAuth 2.0 Login implements the use cases: "Login with Google" or "Login with GitHub". -+OAuth 2.0 Login implements the "Login with Google" or "Login with GitHub" use cases. - - NOTE: OAuth 2.0 Login is implemented by using the *Authorization Code Grant*, as specified in the https://tools.ietf.org/html/rfc6749#section-4.1[OAuth 2.0 Authorization Framework] and https://openid.net/specs/openid-connect-core-1_0.html#CodeFlowAuth[OpenID Connect Core 1.0]. - -@@ -12,38 +12,38 @@ NOTE: OAuth 2.0 Login is implemented by using the *Authorization Code Grant*, as - - Spring Boot 2.0 brings full auto-configuration capabilities for OAuth 2.0 Login. - --This section shows how to configure the {gh-samples-url}/boot/oauth2login-webflux[*OAuth 2.0 Login WebFlux sample*] using _Google_ as the _Authentication Provider_ and covers the following topics: -+This section shows how to configure the {gh-samples-url}/boot/oauth2login-webflux[*OAuth 2.0 Login WebFlux sample*] by using _Google_ as the _Authentication Provider_ and covers the following topics: - --* <> --* <> --* <> --* <> -+* <> -+* <> -+* <> -+* <> - - - [[webflux-oauth2-login-sample-setup]] --=== Initial setup -+=== Initial Setup - - To use Google's OAuth 2.0 authentication system for login, you must set up a project in the Google API Console to obtain OAuth 2.0 credentials. - - NOTE: https://developers.google.com/identity/protocols/OpenIDConnect[Google's OAuth 2.0 implementation] for authentication conforms to the https://openid.net/connect/[OpenID Connect 1.0] specification and is https://openid.net/certification/[OpenID Certified]. - --Follow the instructions on the https://developers.google.com/identity/protocols/OpenIDConnect[OpenID Connect] page, starting in the section, "Setting up OAuth 2.0". -+Follow the instructions on the https://developers.google.com/identity/protocols/OpenIDConnect[OpenID Connect] page, starting in the "`Setting up OAuth 2.0`" section. - --After completing the "Obtain OAuth 2.0 credentials" instructions, you should have a new OAuth Client with credentials consisting of a Client ID and a Client Secret. -+After completing the "`Obtain OAuth 2.0 credentials`" instructions, you should have a new OAuth Client with credentials that consist of a Client ID and a Client Secret. - - [[webflux-oauth2-login-sample-redirect]] --=== Setting the redirect URI -+=== Setting the Redirect URI - --The redirect URI is the path in the application that the end-user's user-agent is redirected back to after they have authenticated with Google and have granted access to the OAuth Client _(<>)_ on the Consent page. -+The redirect URI is the path in the application that the end-user's user-agent is redirected back to after they have authenticated with Google and have been granted access to the OAuth Client (<>) on the consent page. - --In the "Set a redirect URI" sub-section, ensure that the *Authorized redirect URIs* field is set to `http://localhost:8080/login/oauth2/code/google`. -+In the "`Set a redirect URI`" sub-section, ensure that the *Authorized redirect URIs* field is set to `http://localhost:8080/login/oauth2/code/google`. - - TIP: The default redirect URI template is `+{baseUrl}/login/oauth2/code/{registrationId}+`. - The *_registrationId_* is a unique identifier for the <>. - For our example, the `registrationId` is `google`. - --IMPORTANT: If the OAuth Client is running behind a proxy server, it is recommended to check <> to ensure the application is correctly configured. --Also, see the supported <> for `redirect-uri`. -+IMPORTANT: If the OAuth Client runs behind a proxy server, we recommend checking the <> to ensure the application is correctly configured. -+Also, see the supported <> for the `redirect-uri`. - - [[webflux-oauth2-login-sample-config]] - === Configure `application.yml` -@@ -53,6 +53,8 @@ To do so: - - . Go to `application.yml` and set the following configuration: - + -+.OAuth Client properties -+==== - [source,yaml] - ---- - spring: -@@ -65,8 +67,6 @@ spring: - client-secret: google-client-secret - ---- - + --.OAuth Client properties --==== - <1> `spring.security.oauth2.client.registration` is the base property prefix for OAuth Client properties. - <2> Following the base property prefix is the ID for the <>, such as google. - ==== -@@ -75,7 +75,7 @@ spring: - - - [[webflux-oauth2-login-sample-start]] --=== Boot up the application -+=== Boot the Application - - Launch the Spring Boot 2.0 sample and go to `http://localhost:8080`. - You are then redirected to the default _auto-generated_ login page, which displays a link for Google. -@@ -92,7 +92,7 @@ At this point, the OAuth Client retrieves your email address and basic profile i - == Using OpenID Provider Configuration - - For well known providers, Spring Security provides the necessary defaults for the OAuth Authorization Provider's configuration. --If you are working with your own Authorization Provider that supports https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfig[OpenID Provider Configuration] or https://tools.ietf.org/html/rfc8414#section-3[Authorization Server Metadata], the https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfigurationResponse[OpenID Provider Configuration Response]'s `issuer-uri` can be used to configure the application. -+If you are working with your own Authorization Provider that supports https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfig[OpenID Provider Configuration] or https://tools.ietf.org/html/rfc8414#section-3[Authorization Server Metadata], you can use the https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfigurationResponse[OpenID Provider Configuration Response]'s `issuer-uri` to configure the application. - - [source,yml] - ---- -@@ -109,10 +109,9 @@ spring: - client-secret: 6cea952f-10d0-4d00-ac79-cc865820dc2c - ---- - --The `issuer-uri` instructs Spring Security to query in series the endpoints `https://idp.example.com/auth/realms/demo/.well-known/openid-configuration`, `https://idp.example.com/.well-known/openid-configuration/auth/realms/demo`, or `https://idp.example.com/.well-known/oauth-authorization-server/auth/realms/demo` to discover the configuration. -+The `issuer-uri` instructs Spring Security to query, in series, the following endpoints to discover the configuration: `https://idp.example.com/auth/realms/demo/.well-known/openid-configuration`, `https://idp.example.com/.well-known/openid-configuration/auth/realms/demo`, or `https://idp.example.com/.well-known/oauth-authorization-server/auth/realms/demo`. - --[NOTE] --Spring Security will query the endpoints one at a time, stopping at the first that gives a 200 response. -+NOTE: Spring Security queries the endpoints one at a time, stopping at the first that gives a 200 response. - - The `client-id` and `client-secret` are linked to the provider because `keycloak` is used for both the provider and the registration. - -@@ -120,7 +119,7 @@ The `client-id` and `client-secret` are linked to the provider because `keycloak - [[webflux-oauth2-login-explicit]] - == Explicit OAuth2 Login Configuration - --A minimal OAuth2 Login configuration is shown below: -+The following listing shows a minimal OAuth2 Login configuration: - - .Minimal OAuth2 Login - ==== -@@ -168,7 +167,7 @@ fun webFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain { - ---- - ==== - --Additional configuration options can be seen below: -+The following example shows additional configuration options: - - .Advanced OAuth2 Login - ==== -@@ -206,7 +205,7 @@ fun webFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain { - ---- - ==== - --You may register a `GrantedAuthoritiesMapper` `@Bean` to have it automatically applied to the default configuration, as shown in the following example: -+You can register a `GrantedAuthoritiesMapper` `@Bean` to have it be automatically applied to the default configuration: - - .GrantedAuthoritiesMapper Bean - ==== -diff --git a/docs/manual/src/docs/asciidoc/_includes/reactive/oauth2/resource-server.adoc b/docs/manual/src/docs/asciidoc/_includes/reactive/oauth2/resource-server.adoc -index 1c5ff1821b..73a5ef683c 100644 ---- a/docs/manual/src/docs/asciidoc/_includes/reactive/oauth2/resource-server.adoc -+++ b/docs/manual/src/docs/asciidoc/_includes/reactive/oauth2/resource-server.adoc -@@ -1,35 +1,33 @@ - [[webflux-oauth2-resource-server]] - = OAuth 2.0 Resource Server - --Spring Security supports protecting endpoints using two forms of OAuth 2.0 https://tools.ietf.org/html/rfc6750.html[Bearer Tokens]: -+Spring Security supports protecting endpoints by offering two forms of OAuth 2.0 https://tools.ietf.org/html/rfc6750.html[Bearer Tokens]: - - * https://tools.ietf.org/html/rfc7519[JWT] - * Opaque Tokens - - This is handy in circumstances where an application has delegated its authority management to an https://tools.ietf.org/html/rfc6749[authorization server] (for example, Okta or Ping Identity). --This authorization server can be consulted by resource servers to authorize requests. -+Resource serves can consult this authorization server to authorize requests. - --[NOTE] --==== --A complete working example for {gh-samples-url}/boot/oauth2resourceserver-webflux[*JWTs*] is available in the {gh-samples-url}[Spring Security repository]. --==== -+NOTE: A complete working example for {gh-samples-url}/boot/oauth2resourceserver-webflux[JWT] is available in the {gh-samples-url}[Spring Security repository]. - - [[webflux-oauth2resourceserver-jwt-minimaldependencies]] - == Minimal Dependencies for JWT - - Most Resource Server support is collected into `spring-security-oauth2-resource-server`. --However, the support for decoding and verifying JWTs is in `spring-security-oauth2-jose`, meaning that both are necessary in order to have a working resource server that supports JWT-encoded Bearer Tokens. -+However, the support for decoding and verifying JWTs is in `spring-security-oauth2-jose`, meaning that both are necessary to have a working resource server that supports JWT-encoded Bearer Tokens. - - [[webflux-oauth2resourceserver-jwt-minimalconfiguration]] - == Minimal Configuration for JWTs - - When using https://spring.io/projects/spring-boot[Spring Boot], configuring an application as a resource server consists of two basic steps. --First, include the needed dependencies and second, indicate the location of the authorization server. -+First, include the needed dependencies. Second, indicate the location of the authorization server. - - === Specifying the Authorization Server - --In a Spring Boot application, to specify which authorization server to use, simply do: -+In a Spring Boot application, you need to specify which authorization server to use: - -+==== - [source,yml] - ---- - spring: -@@ -39,65 +37,63 @@ spring: - jwt: - issuer-uri: https://idp.example.com/issuer - ---- -+==== - --Where `https://idp.example.com/issuer` is the value contained in the `iss` claim for JWT tokens that the authorization server will issue. --Resource Server will use this property to further self-configure, discover the authorization server's public keys, and subsequently validate incoming JWTs. -+Where `https://idp.example.com/issuer` is the value contained in the `iss` claim for JWT tokens that the authorization server issues. -+This resource server uses this property to further self-configure, discover the authorization server's public keys, and subsequently validate incoming JWTs. - --[NOTE] --To use the `issuer-uri` property, it must also be true that one of `https://idp.example.com/issuer/.well-known/openid-configuration`, `https://idp.example.com/.well-known/openid-configuration/issuer`, or `https://idp.example.com/.well-known/oauth-authorization-server/issuer` is a supported endpoint for the authorization server. -+NOTE: To use the `issuer-uri` property, it must also be true that one of `https://idp.example.com/issuer/.well-known/openid-configuration`, `https://idp.example.com/.well-known/openid-configuration/issuer`, or `https://idp.example.com/.well-known/oauth-authorization-server/issuer` is a supported endpoint for the authorization server. - This endpoint is referred to as a https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfig[Provider Configuration] endpoint or a https://tools.ietf.org/html/rfc8414#section-3[Authorization Server Metadata] endpoint. - --And that's it! -- - === Startup Expectations - --When this property and these dependencies are used, Resource Server will automatically configure itself to validate JWT-encoded Bearer Tokens. -+When this property and these dependencies are used, Resource Server automatically configures itself to validate JWT-encoded Bearer Tokens. - - It achieves this through a deterministic startup process: - --1. Hit the Provider Configuration or Authorization Server Metadata endpoint, processing the response for the `jwks_url` property --2. Configure the validation strategy to query `jwks_url` for valid public keys --3. Configure the validation strategy to validate each JWTs `iss` claim against `https://idp.example.com`. -+. Hit the Provider Configuration or Authorization Server Metadata endpoint, processing the response for the `jwks_url` property. -+. Configure the validation strategy to query `jwks_url` for valid public keys. -+. Configure the validation strategy to validate each JWT's `iss` claim against `https://idp.example.com`. - --A consequence of this process is that the authorization server must be up and receiving requests in order for Resource Server to successfully start up. -+A consequence of this process is that the authorization server must be receiving requests in order for Resource Server to successfully start up. - --[NOTE] --If the authorization server is down when Resource Server queries it (given appropriate timeouts), then startup will fail. -+NOTE: If the authorization server is down when Resource Server queries it (given appropriate timeouts), then startup fails. - - === Runtime Expectations - --Once the application is started up, Resource Server will attempt to process any request containing an `Authorization: Bearer` header: -+Once the application is started up, Resource Server tries to process any request that contains an `Authorization: Bearer` header: - -+==== - [source,html] - ---- - GET / HTTP/1.1 - Authorization: Bearer some-token-value # Resource Server will process this - ---- -+==== - --So long as this scheme is indicated, Resource Server will attempt to process the request according to the Bearer Token specification. -+So long as this scheme is indicated, Resource Server tries to process the request according to the Bearer Token specification. - --Given a well-formed JWT, Resource Server will: -+Given a well-formed JWT, Resource Server: - --1. Validate its signature against a public key obtained from the `jwks_url` endpoint during startup and matched against the JWTs header --2. Validate the JWTs `exp` and `nbf` timestamps and the JWTs `iss` claim, and --3. Map each scope to an authority with the prefix `SCOPE_`. -+1. Validates its signature against a public key obtained from the `jwks_url` endpoint during startup and matched against the JWTs header. -+2. Validates the JWTs `exp` and `nbf` timestamps and the JWTs `iss` claim. -+3. Maps each scope to an authority with the prefix `SCOPE_`. - --[NOTE] --As the authorization server makes available new keys, Spring Security will automatically rotate the keys used to validate the JWT tokens. -+NOTE: As the authorization server makes available new keys, Spring Security automatically rotates the keys used to validate the JWT tokens. - --The resulting `Authentication#getPrincipal`, by default, is a Spring Security `Jwt` object, and `Authentication#getName` maps to the JWT's `sub` property, if one is present. -+By default, the resulting `Authentication#getPrincipal` is a Spring Security `Jwt` object, and `Authentication#getName` maps to the JWT's `sub` property, if one is present. - - From here, consider jumping to: - --<> -- --<> -+* <> -+* <> - - [[webflux-oauth2resourceserver-jwt-jwkseturi]] - === Specifying the Authorization Server JWK Set Uri Directly - --If the authorization server doesn't support any configuration endpoints, or if Resource Server must be able to start up independently from the authorization server, then the `jwk-set-uri` can be supplied as well: -+If the authorization server does not support any configuration endpoints, or if Resource Server must be able to start up independently from the authorization server, you can supply `jwk-set-uri` as well: - -+==== - [source,yaml] - ---- - spring: -@@ -108,22 +104,21 @@ spring: - issuer-uri: https://idp.example.com - jwk-set-uri: https://idp.example.com/.well-known/jwks.json - ---- -+==== - --[NOTE] --The JWK Set uri is not standardized, but can typically be found in the authorization server's documentation -+NOTE: The JWK Set uri is not standardized, but you can typically find it in the authorization server's documentation. - --Consequently, Resource Server will not ping the authorization server at startup. -+Consequently, Resource Server does not ping the authorization server at startup. - We still specify the `issuer-uri` so that Resource Server still validates the `iss` claim on incoming JWTs. - --[NOTE] --This property can also be supplied directly on the <>. -+NOTE: You can supply this property directly on the <>. - - [[webflux-oauth2resourceserver-jwt-sansboot]] - === Overriding or Replacing Boot Auto Configuration - --There are two `@Bean` s that Spring Boot generates on Resource Server's behalf. -+Spring Boot generates two `@Bean` objects on Resource Server's behalf. - --The first is a `SecurityWebFilterChain` that configures the app as a resource server. When including `spring-security-oauth2-jose`, this `SecurityWebFilterChain` looks like: -+The first bean is a `SecurityWebFilterChain` that configures the application as a resource server. When including `spring-security-oauth2-jose`, this `SecurityWebFilterChain` looks like: - - .Resource Server SecurityWebFilterChain - ==== -@@ -158,9 +153,9 @@ fun springSecurityFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain - ---- - ==== - --If the application doesn't expose a `SecurityWebFilterChain` bean, then Spring Boot will expose the above default one. -+If the application does not expose a `SecurityWebFilterChain` bean, Spring Boot exposes the default one (shown in the preceding listing). - --Replacing this is as simple as exposing the bean within the application: -+To replace it, expose the `@Bean` within the application: - - .Replacing SecurityWebFilterChain - ==== -@@ -199,9 +194,9 @@ fun springSecurityFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain - ---- - ==== - --The above requires the scope of `message:read` for any URL that starts with `/messages/`. -+The preceding configuration requires the scope of `message:read` for any URL that starts with `/messages/`. - --Methods on the `oauth2ResourceServer` DSL will also override or replace auto configuration. -+Methods on the `oauth2ResourceServer` DSL also override or replace auto configuration. - - For example, the second `@Bean` Spring Boot creates is a `ReactiveJwtDecoder`, which decodes `String` tokens into validated instances of `Jwt`: - -@@ -226,16 +221,15 @@ fun jwtDecoder(): ReactiveJwtDecoder { - ---- - ==== - --[NOTE] --Calling `{security-api-url}org/springframework/security/oauth2/jwt/ReactiveJwtDecoders.html#fromIssuerLocation-java.lang.String-[ReactiveJwtDecoders#fromIssuerLocation]` is what invokes the Provider Configuration or Authorization Server Metadata endpoint in order to derive the JWK Set Uri. --If the application doesn't expose a `ReactiveJwtDecoder` bean, then Spring Boot will expose the above default one. -+NOTE: Calling `{security-api-url}org/springframework/security/oauth2/jwt/ReactiveJwtDecoders.html#fromIssuerLocation-java.lang.String-[ReactiveJwtDecoders#fromIssuerLocation]` invokes the Provider Configuration or Authorization Server Metadata endpoint to derive the JWK Set URI. -+If the application does not expose a `ReactiveJwtDecoder` bean, Spring Boot exposes the above default one. - --And its configuration can be overridden using `jwkSetUri()` or replaced using `decoder()`. -+Its configuration can be overridden by using `jwkSetUri()` or replaced by using `decoder()`. - - [[webflux-oauth2resourceserver-jwt-jwkseturi-dsl]] - ==== Using `jwkSetUri()` - --An authorization server's JWK Set Uri can be configured <> or it can be supplied in the DSL: -+You can configure an authorization server's JWK Set URI <> or supply it in the DSL: - - ==== - .Java -@@ -280,7 +274,7 @@ Using `jwkSetUri()` takes precedence over any configuration property. - [[webflux-oauth2resourceserver-jwt-decoder-dsl]] - ==== Using `decoder()` - --More powerful than `jwkSetUri()` is `decoder()`, which will completely replace any Boot auto configuration of `JwtDecoder`: -+`decoder()` is more powerful than `jwkSetUri()`, because it completely replaces any Spring Boot auto-configuration of `JwtDecoder`: - - ==== - .Java -@@ -320,12 +314,12 @@ fun springSecurityFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain - ---- - ==== - --This is handy when deeper configuration, like <>, is necessary. -+This is handy when you need deeper configuration, such as <>. - - [[webflux-oauth2resourceserver-decoder-bean]] - ==== Exposing a `ReactiveJwtDecoder` `@Bean` - --Or, exposing a `ReactiveJwtDecoder` `@Bean` has the same effect as `decoder()`: -+Alternately, exposing a `ReactiveJwtDecoder` `@Bean` has the same effect as `decoder()`: - - ==== - .Java -@@ -350,15 +344,16 @@ fun jwtDecoder(): ReactiveJwtDecoder { - [[webflux-oauth2resourceserver-jwt-decoder-algorithm]] - == Configuring Trusted Algorithms - --By default, `NimbusReactiveJwtDecoder`, and hence Resource Server, will only trust and verify tokens using `RS256`. -+By default, `NimbusReactiveJwtDecoder`, and hence Resource Server, trust and verify only tokens that use `RS256`. - --You can customize this via <> or <>. -+You can customize this behavior with <> or by using <>. - - [[webflux-oauth2resourceserver-jwt-boot-algorithm]] --=== Via Spring Boot -+=== Customizing Trusted Algorithms with Spring Boot - - The simplest way to set the algorithm is as a property: - -+==== - [source,yaml] - ---- - spring: -@@ -369,9 +364,10 @@ spring: - jws-algorithm: RS512 - jwk-set-uri: https://idp.example.org/.well-known/jwks.json - ---- -+==== - - [[webflux-oauth2resourceserver-jwt-decoder-builder]] --=== Using a Builder -+=== Customizing Trusted Algorithms by Using a Builder - - For greater power, though, we can use a builder that ships with `NimbusReactiveJwtDecoder`: - -@@ -397,7 +393,7 @@ fun jwtDecoder(): ReactiveJwtDecoder { - ---- - ==== - --Calling `jwsAlgorithm` more than once will configure `NimbusReactiveJwtDecoder` to trust more than one algorithm, like so: -+Calling `jwsAlgorithm` more than once configures `NimbusReactiveJwtDecoder` to trust more than one algorithm: - - ==== - .Java -@@ -421,7 +417,7 @@ fun jwtDecoder(): ReactiveJwtDecoder { - ---- - ==== - --Or, you can call `jwsAlgorithms`: -+Alternately, you can call `jwsAlgorithms`: - - ==== - .Java -@@ -456,14 +452,14 @@ fun jwtDecoder(): ReactiveJwtDecoder { - === Trusting a Single Asymmetric Key - - Simpler than backing a Resource Server with a JWK Set endpoint is to hard-code an RSA public key. --The public key can be provided via <> or by <>. -+The public key can be provided with <> or by <>. - - [[webflux-oauth2resourceserver-jwt-decoder-public-key-boot]] - ==== Via Spring Boot - --Specifying a key via Spring Boot is quite simple. --The key's location can be specified like so: -+You can specify a key with Spring Boot: - -+==== - [source,yaml] - ---- - spring: -@@ -473,8 +469,9 @@ spring: - jwt: - public-key-location: classpath:my-key.pub - ---- -+==== - --Or, to allow for a more sophisticated lookup, you can post-process the `RsaKeyConversionServicePostProcessor`: -+Alternately, to allow for a more sophisticated lookup, you can post-process the `RsaKeyConversionServicePostProcessor`: - - .BeanFactoryPostProcessor - ==== -@@ -504,11 +501,14 @@ fun conversionServiceCustomizer(): BeanFactoryPostProcessor { - - Specify your key's location: - --```yaml -+==== -+[source,yaml] -+---- - key.location: hfds://my-key.pub --``` -+---- -+==== - --And then autowire the value: -+Then autowire the value: - - ==== - .Java -@@ -529,7 +529,7 @@ val key: RSAPublicKey? = null - [[webflux-oauth2resourceserver-jwt-decoder-public-key-builder]] - ==== Using a Builder - --To wire an `RSAPublicKey` directly, you can simply use the appropriate `NimbusReactiveJwtDecoder` builder, like so: -+To wire an `RSAPublicKey` directly, use the appropriate `NimbusReactiveJwtDecoder` builder: - - ==== - .Java -@@ -554,8 +554,8 @@ fun jwtDecoder(): ReactiveJwtDecoder { - [[webflux-oauth2resourceserver-jwt-decoder-secret-key]] - === Trusting a Single Symmetric Key - --Using a single symmetric key is also simple. --You can simply load in your `SecretKey` and use the appropriate `NimbusReactiveJwtDecoder` builder, like so: -+You can also use a single symmetric key. -+You can load in your `SecretKey` and use the appropriate `NimbusReactiveJwtDecoder` builder: - - ==== - .Java -@@ -580,13 +580,18 @@ fun jwtDecoder(): ReactiveJwtDecoder { - [[webflux-oauth2resourceserver-jwt-authorization]] - === Configuring Authorization - --A JWT that is issued from an OAuth 2.0 Authorization Server will typically either have a `scope` or `scp` attribute, indicating the scopes (or authorities) it's been granted, for example: -+A JWT that is issued from an OAuth 2.0 Authorization Server typically has either a `scope` or an `scp` attribute, indicating the scopes (or authorities) it has been granted -- for example: - --`{ ..., "scope" : "messages contacts"}` -+==== -+[source,json] -+---- -+{ ..., "scope" : "messages contacts"} -+---- -+==== - --When this is the case, Resource Server will attempt to coerce these scopes into a list of granted authorities, prefixing each scope with the string "SCOPE_". -+When this is the case, Resource Server tries to coerce these scopes into a list of granted authorities, prefixing each scope with the string, `SCOPE_`. - --This means that to protect an endpoint or method with a scope derived from a JWT, the corresponding expressions should include this prefix: -+This means that, to protect an endpoint or method with a scope derived from a JWT, the corresponding expressions should include this prefix: - - ==== - .Java -@@ -624,7 +629,7 @@ fun springSecurityFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain - ---- - ==== - --Or similarly with method security: -+You can do something similar with method security: - - ==== - .Java -@@ -646,8 +651,8 @@ fun getMessages(): Flux { } - ==== Extracting Authorities Manually - - However, there are a number of circumstances where this default is insufficient. --For example, some authorization servers don't use the `scope` attribute, but instead have their own custom attribute. --Or, at other times, the resource server may need to adapt the attribute or a composition of attributes into internalized authorities. -+For example, some authorization servers do not use the `scope` attribute. Instead, they have their own custom attribute. -+At other times, the resource server may need to adapt the attribute or a composition of attributes into internalized authorities. - - To this end, the DSL exposes `jwtAuthenticationConverter()`: - -@@ -703,10 +708,10 @@ fun grantedAuthoritiesExtractor(): Converter>, indicating the authorization server's issuer uri, Resource Server will default to verifying the `iss` claim as well as the `exp` and `nbf` timestamp claims. -+Using <>, indicating the authorization server's issuer URI, Resource Server defaults to verifying the `iss` claim as well as the `exp` and `nbf` timestamp claims. - --In circumstances where validation needs to be customized, Resource Server ships with two standard validators and also accepts custom `OAuth2TokenValidator` instances. -+In circumstances where you need to customize validation needs, Resource Server ships with two standard validators and also accepts custom `OAuth2TokenValidator` instances. - - [[webflux-oauth2resourceserver-jwt-validation-clockskew]] - ==== Customizing Timestamp Validation - --JWT's typically have a window of validity, with the start of the window indicated in the `nbf` claim and the end indicated in the `exp` claim. -+JWT instances typically have a window of validity, with the start of the window indicated in the `nbf` claim and the end indicated in the `exp` claim. - --However, every server can experience clock drift, which can cause tokens to appear expired to one server, but not to another. --This can cause some implementation heartburn as the number of collaborating servers increases in a distributed system. -+However, every server can experience clock drift, which can cause tokens to appear to be expired to one server but not to another. -+This can cause some implementation heartburn, as the number of collaborating servers increases in a distributed system. - --Resource Server uses `JwtTimestampValidator` to verify a token's validity window, and it can be configured with a `clockSkew` to alleviate the above problem: -+Resource Server uses `JwtTimestampValidator` to verify a token's validity window, and you can configure it with a `clockSkew` to alleviate the clock drift problem: - - ==== - .Java -@@ -817,13 +822,12 @@ fun jwtDecoder(): ReactiveJwtDecoder { - ---- - ==== - --[NOTE] --By default, Resource Server configures a clock skew of 30 seconds. -+NOTE: By default, Resource Server configures a clock skew of 30 seconds. - - [[webflux-oauth2resourceserver-validation-custom]] - ==== Configuring a Custom Validator - --Adding a check for the `aud` claim is simple with the `OAuth2TokenValidator` API: -+You can Add a check for the `aud` claim with the `OAuth2TokenValidator` API: - - ==== - .Java -@@ -858,7 +862,7 @@ class AudienceValidator : OAuth2TokenValidator { - ---- - ==== - --Then, to add into a resource server, it's a matter of specifying the `ReactiveJwtDecoder` instance: -+Then, to add into a resource server, you can specifying the `ReactiveJwtDecoder` instance: - - ==== - .Java -@@ -896,25 +900,28 @@ fun jwtDecoder(): ReactiveJwtDecoder { - - [[webflux-oauth2resourceserver-opaque-minimaldependencies]] - === Minimal Dependencies for Introspection --As described in <> most of Resource Server support is collected in `spring-security-oauth2-resource-server`. --However unless a custom <> is provided, the Resource Server will fallback to ReactiveOpaqueTokenIntrospector. --Meaning that both `spring-security-oauth2-resource-server` and `oauth2-oidc-sdk` are necessary in order to have a working minimal Resource Server that supports opaque Bearer Tokens. --Please refer to `spring-security-oauth2-resource-server` in order to determin the correct version for `oauth2-oidc-sdk`. -+As described in <>, most Resource Server support is collected in `spring-security-oauth2-resource-server`. -+However, unless you provide a custom <>, the Resource Server falls back to `ReactiveOpaqueTokenIntrospector`. -+This means that both `spring-security-oauth2-resource-server` and `oauth2-oidc-sdk` are necessary to have a working minimal Resource Server that supports opaque Bearer Tokens. -+See `spring-security-oauth2-resource-server` in order to determine the correct version for `oauth2-oidc-sdk`. - - [[webflux-oauth2resourceserver-opaque-minimalconfiguration]] - === Minimal Configuration for Introspection - --Typically, an opaque token can be verified via an https://tools.ietf.org/html/rfc7662[OAuth 2.0 Introspection Endpoint], hosted by the authorization server. -+Typically, you can verify an opaque token with an https://tools.ietf.org/html/rfc7662[OAuth 2.0 Introspection Endpoint], hosted by the authorization server. - This can be handy when revocation is a requirement. - --When using https://spring.io/projects/spring-boot[Spring Boot], configuring an application as a resource server that uses introspection consists of two basic steps. --First, include the needed dependencies and second, indicate the introspection endpoint details. -+When using https://spring.io/projects/spring-boot[Spring Boot], configuring an application as a resource server that uses introspection consists of two steps: -+ -+. Include the needed dependencies. -+. Indicate the introspection endpoint details. - - [[webflux-oauth2resourceserver-opaque-introspectionuri]] - ==== Specifying the Authorization Server - --To specify where the introspection endpoint is, simply do: -+You can specify where the introspection endpoint is: - -+==== - [source,yaml] - ---- - security: -@@ -925,54 +932,55 @@ security: - client-id: client - client-secret: secret - ---- -+==== - - Where `https://idp.example.com/introspect` is the introspection endpoint hosted by your authorization server and `client-id` and `client-secret` are the credentials needed to hit that endpoint. - --Resource Server will use these properties to further self-configure and subsequently validate incoming JWTs. -- --[NOTE] --When using introspection, the authorization server's word is the law. --If the authorization server responses that the token is valid, then it is. -+Resource Server uses these properties to further self-configure and subsequently validate incoming JWTs. - --And that's it! -+NOTE: When using introspection, the authorization server's word is the law. -+If the authorization server responses that the token is valid, it is. - - ==== Startup Expectations - --When this property and these dependencies are used, Resource Server will automatically configure itself to validate Opaque Bearer Tokens. -+When this property and these dependencies are used, Resource Server automatically configures itself to validate Opaque Bearer Tokens. - --This startup process is quite a bit simpler than for JWTs since no endpoints need to be discovered and no additional validation rules get added. -+This startup process is quite a bit simpler than for JWTs, since no endpoints need to be discovered and no additional validation rules get added. - - ==== Runtime Expectations - --Once the application is started up, Resource Server will attempt to process any request containing an `Authorization: Bearer` header: -+Once the application has started, Resource Server tries to process any request containing an `Authorization: Bearer` header: - --```http -+==== -+[source,http] -+---- - GET / HTTP/1.1 - Authorization: Bearer some-token-value # Resource Server will process this --``` -+---- -+==== - --So long as this scheme is indicated, Resource Server will attempt to process the request according to the Bearer Token specification. -+So long as this scheme is indicated, Resource Server tries to process the request according to the Bearer Token specification. - --Given an Opaque Token, Resource Server will -+Given an Opaque Token, Resource Server: - --1. Query the provided introspection endpoint using the provided credentials and the token --2. Inspect the response for an `{ 'active' : true }` attribute --3. Map each scope to an authority with the prefix `SCOPE_` -+. Queries the provided introspection endpoint by using the provided credentials and the token. -+. Inspects the response for an `{ 'active' : true }` attribute. -+. Maps each scope to an authority with a prefix of `SCOPE_`. - --The resulting `Authentication#getPrincipal`, by default, is a Spring Security `{security-api-url}org/springframework/security/oauth2/core/OAuth2AuthenticatedPrincipal.html[OAuth2AuthenticatedPrincipal]` object, and `Authentication#getName` maps to the token's `sub` property, if one is present. -+By default, the resulting `Authentication#getPrincipal` is a Spring Security `{security-api-url}org/springframework/security/oauth2/core/OAuth2AuthenticatedPrincipal.html[OAuth2AuthenticatedPrincipal]` object, and `Authentication#getName` maps to the token's `sub` property, if one is present. - - From here, you may want to jump to: - --* <> --* <> --* <> -+* <> -+* <> -+* <> - - [[webflux-oauth2resourceserver-opaque-attributes]] --=== Looking Up Attributes Post-Authentication -+=== Looking Up Attributes After Authentication - - Once a token is authenticated, an instance of `BearerTokenAuthentication` is set in the `SecurityContext`. - --This means that it's available in `@Controller` methods when using `@EnableWebFlux` in your configuration: -+This means that it is available in `@Controller` methods when you use `@EnableWebFlux` in your configuration: - - ==== - .Java -@@ -994,7 +1002,7 @@ fun foo(authentication: BearerTokenAuthentication): Mono { - ---- - ==== - --Since `BearerTokenAuthentication` holds an `OAuth2AuthenticatedPrincipal`, that also means that it's available to controller methods, too: -+Since `BearerTokenAuthentication` holds an `OAuth2AuthenticatedPrincipal`, it is also available to controller methods: - - ==== - .Java -@@ -1016,11 +1024,11 @@ fun foo(@AuthenticationPrincipal principal: OAuth2AuthenticatedPrincipal): Mono< - ---- - ==== - --==== Looking Up Attributes Via SpEL -+==== Looking Up Attributes with SpEL - --Of course, this also means that attributes can be accessed via SpEL. -+You can access attributes with the Spring Expression Language (SpEL). - --For example, if using `@EnableReactiveMethodSecurity` so that you can use `@PreAuthorize` annotations, you can do: -+For example, if you use `@EnableReactiveMethodSecurity` so that you can use `@PreAuthorize` annotations, you can do: - - ==== - .Java -@@ -1045,10 +1053,10 @@ fun forFoosEyesOnly(): Mono { - [[webflux-oauth2resourceserver-opaque-sansboot]] - === Overriding or Replacing Boot Auto Configuration - --There are two `@Bean` s that Spring Boot generates on Resource Server's behalf. -+Spring Boot generates two `@Bean` instances for Resource Server. - --The first is a `SecurityWebFilterChain` that configures the app as a resource server. --When use Opaque Token, this `SecurityWebFilterChain` looks like: -+The first is a `SecurityWebFilterChain` that configures the application as a resource server. -+When you use an Opaque Token, this `SecurityWebFilterChain` looks like: - - ==== - .Java -@@ -1082,9 +1090,9 @@ fun springSecurityFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain - ---- - ==== - --If the application doesn't expose a `SecurityWebFilterChain` bean, then Spring Boot will expose the above default one. -+If the application does not expose a `SecurityWebFilterChain` bean, Spring Boot exposes the default bean (shown in the preceding listing). - --Replacing this is as simple as exposing the bean within the application: -+You can replace it by exposing the bean within the application: - - .Replacing SecurityWebFilterChain - ==== -@@ -1130,9 +1138,9 @@ fun springSecurityFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain - ---- - ==== - --The above requires the scope of `message:read` for any URL that starts with `/messages/`. -+The preceding example requires the scope of `message:read` for any URL that starts with `/messages/`. - --Methods on the `oauth2ResourceServer` DSL will also override or replace auto configuration. -+Methods on the `oauth2ResourceServer` DSL also override or replace auto configuration. - - For example, the second `@Bean` Spring Boot creates is a `ReactiveOpaqueTokenIntrospector`, which decodes `String` tokens into validated instances of `OAuth2AuthenticatedPrincipal`: - -@@ -1156,14 +1164,14 @@ fun introspector(): ReactiveOpaqueTokenIntrospector { - ---- - ==== - --If the application doesn't expose a `ReactiveOpaqueTokenIntrospector` bean, then Spring Boot will expose the above default one. -+If the application does not expose a `ReactiveOpaqueTokenIntrospector` bean, Spring Boot exposes the default one (shown in the preceding listing). - --And its configuration can be overridden using `introspectionUri()` and `introspectionClientCredentials()` or replaced using `introspector()`. -+You can override its configuration by using `introspectionUri()` and `introspectionClientCredentials()` or replace it by using `introspector()`. - - [[webflux-oauth2resourceserver-opaque-introspectionuri-dsl]] - ==== Using `introspectionUri()` - --An authorization server's Introspection Uri can be configured <> or it can be supplied in the DSL: -+You can configure an authorization server's Introspection URI <>, or you can supply in the DSL: - - ==== - .Java -@@ -1213,7 +1221,7 @@ Using `introspectionUri()` takes precedence over any configuration property. - [[webflux-oauth2resourceserver-opaque-introspector-dsl]] - ==== Using `introspector()` - --More powerful than `introspectionUri()` is `introspector()`, which will completely replace any Boot auto configuration of `ReactiveOpaqueTokenIntrospector`: -+`introspector()` is more powerful than `introspectionUri()`. It completely replaces any Boot auto-configuration of `ReactiveOpaqueTokenIntrospector`: - - ==== - .Java -@@ -1256,7 +1264,7 @@ fun springSecurityFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain - ---- - ==== - --This is handy when deeper configuration, like <>or <> is necessary. -+This is handy when deeper configuration, such as <>or <>, is necessary. - - [[webflux-oauth2resourceserver-opaque-introspector-bean]] - ==== Exposing a `ReactiveOpaqueTokenIntrospector` `@Bean` -@@ -1286,13 +1294,18 @@ fun introspector(): ReactiveOpaqueTokenIntrospector { - [[webflux-oauth2resourceserver-opaque-authorization]] - === Configuring Authorization - --An OAuth 2.0 Introspection endpoint will typically return a `scope` attribute, indicating the scopes (or authorities) it's been granted, for example: -+An OAuth 2.0 Introspection endpoint typically returns a `scope` attribute, indicating the scopes (or authorities) it has been granted -- for example: - --`{ ..., "scope" : "messages contacts"}` -+==== -+[source,json] -+---- -+{ ..., "scope" : "messages contacts"} -+---- -+==== - --When this is the case, Resource Server will attempt to coerce these scopes into a list of granted authorities, prefixing each scope with the string "SCOPE_". -+When this is the case, Resource Server tries to coerce these scopes into a list of granted authorities, prefixing each scope with a string: `SCOPE_`. - --This means that to protect an endpoint or method with a scope derived from an Opaque Token, the corresponding expressions should include this prefix: -+This means that, to protect an endpoint or method with a scope derived from an Opaque Token, the corresponding expressions should include this prefix: - - ==== - .Java -@@ -1333,7 +1346,7 @@ fun springSecurityFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain - ---- - ==== - --Or similarly with method security: -+You can do something similar with method security: - - ==== - .Java -@@ -1354,9 +1367,9 @@ fun getMessages(): Flux { } - [[webflux-oauth2resourceserver-opaque-authorization-extraction]] - ==== Extracting Authorities Manually - --By default, Opaque Token support will extract the scope claim from an introspection response and parse it into individual `GrantedAuthority` instances. -+By default, Opaque Token support extracts the scope claim from an introspection response and parses it into individual `GrantedAuthority` instances. - --For example, if the introspection response were: -+Consider the following example: - - [source,json] - ---- -@@ -1366,9 +1379,9 @@ For example, if the introspection response were: - } - ---- - --Then Resource Server would generate an `Authentication` with two authorities, one for `message:read` and the other for `message:write`. -+If the introspection response were as the preceding example shows, Resource Server would generate an `Authentication` with two authorities, one for `message:read` and the other for `message:write`. - --This can, of course, be customized using a custom `ReactiveOpaqueTokenIntrospector` that takes a look at the attribute set and converts in its own way: -+You can customize behavior by using a custom `ReactiveOpaqueTokenIntrospector` that looks at the attribute set and converts in its own way: - - ==== - .Java -@@ -1415,7 +1428,7 @@ class CustomAuthoritiesOpaqueTokenIntrospector : ReactiveOpaqueTokenIntrospector - ---- - ==== - --Thereafter, this custom introspector can be configured simply by exposing it as a `@Bean`: -+Thereafter, you can configure this custom introspector by exposing it as a `@Bean`: - - ==== - .Java -@@ -1441,12 +1454,13 @@ fun introspector(): ReactiveOpaqueTokenIntrospector { - === Using Introspection with JWTs - - A common question is whether or not introspection is compatible with JWTs. --Spring Security's Opaque Token support has been designed to not care about the format of the token -- it will gladly pass any token to the introspection endpoint provided. -+Spring Security's Opaque Token support has been designed to not care about the format of the token. It gladly passes any token to the provided introspection endpoint. - --So, let's say that you've got a requirement that requires you to check with the authorization server on each request, in case the JWT has been revoked. -+So, suppose you need to check with the authorization server on each request, in case the JWT has been revoked. - --Even though you are using the JWT format for the token, your validation method is introspection, meaning you'd want to do: -+Even though you are using the JWT format for the token, your validation method is introspection, meaning you would want to do: - -+==== - [source,yaml] - ---- - spring: -@@ -1458,14 +1472,15 @@ spring: - client-id: client - client-secret: secret - ---- -+==== - - In this case, the resulting `Authentication` would be `BearerTokenAuthentication`. - Any attributes in the corresponding `OAuth2AuthenticatedPrincipal` would be whatever was returned by the introspection endpoint. - --But, let's say that, oddly enough, the introspection endpoint only returns whether or not the token is active. -+However, suppose that, for whatever reason, the introspection endpoint returns only whether or not the token is active. - Now what? - --In this case, you can create a custom `ReactiveOpaqueTokenIntrospector` that still hits the endpoint, but then updates the returned principal to have the JWTs claims as the attributes: -+In this case, you can create a custom `ReactiveOpaqueTokenIntrospector` that still hits the endpoint but then updates the returned principal to have the JWTs claims as the attributes: - - ==== - .Java -@@ -1519,7 +1534,7 @@ class JwtOpaqueTokenIntrospector : ReactiveOpaqueTokenIntrospector { - ---- - ==== - --Thereafter, this custom introspector can be configured simply by exposing it as a `@Bean`: -+Thereafter, you can configure this custom introspector by exposing it as a `@Bean`: - - ==== - .Java -@@ -1544,16 +1559,16 @@ fun introspector(): ReactiveOpaqueTokenIntrospector { - [[webflux-oauth2resourceserver-opaque-userinfo]] - === Calling a `/userinfo` Endpoint - --Generally speaking, a Resource Server doesn't care about the underlying user, but instead about the authorities that have been granted. -+Generally speaking, a Resource Server does not care about the underlying user but, instead, cares about the authorities that have been granted. - - That said, at times it can be valuable to tie the authorization statement back to a user. - --If an application is also using `spring-security-oauth2-client`, having set up the appropriate `ClientRegistrationRepository`, then this is quite simple with a custom `OpaqueTokenIntrospector`. --This implementation below does three things: -+If an application also uses `spring-security-oauth2-client`, having set up the appropriate `ClientRegistrationRepository`, you can do so with a custom `OpaqueTokenIntrospector`. -+The implementation in the next listing does three things: - --* Delegates to the introspection endpoint, to affirm the token's validity --* Looks up the appropriate client registration associated with the `/userinfo` endpoint --* Invokes and returns the response from the `/userinfo` endpoint -+* Delegates to the introspection endpoint, to affirm the token's validity. -+* Looks up the appropriate client registration associated with the `/userinfo` endpoint. -+* Invokes and returns the response from the `/userinfo` endpoint. - - ==== - .Java -@@ -1610,8 +1625,8 @@ class UserInfoOpaqueTokenIntrospector : ReactiveOpaqueTokenIntrospector { - ---- - ==== - --If you aren't using `spring-security-oauth2-client`, it's still quite simple. --You will simply need to invoke the `/userinfo` with your own instance of `WebClient`: -+If you do not use `spring-security-oauth2-client`, you can do so -+by invoking the `/userinfo` with your own instance of `WebClient`: - - ==== - .Java -@@ -1672,17 +1687,17 @@ fun introspector(): ReactiveOpaqueTokenIntrospector { - - A resource server is considered multi-tenant when there are multiple strategies for verifying a bearer token, keyed by some tenant identifier. - --For example, your resource server may accept bearer tokens from two different authorization servers. --Or, your authorization server may represent a multiplicity of issuers. -+For example, your resource server can accept bearer tokens from two different authorization servers. -+Alternately, your authorization server can represent a multiplicity of issuers. - --In each case, there are two things that need to be done and trade-offs associated with how you choose to do them: -+In each case, two things need to be done and trade-offs are associated with how you choose to do them: - --1. Resolve the tenant --2. Propagate the tenant -+1. Resolve the tenant. -+2. Propagate the tenant. - - === Resolving the Tenant By Claim - --One way to differentiate tenants is by the issuer claim. Since the issuer claim accompanies signed JWTs, this can be done with the `JwtIssuerReactiveAuthenticationManagerResolver`, like so: -+One way to differentiate tenants is by the issuer claim. Since the issuer claim accompanies signed JWTs, you can do so with the `JwtIssuerReactiveAuthenticationManagerResolver`: - - ==== - .Java -@@ -1722,8 +1737,8 @@ This allows for an application startup that is independent from those authorizat - - ==== Dynamic Tenants - --Of course, you may not want to restart the application each time a new tenant is added. --In this case, you can configure the `JwtIssuerReactiveAuthenticationManagerResolver` with a repository of `ReactiveAuthenticationManager` instances, which you can edit at runtime, like so: -+You may not want to restart the application each time a new tenant is added. -+In this case, you can configure the `JwtIssuerReactiveAuthenticationManagerResolver` with a repository of `ReactiveAuthenticationManager` instances, which you can edit at runtime: - - ==== - .Java -@@ -1777,20 +1792,20 @@ return http { - ---- - ==== - --In this case, you construct `JwtIssuerReactiveAuthenticationManagerResolver` with a strategy for obtaining the `ReactiveAuthenticationManager` given the issuer. --This approach allows us to add and remove elements from the repository (shown as a `Map` in the snippet) at runtime. -+In this case, you construct `JwtIssuerReactiveAuthenticationManagerResolver` with a strategy for obtaining the `ReactiveAuthenticationManager` given to the issuer. -+This approach lets us add and remove elements from the repository (shown as a `Map` in the preceding snippet) at runtime. - - NOTE: It would be unsafe to simply take any issuer and construct an `ReactiveAuthenticationManager` from it. --The issuer should be one that the code can verify from a trusted source like an allowed list of issuers. -+The issuer should be one that the code can verify from a trusted source, such as an allowed list of issuers. - - [[webflux-oauth2resourceserver-bearertoken-resolver]] - == Bearer Token Resolution - - By default, Resource Server looks for a bearer token in the `Authorization` header. --This, however, can be customized. -+However, you can verify this token. - - For example, you may have a need to read the bearer token from a custom header. --To achieve this, you can wire an instance of `ServerBearerTokenAuthenticationConverter` into the DSL, as you can see in the following example: -+To do so, you can wire an instance of `ServerBearerTokenAuthenticationConverter` into the DSL: - - .Custom Bearer Token Header - ==== -@@ -1820,8 +1835,8 @@ return http { - - == Bearer Token Propagation - --Now that you're in possession of a bearer token, it might be handy to pass that to downstream services. --This is quite simple with `{security-api-url}org/springframework/security/oauth2/server/resource/web/reactive/function/client/ServerBearerExchangeFilterFunction.html[ServerBearerExchangeFilterFunction]`, which you can see in the following example: -+Now that you have a bearer token, you can pass that to downstream services. -+This is possible with `{security-api-url}org/springframework/security/oauth2/server/resource/web/reactive/function/client/ServerBearerExchangeFilterFunction.html[ServerBearerExchangeFilterFunction]`: - - ==== - .Java -@@ -1847,10 +1862,8 @@ fun rest(): WebClient { - ---- - ==== - --When the above `WebClient` is used to perform requests, Spring Security will look up the current `Authentication` and extract any `{security-api-url}org/springframework/security/oauth2/core/AbstractOAuth2Token.html[AbstractOAuth2Token]` credential. --Then, it will propagate that token in the `Authorization` header. -- --For example: -+When the `WebClient` shown in the preceding example performs requests, Spring Security looks up the current `Authentication` and extract any `{security-api-url}org/springframework/security/oauth2/core/AbstractOAuth2Token.html[AbstractOAuth2Token]` credential. -+Then, it propagates that token in the `Authorization` header -- for example: - - ==== - .Java -@@ -1872,9 +1885,9 @@ this.rest.get() - ---- - ==== - --Will invoke the `https://other-service.example.com/endpoint`, adding the bearer token `Authorization` header for you. -+The prececing example invokes the `https://other-service.example.com/endpoint`, adding the bearer token `Authorization` header for you. - --In places where you need to override this behavior, it's a simple matter of supplying the header yourself, like so: -+In places where you need to override this behavior, you can supply the header yourself: - - ==== - .Java -@@ -1898,8 +1911,7 @@ rest.get() - ---- - ==== - --In this case, the filter will fall back and simply forward the request onto the rest of the web filter chain. -+In this case, the filter falls back and forwards the request onto the rest of the web filter chain. - --[NOTE] --Unlike the https://docs.spring.io/spring-security/site/docs/current-SNAPSHOT/api/org/springframework/security/oauth2/client/web/reactive/function/client/ServerOAuth2AuthorizedClientExchangeFilterFunction.html[OAuth 2.0 Client filter function], this filter function makes no attempt to renew the token, should it be expired. --To obtain this level of support, please use the OAuth 2.0 Client filter. -+NOTE: Unlike the https://docs.spring.io/spring-security/site/docs/current-SNAPSHOT/api/org/springframework/security/oauth2/client/web/reactive/function/client/ServerOAuth2AuthorizedClientExchangeFilterFunction.html[OAuth 2.0 Client filter function], this filter function makes no attempt to renew the token, should it be expired. -+To obtain this level of support, use the OAuth 2.0 Client filter. -diff --git a/docs/manual/src/docs/asciidoc/_includes/reactive/registered-oauth2-authorized-client.adoc b/docs/manual/src/docs/asciidoc/_includes/reactive/registered-oauth2-authorized-client.adoc -index cd1e4c06cd..ce98690560 100644 ---- a/docs/manual/src/docs/asciidoc/_includes/reactive/registered-oauth2-authorized-client.adoc -+++ b/docs/manual/src/docs/asciidoc/_includes/reactive/registered-oauth2-authorized-client.adoc -@@ -1,14 +1,11 @@ - [[webflux-roac]] - = @RegisteredOAuth2AuthorizedClient - --Spring Security allows resolving an access token using `@RegisteredOAuth2AuthorizedClient`. -+Spring Security allows resolving an access token by using `@RegisteredOAuth2AuthorizedClient`. - --[NOTE] --==== --A working example can be found in {gh-samples-url}/boot/oauth2webclient-webflux[*OAuth 2.0 WebClient WebFlux sample*]. --==== -+NOTE: You can find a working example in the {gh-samples-url}/boot/oauth2webclient-webflux[OAuth 2.0 WebClient WebFlux sample]. - --After configuring Spring Security for <> or as an <>, an `OAuth2AuthorizedClient` can be resolved using the following: -+After configuring Spring Security for <> or as an <>, you can resolve an `OAuth2AuthorizedClient` by using the following: - - ==== - .Java -@@ -30,14 +27,14 @@ fun explicit(@RegisteredOAuth2AuthorizedClient("client-id") authorizedClient: OA - ---- - ==== - --This integrates into Spring Security to provide the following features: -+This code integrates into Spring Security to provide the following features: - --* Spring Security will automatically refresh expired tokens (if a refresh token is present) --* If an access token is requested and not present, Spring Security will automatically request the access token. --** For `authorization_code` this involves performing the redirect and then replaying the original request --** For `client_credentials` the token is simply requested and saved -+* Spring Security automatically refreshes expired tokens (if a refresh token is present). -+* If an access token is requested and not present, Spring Security automatically requests the access token. -+** For `authorization_code`, this involves performing the redirect and then replaying the original request. -+** For `client_credentials`, the token is simply requested and saved. - --If the user authenticated using `oauth2Login()`, then the `client-id` is optional. -+If the user authenticated by using `oauth2Login()`, the `client-id` is optional. - For example, the following would work: - - ==== -@@ -60,4 +57,4 @@ fun implicit(@RegisteredOAuth2AuthorizedClient authorizedClient: OAuth2Authorize - ---- - ==== - --This is convenient if the user always authenticates with OAuth2 Login and an access token from the same authorization server is needed. -+This approach is convenient if the user always authenticates with OAuth2 Login and an access token from the same authorization server is needed. -diff --git a/docs/manual/src/docs/asciidoc/_includes/reactive/rsocket.adoc b/docs/manual/src/docs/asciidoc/_includes/reactive/rsocket.adoc -index 7cecae769b..822b0cd1a9 100644 ---- a/docs/manual/src/docs/asciidoc/_includes/reactive/rsocket.adoc -+++ b/docs/manual/src/docs/asciidoc/_includes/reactive/rsocket.adoc -@@ -2,9 +2,9 @@ - = RSocket Security - - Spring Security's RSocket support relies on a `SocketAcceptorInterceptor`. --The main entry point into security is found in the `PayloadSocketAcceptorInterceptor` which adapts the RSocket APIs to allow intercepting a `PayloadExchange` with `PayloadInterceptor` implementations. -+The main entry point into security is in `PayloadSocketAcceptorInterceptor`, which adapts the RSocket APIs to allow intercepting a `PayloadExchange` with `PayloadInterceptor` implementations. - --You can find a few sample applications that demonstrate the code below: -+You can find two sample applications that demonstrate the code: - - * Hello RSocket {gh-samples-url}/boot/hellorsocket[hellorsocket] - * https://github.com/rwinch/spring-flights/tree/security[Spring Flights] -@@ -12,8 +12,9 @@ You can find a few sample applications that demonstrate the code below: - - == Minimal RSocket Security Configuration - --You can find a minimal RSocket Security configuration below: -+The following example shows a minimal RSocket Security configuration: - -+==== - [source,java] - ----- - @Configuration -@@ -31,15 +32,17 @@ public class HelloRSocketSecurityConfig { - } - } - ----- -+==== - - This configuration enables <> and sets up <> to require an authenticated user for any request. - - == Adding SecuritySocketAcceptorInterceptor - --For Spring Security to work we need to apply `SecuritySocketAcceptorInterceptor` to the `ServerRSocketFactory`. --This is what connects our `PayloadSocketAcceptorInterceptor` we created with the RSocket infrastructure. --In a Spring Boot application this is done automatically using `RSocketSecurityAutoConfiguration` with the following code. -+For Spring Security to work, we need to apply `SecuritySocketAcceptorInterceptor` to the `ServerRSocketFactory`. -+Doing so connects our `PayloadSocketAcceptorInterceptor` with the RSocket infrastructure. -+In a Spring Boot application, you can do this automatically by using `RSocketSecurityAutoConfiguration` with the following code: - -+==== - [source,java] - ---- - @Bean -@@ -48,45 +51,44 @@ ServerRSocketFactoryProcessor springSecurityRSocketSecurity( - return builder -> builder.addSocketAcceptorPlugin(interceptor); - } - ---- -+==== - - [[rsocket-authentication]] - == RSocket Authentication - --RSocket authentication is performed with `AuthenticationPayloadInterceptor` which acts as a controller to invoke a `ReactiveAuthenticationManager` instance. -+RSocket authentication is performed with `AuthenticationPayloadInterceptor`, which acts as a controller to invoke a `ReactiveAuthenticationManager` instance. - - [[rsocket-authentication-setup-vs-request]] --=== Authentication at Setup vs Request Time -+=== Authentication at Setup versus Request Time - --Generally, authentication can occur at setup time and/or request time. -+Generally, authentication can occur at setup time or at request time or both. - - Authentication at setup time makes sense in a few scenarios. --A common scenarios is when a single user (i.e. mobile connection) is leveraging an RSocket connection. --In this case only a single user is leveraging the connection, so authentication can be done once at connection time. -+A common scenarios is when a single user (such as a mobile connection) uses an RSocket connection. -+In this case, only a single user uses the connection, so authentication can be done once at connection time. - --In a scenario where the RSocket connection is shared it makes sense to send credentials on each request. --For example, a web application that connects to an RSocket server as a downstream service would make a single connection that all users leverage. --In this case, if the RSocket server needs to perform authorization based on the web application's users credentials per request makes sense. -+In a scenario where the RSocket connection is shared, it makes sense to send credentials on each request. -+For example, a web application that connects to an RSocket server as a downstream service would make a single connection that all users use. -+In this case, if the RSocket server needs to perform authorization based on the web application's users credentials, authentication for each request makes sense. - --In some scenarios authentication at setup and per request makes sense. --Consider a web application as described previously. -+In some scenarios, authentication at both setup and for each request makes sense. -+Consider a web application, as described previously. - If we need to restrict the connection to the web application itself, we can provide a credential with a `SETUP` authority at connection time. --Then each user would have different authorities but not the `SETUP` authority. -+Then each user can have different authorities but not the `SETUP` authority. - This means that individual users can make requests but not make additional connections. - - [[rsocket-authentication-simple]] - === Simple Authentication - --Spring Security has support for https://github.com/rsocket/rsocket/blob/5920ed374d008abb712cb1fd7c9d91778b2f4a68/Extensions/Security/Simple.md[Simple Authentication Metadata Extension]. -+Spring Security has support for the https://github.com/rsocket/rsocket/blob/5920ed374d008abb712cb1fd7c9d91778b2f4a68/Extensions/Security/Simple.md[Simple Authentication Metadata Extension]. - --[NOTE] --==== --Basic Authentication drafts evolved into Simple Authentication and is only supported for backward compatibility. -+NOTE: Basic Authentication evolved into Simple Authentication and is only supported for backward compatibility. - See `RSocketSecurity.basicAuthentication(Customizer)` for setting it up. --==== - --The RSocket receiver can decode the credentials using `AuthenticationPayloadExchangeConverter` which is automatically setup using the `simpleAuthentication` portion of the DSL. --An explicit configuration can be found below. -+The RSocket receiver can decode the credentials by using `AuthenticationPayloadExchangeConverter`, which is automatically setup by using the `simpleAuthentication` portion of the DSL. -+The following example shows an explicit configuration: - -+==== - [source,java] - ---- - @Bean -@@ -101,17 +103,21 @@ PayloadSocketAcceptorInterceptor rsocketInterceptor(RSocketSecurity rsocket) { - return rsocket.build(); - } - ---- -+==== - --The RSocket sender can send credentials using `SimpleAuthenticationEncoder` which can be added to Spring's `RSocketStrategies`. -+The RSocket sender can send credentials by using `SimpleAuthenticationEncoder`, which you can add to Spring's `RSocketStrategies`. - -+==== - [source,java] - ---- - RSocketStrategies.Builder strategies = ...; - strategies.encoder(new SimpleAuthenticationEncoder()); - ---- -+==== - --It can then be used to send a username and password to the receiver in the setup: -+You can then use it to send a username and password to the receiver in the setup: - -+==== - [source,java] - ---- - MimeType authenticationMimeType = -@@ -122,9 +128,11 @@ Mono requester = RSocketRequester.builder() - .rsocketStrategies(strategies.build()) - .connectTcp(host, port); - ---- -+==== - --Alternatively or additionally, a username and password can be sent in a request. -+Alternatively or additionally, a username and password can be sent in a request: - -+==== - [source,java] - ---- - Mono requester; -@@ -138,16 +146,18 @@ public Mono findRadar(String code) { - ); - } - ---- -+==== - - [[rsocket-authentication-jwt]] - === JWT - --Spring Security has support for https://github.com/rsocket/rsocket/blob/5920ed374d008abb712cb1fd7c9d91778b2f4a68/Extensions/Security/Bearer.md[Bearer Token Authentication Metadata Extension]. --The support comes in the form of authenticating a JWT (determining the JWT is valid) and then using the JWT to make authorization decisions. -+Spring Security has support for the https://github.com/rsocket/rsocket/blob/5920ed374d008abb712cb1fd7c9d91778b2f4a68/Extensions/Security/Bearer.md[Bearer Token Authentication Metadata Extension]. -+The support comes in the form of authenticating a JWT (determining that the JWT is valid) and then using the JWT to make authorization decisions. - --The RSocket receiver can decode the credentials using `BearerPayloadExchangeConverter` which is automatically setup using the `jwt` portion of the DSL. --An example configuration can be found below: -+The RSocket receiver can decode the credentials by using `BearerPayloadExchangeConverter`, which is automatically setup by using the `jwt` portion of the DSL. -+The following listing shows an example configuration: - -+==== - [source,java] - ---- - @Bean -@@ -162,10 +172,12 @@ PayloadSocketAcceptorInterceptor rsocketInterceptor(RSocketSecurity rsocket) { - return rsocket.build(); - } - ---- -+==== - --The configuration above relies on the existence of a `ReactiveJwtDecoder` `@Bean` being present. --An example of creating one from the issuer can be found below: -+The preceding configuration relies a `ReactiveJwtDecoder` `@Bean` being present. -+The following example creates one from the issuer: - -+==== - [source,java] - ---- - @Bean -@@ -174,10 +186,12 @@ ReactiveJwtDecoder jwtDecoder() { - .fromIssuerLocation("https://example.com/auth/realms/demo"); - } - ---- -+==== - --The RSocket sender does not need to do anything special to send the token because the value is just a simple String. --For example, the token can be sent at setup time: -+The RSocket sender does not need to do anything special to send the token, because the value is a simple `String`. -+The following example sends the token at setup time: - -+==== - [source,java] - ---- - MimeType authenticationMimeType = -@@ -187,9 +201,11 @@ Mono requester = RSocketRequester.builder() - .setupMetadata(token, authenticationMimeType) - .connectTcp(host, port); - ---- -+==== - --Alternatively or additionally, the token can be sent in a request. -+Alternatively or additionally, you can send the token in a request: - -+==== - [source,java] - ---- - MimeType authenticationMimeType = -@@ -205,14 +221,16 @@ public Mono findRadar(String code) { - ); - } - ---- -+==== - - [[rsocket-authorization]] - == RSocket Authorization - --RSocket authorization is performed with `AuthorizationPayloadInterceptor` which acts as a controller to invoke a `ReactiveAuthorizationManager` instance. --The DSL can be used to setup authorization rules based upon the `PayloadExchange`. --An example configuration can be found below: -+RSocket authorization is performed with `AuthorizationPayloadInterceptor`, which acts as a controller to invoke a `ReactiveAuthorizationManager` instance. -+You can use the DSL to set up authorization rules based upon the `PayloadExchange`. -+The following listing shows an example configuration: - -+==== - [[source,java]] - ---- - rsocket -@@ -228,17 +246,18 @@ rsocket - .anyExchange().permitAll() // <6> - ) - ---- --<1> Setting up a connection requires the authority `ROLE_SETUP` --<2> If the route is `fetch.profile.me` authorization only requires the user be authenticated --<3> In this rule we setup a custom matcher where authorization requires the user to have the authority `ROLE_CUSTOM` --<4> This rule leverages custom authorization. --The matcher expresses a variable with the name `username` that is made available in the `context`. -+<1> Setting up a connection requires the `ROLE_SETUP` authority. -+<2> If the route is `fetch.profile.me`, authorization only requires the user to be authenticated. -+<3> In this rule, we set up a custom matcher, where authorization requires the user to have the `ROLE_CUSTOM` authority. -+<4> This rule uses custom authorization. -+The matcher expresses a variable with a name of `username` that is made available in the `context`. - A custom authorization rule is exposed in the `checkFriends` method. --<5> This rule ensures that request that does not already have a rule will require the user to be authenticated. -+<5> This rule ensures that a request that does not already have a rule requires the user to be authenticated. - A request is where the metadata is included. - It would not include additional payloads. - <6> This rule ensures that any exchange that does not already have a rule is allowed for anyone. --In this example, it means that payloads that have no metadata have no authorization rules. -+In this example, it means that payloads that have no metadata also have no authorization rules. -+==== - --It is important to understand that authorization rules are performed in order. --Only the first authorization rule that matches will be invoked. -+Note that authorization rules are performed in order. -+Only the first authorization rule that matches is invoked. -diff --git a/docs/manual/src/docs/asciidoc/_includes/reactive/test.adoc b/docs/manual/src/docs/asciidoc/_includes/reactive/test.adoc -index 4a9e3a9e39..247dc15a4c 100644 ---- a/docs/manual/src/docs/asciidoc/_includes/reactive/test.adoc -+++ b/docs/manual/src/docs/asciidoc/_includes/reactive/test.adoc -@@ -1,12 +1,15 @@ - [[test-webflux]] - = Reactive Test Support - -+This section describes how to test reactive applications that use Spring Security. -+ - [[test-erms]] - == Testing Reactive Method Security - --For example, we can test our example from <> using the same setup and annotations we did in <>. --Here is a minimal sample of what we can do: -+For example, we can test our example from <> by using the same setup and annotations that we used in <>. -+The following minimal sample shows what we can do: - -+==== - [source,java] - ---- - @RunWith(SpringRunner.class) -@@ -39,6 +42,7 @@ public class HelloWorldMessageServiceTests { - } - } - ---- -+==== - - [[test-webtestclient]] - == WebTestClientSupport -@@ -46,6 +50,7 @@ public class HelloWorldMessageServiceTests { - Spring Security provides integration with `WebTestClient`. - The basic setup looks like this: - -+==== - [source,java] - ---- - @RunWith(SpringRunner.class) -@@ -69,12 +74,13 @@ public class HelloWebfluxMethodApplicationTests { - // ... - } - ---- -+==== - - === Authentication - --After applying the Spring Security support to `WebTestClient` we can use either annotations or `mutateWith` support. --For example: -+After applying the Spring Security support to `WebTestClient`, we can use either annotations or `mutateWith` support -- for example: - -+==== - [source,java] - ---- - @Test -@@ -132,13 +138,14 @@ public void messageWhenMutateWithMockAdminThenOk() throws Exception { - .expectBody(String.class).isEqualTo("Hello World!"); - } - ---- -+==== - - - === CSRF Support - --Spring Security also provides support for CSRF testing with `WebTestClient`. --For example: -+Spring Security also provides support for CSRF testing with `WebTestClient` -- for example: - -+==== - [source,java] - ---- - this.rest -@@ -148,14 +155,16 @@ this.rest - .uri("/login") - ... - ---- -+==== - - [[webflux-testing-oauth2]] - === 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`. - --For example, for a controller that looks like this: -+Consider the following example of a controller: - -+==== - [source,java] - ---- - @GetMapping("/endpoint") -@@ -163,11 +172,13 @@ public Mono foo(Principal user) { - return Mono.just(user.getName()); - } - ---- -+==== - --There's nothing OAuth2-specific about it, so you will likely be able to simply <> and be fine. -+Nothing about it is OAuth2-specific, so you can <> and be fine. - --But, in cases where your controllers are bound to some aspect of Spring Security's OAuth 2.0 support, like the following: -+However, consider a case where your controller is bound to some aspect of Spring Security's OAuth 2.0 support: - -+==== - [source,java] - ---- - @GetMapping("/endpoint") -@@ -175,50 +186,59 @@ public Mono foo(@AuthenticationPrincipal OidcUser user) { - return Mono.just(user.getIdToken().getSubject()); - } - ---- -+==== - --then Spring Security's test support can come in handy. -+In that case, Spring Security's test support is handy. - - [[webflux-testing-oidc-login]] - === Testing OIDC Login - --Testing the method above with `WebTestClient` 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. -+Testing the method shown in the <> with `WebTestClient` requires simulating some kind of grant flow with an authorization server. -+This is a daunting task, which is why Spring Security ships with support for removing this boilerplate. - --For example, we can tell Spring Security to include a default `OidcUser` using the `SecurityMockServerConfigurers#oidcLogin` method, like so: -+For example, we can tell Spring Security to include a default `OidcUser` by using the `SecurityMockServerConfigurers#oidcLogin` method: - -+==== - [source,java] - ---- - client - .mutateWith(mockOidcLogin()).get().uri("/endpoint").exchange(); - ---- -+==== - --What this will do is configure the associated `MockServerRequest` with an `OidcUser` that includes a simple `OidcIdToken`, `OidcUserInfo`, and `Collection` of granted authorities. -+That line configures the associated `MockServerRequest` with an `OidcUser` that includes a simple `OidcIdToken`, an `OidcUserInfo`, and a `Collection` of granted authorities. - --Specifically, it will include an `OidcIdToken` with a `sub` claim set to `user`: -+Specifically, it includes an `OidcIdToken` with a `sub` claim set to `user`: - -+==== - [source,json] - ---- - assertThat(user.getIdToken().getClaim("sub")).isEqualTo("user"); - ---- -+==== - --an `OidcUserInfo` with no claims set: -+It also includes an `OidcUserInfo` with no claims set: - -+==== - [source,json] - ---- - assertThat(user.getUserInfo().getClaims()).isEmpty(); - ---- -+==== - --and a `Collection` of authorities with just one authority, `SCOPE_read`: -+It also includes a `Collection` of authorities with just one authority, `SCOPE_read`: - -+==== - [source,json] - ---- - assertThat(user.getAuthorities()).hasSize(1); - assertThat(user.getAuthorities()).containsExactly(new SimpleGrantedAuthority("SCOPE_read")); - ---- -+==== - --Spring Security does the necessary work to make sure that the `OidcUser` instance is available for <>. -+Spring Security makes sure that the `OidcUser` instance is available for <>. - --Further, it also links that `OidcUser` to a simple instance of `OAuth2AuthorizedClient` that it deposits into a mock `ServerOAuth2AuthorizedClientRepository`. -+Further, it also links the `OidcUser` to a simple instance of `OAuth2AuthorizedClient` that it deposits into a mock `ServerOAuth2AuthorizedClientRepository`. - This can be handy if your tests <>.. - - [[webflux-testing-oidc-login-authorities]] -@@ -226,8 +246,9 @@ This can be handy if your tests < foo(@AuthenticationPrincipal OidcUser oidcUser) { - // ... - } - ---- -+==== - --In that case, you'd want to specify that claim with the `idToken()` method: -+In that case, you can specify that claim with the `idToken()` method: - -+==== - [source,java] - ---- - client -@@ -264,25 +289,27 @@ client - ) - .get().uri("/endpoint").exchange(); - ---- -+==== - --since `OidcUser` collects its claims from `OidcIdToken`. -+That works because `OidcUser` collects its claims from `OidcIdToken`. - - [[webflux-testing-oidc-login-user]] - ==== Additional Configurations - --There are additional methods, too, for further configuring the authentication; it simply depends on what data your controller expects: -+There are additional methods, too, for further configuring the authentication, depending on what data your controller expects: - --* `userInfo(OidcUserInfo.Builder)` - For configuring the `OidcUserInfo` instance --* `clientRegistration(ClientRegistration)` - For configuring the associated `OAuth2AuthorizedClient` with a given `ClientRegistration` --* `oidcUser(OidcUser)` - For configuring the complete `OidcUser` instance -+* `userInfo(OidcUserInfo.Builder)`: Configures the `OidcUserInfo` instance -+* `clientRegistration(ClientRegistration)`: Configures the associated `OAuth2AuthorizedClient` with a given `ClientRegistration` -+* `oidcUser(OidcUser)`: Configures the complete `OidcUser` instance - - That last one is handy if you: --1. Have your own implementation of `OidcUser`, or --2. Need to change the name attribute -+* Have your own implementation of `OidcUser` or -+* Need to change the name attribute - --For example, let's say that your authorization server sends the principal name in the `user_name` claim instead of the `sub` claim. -+For example, suppose that your authorization server sends the principal name in the `user_name` claim instead of the `sub` claim. - In that case, you can configure an `OidcUser` by hand: - -+==== - [source,java] - ---- - OidcUser oidcUser = new DefaultOidcUser( -@@ -294,15 +321,17 @@ client - .mutateWith(mockOidcLogin().oidcUser(oidcUser)) - .get().uri("/endpoint").exchange(); - ---- -+==== - - [[webflux-testing-oauth2-login]] - === Testing OAuth 2.0 Login - --As with <>, 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. -+As with <>, testing OAuth 2.0 Login presents a similar challenge: mocking a grant flow. -+Because of that, Spring Security also has test support for non-OIDC use cases. - --Let's say that we've got a controller that gets the logged-in user as an `OAuth2User`: -+Suppose that we have a controller that gets the logged-in user as an `OAuth2User`: - -+==== - [source,java] - ---- - @GetMapping("/endpoint") -@@ -310,32 +339,39 @@ public Mono foo(@AuthenticationPrincipal OAuth2User oauth2User) { - return Mono.just(oauth2User.getAttribute("sub")); - } - ---- -+==== - --In that case, we can tell Spring Security to include a default `OAuth2User` using the `SecurityMockServerConfigurers#oauth2User` method, like so: -+In that case, we can tell Spring Security to include a default `OAuth2User` by using the `SecurityMockServerConfigurers#oauth2User` method: - -+==== - [source,java] - ---- - client - .mutateWith(mockOAuth2Login()) - .get().uri("/endpoint").exchange(); - ---- -+==== - --What this will do is configure the associated `MockServerRequest` with an `OAuth2User` that includes a simple `Map` of attributes and `Collection` of granted authorities. -+The preceding example configures the associated `MockServerRequest` with an `OAuth2User` that includes a simple `Map` of attributes and a `Collection` of granted authorities. - --Specifically, it will include a `Map` with a key/value pair of `sub`/`user`: -+Specifically, it includes a `Map` with a key/value pair of `sub`/`user`: - -+==== - [source,json] - ---- - assertThat((String) user.getAttribute("sub")).isEqualTo("user"); - ---- -+==== - --and a `Collection` of authorities with just one authority, `SCOPE_read`: -+It also includes a `Collection` of authorities with just one authority, `SCOPE_read`: - -+==== - [source,json] - ---- - assertThat(user.getAuthorities()).hasSize(1); - assertThat(user.getAuthorities()).containsExactly(new SimpleGrantedAuthority("SCOPE_read")); - ---- -+==== - - Spring Security does the necessary work to make sure that the `OAuth2User` instance is available for <>. - -@@ -347,8 +383,9 @@ This can be handy if your tests < foo(@AuthenticationPrincipal OAuth2User oauth2User) { - // ... - } - ---- -+==== - --In that case, you'd want to specify that attribute with the `attributes()` method: -+In that case, you can specify that attribute with the `attributes()` method: - -+==== - [source,java] - ---- - client -@@ -385,22 +426,24 @@ client - ) - .get().uri("/endpoint").exchange(); - ---- -+==== - - [[webflux-testing-oauth2-login-user]] - ==== Additional Configurations - --There are additional methods, too, for further configuring the authentication; it simply depends on what data your controller expects: -+There are additional methods, too, for further configuring the authentication, depending on what data your controller expects: - --* `clientRegistration(ClientRegistration)` - For configuring the associated `OAuth2AuthorizedClient` with a given `ClientRegistration` --* `oauth2User(OAuth2User)` - For configuring the complete `OAuth2User` instance -+* `clientRegistration(ClientRegistration)`: Configures the associated `OAuth2AuthorizedClient` with a given `ClientRegistration` -+* `oauth2User(OAuth2User)`: Configures the complete `OAuth2User` instance - - That last one is handy if you: --1. Have your own implementation of `OAuth2User`, or --2. Need to change the name attribute -+* Have your own implementation of `OAuth2User` or -+* Need to change the name attribute - --For example, let's say that your authorization server sends the principal name in the `user_name` claim instead of the `sub` claim. -+For example, suppose that your authorization server sends the principal name in the `user_name` claim instead of the `sub` claim. - In that case, you can configure an `OAuth2User` by hand: - -+==== - [source,java] - ---- - OAuth2User oauth2User = new DefaultOAuth2User( -@@ -412,14 +455,16 @@ client - .mutateWith(mockOAuth2Login().oauth2User(oauth2User)) - .get().uri("/endpoint").exchange(); - ---- -+==== - - [[webflux-testing-oauth2-client]] - === 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: -+For example, your controller may rely on the client credentials grant to get a token that is not associated with the user at all: - --[source,json] -+==== -+[source,java] - ---- - @GetMapping("/endpoint") - public Mono foo(@RegisteredOAuth2AuthorizedClient("my-app") OAuth2AuthorizedClient authorizedClient) { -@@ -429,51 +474,61 @@ public Mono foo(@RegisteredOAuth2AuthorizedClient("my-app") OAuth2Author - .bodyToMono(String.class); - } - ---- -+==== - --Simulating this handshake with the authorization server could be cumbersome. --Instead, you can use `SecurityMockServerConfigurers#oauth2Client` to add a `OAuth2AuthorizedClient` into a mock `ServerOAuth2AuthorizedClientRepository`: -+Simulating this handshake with the authorization server can be cumbersome. -+Instead, you can use `SecurityMockServerConfigurers#oauth2Client` to add a `OAuth2AuthorizedClient` to a mock `ServerOAuth2AuthorizedClientRepository`: - -+==== - [source,java] - ---- - client - .mutateWith(mockOAuth2Client("my-app")) - .get().uri("/endpoint").exchange(); - ---- -+==== - --What this will do is create an `OAuth2AuthorizedClient` that has a simple `ClientRegistration`, `OAuth2AccessToken`, and resource owner name. -+This creates an `OAuth2AuthorizedClient` that has a simple `ClientRegistration`, a `OAuth2AccessToken`, and a resource owner name. - --Specifically, it will include a `ClientRegistration` with a client id of "test-client" and client secret of "test-secret": -+Specifically, it includes a `ClientRegistration` with a client ID of `test-client` and a client secret of `test-secret`: - -+==== - [source,json] - ---- - assertThat(authorizedClient.getClientRegistration().getClientId()).isEqualTo("test-client"); - assertThat(authorizedClient.getClientRegistration().getClientSecret()).isEqualTo("test-secret"); - ---- -+==== - --a resource owner name of "user": -+It also includes a resource owner name of `user`: - -+==== - [source,json] - ---- - assertThat(authorizedClient.getPrincipalName()).isEqualTo("user"); - ---- -+==== - --and an `OAuth2AccessToken` with just one scope, `read`: -+It also includes an `OAuth2AccessToken` with one scope, `read`: - -+==== - [source,json] - ---- - assertThat(authorizedClient.getAccessToken().getScopes()).hasSize(1); - assertThat(authorizedClient.getAccessToken().getScopes()).containsExactly("read"); - ---- -+==== - --The client can then be retrieved as normal using `@RegisteredOAuth2AuthorizedClient` in a controller method. -+You can then retrieve the client as usual by using `@RegisteredOAuth2AuthorizedClient` in a controller method. - - [[webflux-testing-oauth2-client-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: -+Consider the following example of how a controller can inspect the scopes: - --[source,json] -+==== -+[source,java] - ---- - @GetMapping("/endpoint") - public Mono foo(@RegisteredOAuth2AuthorizedClient("my-app") OAuth2AuthorizedClient authorizedClient) { -@@ -487,9 +542,11 @@ public Mono foo(@RegisteredOAuth2AuthorizedClient("my-app") OAuth2Author - // ... - } - ---- -+==== - --then you can configure the scope using the `accessToken()` method: -+Given a controller that inspects scopes, you can configure the scope by using the `accessToken()` method: - -+==== - [source,java] - ---- - client -@@ -498,22 +555,24 @@ client - ) - .get().uri("/endpoint").exchange(); - ---- -+==== - - [[webflux-testing-oauth2-client-registration]] - ==== Additional Configurations - --There are additional methods, too, for further configuring the authentication; it simply depends on what data your controller expects: -+You can also use additional methods to further configure the authentication depending on what data your controller expects: - --* `principalName(String)` - For configuring the resource owner name --* `clientRegistration(Consumer)` - For configuring the associated `ClientRegistration` --* `clientRegistration(ClientRegistration)` - For configuring the complete `ClientRegistration` -+* `principalName(String)`; Configures the resource owner name -+* `clientRegistration(Consumer)`: Configures the associated `ClientRegistration` -+* `clientRegistration(ClientRegistration)`: Configures the complete `ClientRegistration` - - That last one is handy if you want to use a real `ClientRegistration` - --For example, let's say that you are wanting to use one of your app's `ClientRegistration` definitions, as specified in your `application.yml`. -+For example, suppose that you want to use one of your application's `ClientRegistration` definitions, as specified in your `application.yml`. - - In that case, your test can autowire the `ReactiveClientRegistrationRepository` and look up the one your test needs: - -+==== - [source,java] - ---- - @Autowired -@@ -527,32 +586,36 @@ client - ) - .get().uri("/exchange").exchange(); - ---- -+==== - - [[webflux-testing-jwt]] - === Testing JWT Authentication - --In order to make an authorized request on a resource server, you need a bearer token. --If your resource server is configured for JWTs, then this would mean that the bearer token needs to be signed and then encoded according to the JWT specification. --All of this can be quite daunting, especially when this isn't the focus of your test. -+To make an authorized request on a resource server, you need a bearer token. -+If your resource server is configured for JWTs, the bearer token needs to be signed and then encoded according to the JWT specification. -+All of this can be quite daunting, especially when this is not the focus of your test. - --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: -+Fortunately, there are a number of simple ways in which you can overcome this difficulty and let your tests focus on authorization and not on representing bearer tokens. -+We look at two of them in the next two subsections. - - ==== `mockJwt() WebTestClientConfigurer` - --The first way is via a `WebTestClientConfigurer`. -+The first way is with a `WebTestClientConfigurer`. - The simplest of these would look something like this: - -+==== - [source,java] - ---- - client - .mutateWith(mockJwt()).get().uri("/endpoint").exchange(); - ---- -+==== - --What this will do is create a mock `Jwt`, passing it correctly through any authentication APIs so that it's available for your authorization mechanisms to verify. -+This example creates a mock `Jwt` and passes it through any authentication APIs so that it is available for your authorization mechanisms to verify. - - By default, the `JWT` that it creates has the following characteristics: - -+==== - [source,json] - ---- - { -@@ -563,9 +626,11 @@ By default, the `JWT` that it creates has the following characteristics: - } - } - ---- -+==== - --And the resulting `Jwt`, were it tested, would pass in the following way: -+The resulting `Jwt`, were it tested, would pass in the following way: - -+==== - [source,java] - ---- - assertThat(jwt.getTokenValue()).isEqualTo("token"); -@@ -574,11 +639,13 @@ assertThat(jwt.getSubject()).isEqualTo("sub"); - GrantedAuthority authority = jwt.getAuthorities().iterator().next(); - assertThat(authority.getAuthority()).isEqualTo("read"); - ---- -+==== - --These values can, of course be configured. -+Note that you configure these values. - --Any headers or claims can be configured with their corresponding methods: -+You can also configure any headers or claims with their corresponding methods: - -+==== - [source,java] - ---- - client -@@ -593,28 +660,34 @@ client - .mutateWith(mockJwt().jwt(jwt -> jwt.claims(claims -> claims.remove("scope")))) - .get().uri("/endpoint").exchange(); - ---- -+==== - - The `scope` and `scp` claims are processed the same way here as they are in a normal bearer token request. - However, this can be overridden simply by providing the list of `GrantedAuthority` instances that you need for your test: - -+==== - [source,java] - ---- - client - .mutateWith(jwt().authorities(new SimpleGrantedAuthority("SCOPE_messages"))) - .get().uri("/endpoint").exchange(); - ---- -+==== - --Or, if you have a custom `Jwt` to `Collection` converter, you can also use that to derive the authorities: -+Alternatively, if you have a custom `Jwt` to `Collection` converter, you can also use that to derive the authorities: - -+==== - [source,java] - ---- - client - .mutateWith(jwt().authorities(new MyConverter())) - .get().uri("/endpoint").exchange(); - ---- -+==== - --You can also specify a complete `Jwt`, for which `{security-api-url}org/springframework/security/oauth2/jwt/Jwt.Builder.html[Jwt.Builder]` comes quite handy: -+You can also specify a complete `Jwt`, for which `{security-api-url}org/springframework/security/oauth2/jwt/Jwt.Builder.html[Jwt.Builder]` is quite handy: - -+==== - [source,java] - ---- - Jwt jwt = Jwt.withTokenValue("token") -@@ -626,12 +699,14 @@ client - .mutateWith(mockJwt().jwt(jwt)) - .get().uri("/endpoint").exchange(); - ---- -+==== - --==== `authentication()` `WebTestClientConfigurer` -+==== `authentication()` and `WebTestClientConfigurer` - - The second way is by using the `authentication()` `Mutator`. --Essentially, you can instantiate your own `JwtAuthenticationToken` and provide it in your test, like so: -+You can instantiate your own `JwtAuthenticationToken` and provide it in your test: - -+==== - [source,java] - ---- - Jwt jwt = Jwt.withTokenValue("token") -@@ -645,8 +720,9 @@ client - .mutateWith(authentication(token)) - .get().uri("/endpoint").exchange(); - ---- -+==== - --Note that as an alternative to these, you can also mock the `ReactiveJwtDecoder` bean itself with a `@MockBean` annotation. -+Note that, as an alternative to these, you can also mock the `ReactiveJwtDecoder` bean itself with a `@MockBean` annotation. - - [[webflux-testing-opaque-token]] - === Testing Opaque Token Authentication -@@ -654,8 +730,9 @@ Note that as an alternative to these, you can also mock the `ReactiveJwtDecoder` - Similar to <>, 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. - --Let's say that we've got a controller that retrieves the authentication as a `BearerTokenAuthentication`: -+Suppose you have a controller that retrieves the authentication as a `BearerTokenAuthentication`: - -+==== - [source,java] - ---- - @GetMapping("/endpoint") -@@ -663,42 +740,50 @@ public Mono foo(BearerTokenAuthentication authentication) { - return Mono.just((String) authentication.getTokenAttributes("sub")); - } - ---- -+==== - --In that case, we can tell Spring Security to include a default `BearerTokenAuthentication` using the `SecurityMockServerConfigurers#opaqueToken` method, like so: -+In that case, you can tell Spring Security to include a default `BearerTokenAuthentication` by using the `SecurityMockServerConfigurers#opaqueToken` method: - -+==== - [source,java] - ---- - client - .mutateWith(mockOpaqueToken()) - .get().uri("/endpoint").exchange(); - ---- -+==== - --What this will do is configure the associated `MockHttpServletRequest` with a `BearerTokenAuthentication` that includes a simple `OAuth2AuthenticatedPrincipal`, `Map` of attributes, and `Collection` of granted authorities. -+This example configures the associated `MockHttpServletRequest` with a `BearerTokenAuthentication` that includes a simple `OAuth2AuthenticatedPrincipal`, a `Map` of attributes, and a `Collection` of granted authorities. - --Specifically, it will include a `Map` with a key/value pair of `sub`/`user`: -+Specifically, it includes a `Map` with a key/value pair of `sub`/`user`: - -+==== - [source,json] - ---- - assertThat((String) token.getTokenAttributes().get("sub")).isEqualTo("user"); - ---- -+==== - --and a `Collection` of authorities with just one authority, `SCOPE_read`: -+It also includes a `Collection` of authorities with just one authority, `SCOPE_read`: - -+==== - [source,json] - ---- - assertThat(token.getAuthorities()).hasSize(1); - assertThat(token.getAuthorities()).containsExactly(new SimpleGrantedAuthority("SCOPE_read")); - ---- -+==== - --Spring Security does the necessary work to make sure that the `BearerTokenAuthentication` instance is available for your controller methods. -+Spring Security makes sure that the `BearerTokenAuthentication` instance is available for your controller methods. - - [[webflux-testing-opaque-token-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. - --In this case, you can supply what granted authorities you need using the `authorities()` method: -+In those cases, you can supply the granted authorities you need by using the `authorities()` method: - -+==== - [source,java] - ---- - client -@@ -707,15 +792,17 @@ client - ) - .get().uri("/endpoint").exchange(); - ---- -+==== - - [[webflux-testing-opaque-token-attributes]] - ==== 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. -+While granted authorities are quite common across all of Spring Security, we also have attributes in the case of OAuth 2.0. - --Let's say, for example, that you've got a `user_id` attribute that indicates the user's id in your system. --You might access it like so in a controller: -+Suppose, for example, that you have a `user_id` attribute that indicates the user's ID in your system. -+You might access it as follows in a controller: - -+==== - [source,java] - ---- - @GetMapping("/endpoint") -@@ -724,9 +811,11 @@ public Mono foo(BearerTokenAuthentication authentication) { - // ... - } - ---- -+==== - --In that case, you'd want to specify that attribute with the `attributes()` method: -+In that case, you can specify that attribute with the `attributes()` method: - -+==== - [source,java] - ---- - client -@@ -735,21 +824,23 @@ client - ) - .get().uri("/endpoint").exchange(); - ---- -+==== - - [[webflux-testing-opaque-token-principal]] - ==== Additional Configurations - --There are additional methods, too, for further configuring the authentication; it simply depends on what data your controller expects. -+You can also use additional methods to further configure the authentication, depending on what data your controller expects. - --One such is `principal(OAuth2AuthenticatedPrincipal)`, which you can use to configure the complete `OAuth2AuthenticatedPrincipal` instance that underlies the `BearerTokenAuthentication` -+One such method is `principal(OAuth2AuthenticatedPrincipal)`, which you can use to configure the complete `OAuth2AuthenticatedPrincipal` instance that underlies the `BearerTokenAuthentication`. - --It's handy if you: --1. Have your own implementation of `OAuth2AuthenticatedPrincipal`, or --2. Want to specify a different principal name -+It is handy if you: -+* Have your own implementation of `OAuth2AuthenticatedPrincipal` or -+* Want to specify a different principal name - --For example, let's say that your authorization server sends the principal name in the `user_name` attribute instead of the `sub` attribute. -+For example, suppose that your authorization server sends the principal name in the `user_name` attribute instead of the `sub` attribute. - In that case, you can configure an `OAuth2AuthenticatedPrincipal` by hand: - -+==== - [source,java] - ---- - Map attributes = Collections.singletonMap("user_name", "foo_user"); -@@ -762,5 +853,6 @@ client - .mutateWith(mockOpaqueToken().principal(principal)) - .get().uri("/endpoint").exchange(); - ---- -+==== - --Note that as an alternative to using `mockOpaqueToken()` test support, you can also mock the `OpaqueTokenIntrospector` bean itself with a `@MockBean` annotation. -+Note that, as an alternative to using `mockOpaqueToken()` test support, you can also mock the `OpaqueTokenIntrospector` bean itself with a `@MockBean` annotation. -diff --git a/docs/manual/src/docs/asciidoc/_includes/reactive/webclient.adoc b/docs/manual/src/docs/asciidoc/_includes/reactive/webclient.adoc -index 181ac58b2c..5de656a0e8 100644 ---- a/docs/manual/src/docs/asciidoc/_includes/reactive/webclient.adoc -+++ b/docs/manual/src/docs/asciidoc/_includes/reactive/webclient.adoc -@@ -1,13 +1,9 @@ - = WebClient - --[NOTE] --==== --The following documentation is for use within Reactive environments. --For Servlet environments, refer to <> environments. --==== -- -+NOTE: The documentation in this section is for use within Reactive environments. -+For Servlet environments, see <>. - --Spring Framework has built in support for setting a Bearer token. -+Spring Framework has built-in support for setting a Bearer token: - - ==== - .Java -@@ -29,17 +25,17 @@ webClient.get() - - Spring Security builds on this support to provide additional benefits: - --* Spring Security will automatically refresh expired tokens (if a refresh token is present) --* If an access token is requested and not present, Spring Security will automatically request the access token. --** For authorization_code this involves performing the redirect and then replaying the original request --** For client_credentials the token is simply requested and saved -+* Spring Security automatically refreshes expired tokens (if a refresh token is present). -+* If an access token is requested and not present, Spring Security automatically requests the access token. -+** For `authorization_code`, this involves performing the redirect and then replaying the original request. -+** For `client_credentials`, the token is requested and saved. - * Support for the ability to transparently include the current OAuth token or explicitly select which token should be used. - - [[webclient-setup]] - == WebClient OAuth2 Setup - --The first step is ensuring to setup the `WebClient` correctly. --An example of setting up `WebClient` in a fully reactive environment can be found below: -+The first step is ensuring that the `WebClient` is set up correctly. -+The following example shows how to set up `WebClient` in a fully reactive environment: - - ==== - .Java -@@ -81,8 +77,8 @@ fun webClient(clientRegistrations: ReactiveClientRegistrationRepository, - [[webclient-implicit]] - == Implicit OAuth2AuthorizedClient - --If we set `defaultOAuth2AuthorizedClient` to `true` in our setup and the user authenticated with oauth2Login (i.e. OIDC), then the current authentication is used to automatically provide the access token. --Alternatively, if we set `defaultClientRegistrationId` to a valid `ClientRegistration` id, that registration is used to provide the access token. -+If we set `defaultOAuth2AuthorizedClient` to `true` in our setup and the user authenticated with `oauth2Login` (OIDC), the current authentication is used to automatically provide the access token. -+Alternatively, if we set `defaultClientRegistrationId` to a valid `ClientRegistration` ID, that registration is used to provide the access token. - This is convenient, but in environments where not all endpoints should get the access token, it is dangerous (you might provide the wrong access token to an endpoint). - - ==== -@@ -110,8 +106,8 @@ val body: Mono = webClient - [[webclient-explicit]] - == Explicit OAuth2AuthorizedClient - --The `OAuth2AuthorizedClient` can be explicitly provided by setting it on the requests attributes. --In the example below we resolve the `OAuth2AuthorizedClient` using Spring WebFlux or Spring MVC argument resolver support. -+You can explicitly provide the `OAuth2AuthorizedClient` by setting it on the request attributes. -+In the next example, we resolve the `OAuth2AuthorizedClient` by using Spring WebFlux or the Spring MVC argument resolver support. - However, it does not matter how the `OAuth2AuthorizedClient` is resolved. - - ==== -@@ -147,8 +143,8 @@ fun explicit(@RegisteredOAuth2AuthorizedClient("client-id") authorizedClient: OA - [[webclient-clientregistrationid]] - == clientRegistrationId - --Alternatively, it is possible to specify the `clientRegistrationId` on the request attributes and the `WebClient` will attempt to lookup the `OAuth2AuthorizedClient`. --If it is not found, one will automatically be acquired. -+Alternatively, you can specify the `clientRegistrationId` on the request attributes, and the `WebClient` tries to look up the `OAuth2AuthorizedClient`. -+If it is not found, one is automatically acquired. - - ==== - .Java -diff --git a/docs/manual/src/docs/asciidoc/_includes/reactive/webflux.adoc b/docs/manual/src/docs/asciidoc/_includes/reactive/webflux.adoc -index d6a5263a35..d181b8c100 100644 ---- a/docs/manual/src/docs/asciidoc/_includes/reactive/webflux.adoc -+++ b/docs/manual/src/docs/asciidoc/_includes/reactive/webflux.adoc -@@ -2,7 +2,7 @@ - = WebFlux Security - - Spring Security's WebFlux support relies on a `WebFilter` and works the same for Spring WebFlux and Spring WebFlux.Fn. --You can find a few sample applications that demonstrate the code below: -+A few sample applications demonstrate the code: - - * Hello WebFlux {gh-samples-url}/boot/hellowebflux[hellowebflux] - * Hello WebFlux.Fn {gh-samples-url}/boot/hellowebfluxfn[hellowebfluxfn] -@@ -11,7 +11,7 @@ You can find a few sample applications that demonstrate the code below: - - == Minimal WebFlux Security Configuration - --You can find a minimal WebFlux Security configuration below: -+The following listing shows a minimal WebFlux Security configuration: - - .Minimal WebFlux Security Configuration - ==== -@@ -53,11 +53,11 @@ class HelloWebfluxSecurityConfig { - ----- - ==== - --This configuration provides form and http basic authentication, sets up authorization to require an authenticated user for accessing any page, sets up a default log in page and a default log out page, sets up security related HTTP headers, CSRF protection, and more. -+This configuration provides form and HTTP basic authentication, sets up authorization to require an authenticated user for accessing any page, sets up a default login page and a default logout page, sets up security related HTTP headers, adds CSRF protection, and more. - - == Explicit WebFlux Security Configuration - --You can find an explicit version of the minimal WebFlux Security configuration below: -+The following page shows an explicit version of the minimal WebFlux Security configuration: - - .Explicit WebFlux Security Configuration - ==== -@@ -123,17 +123,18 @@ class HelloWebfluxSecurityConfig { - ==== - - This configuration explicitly sets up all the same things as our minimal configuration. --From here you can easily make the changes to the defaults. -+From here, you can more easily make changes to the defaults. - --You can find more examples of explicit configuration in unit tests, by searching https://github.com/spring-projects/spring-security/search?q=path%3Aconfig%2Fsrc%2Ftest%2F+EnableWebFluxSecurity[EnableWebFluxSecurity in the `config/src/test/` directory]. -+You can find more examples of explicit configuration in unit tests, by searching for https://github.com/spring-projects/spring-security/search?q=path%3Aconfig%2Fsrc%2Ftest%2F+EnableWebFluxSecurity[`EnableWebFluxSecurity` in the `config/src/test/` directory]. - - [[jc-webflux-multiple-filter-chains]] - === Multiple Chains Support - --You can configure multiple `SecurityWebFilterChain` instances to separate configuration by `RequestMatcher` s. -+You can configure multiple `SecurityWebFilterChain` instances to separate configuration by `RequestMatcher` instances. - --For example, you can isolate configuration for URLs that start with `/api`, like so: -+For example, you can isolate configuration for URLs that start with `/api`: - -+==== - [source,java] - ---- - @Configuration -@@ -171,15 +172,15 @@ static class MultiSecurityHttpConfig { - } - ---- - --<1> Configure a `SecurityWebFilterChain` with an `@Order` to specify which `SecurityWebFilterChain` Spring Security should consider first --<2> Use `PathPatternParserServerWebExchangeMatcher` to state that this `SecurityWebFilterChain` will only apply to URL paths that start with `/api/` --<3> Specify the authentication mechanisms that will be used for `/api/**` endpoints --<4> Create another instance of `SecurityWebFilterChain` with lower precedence to match all other URLs --<5> Specify the authentication mechanisms that will be used for the rest of the application -- --Spring Security will select one `SecurityWebFilterChain` `@Bean` for each request. --It will match the requests in order by the `securityMatcher` definition. -+<1> Configure a `SecurityWebFilterChain` with an `@Order` to specify which `SecurityWebFilterChain` Spring Security should consider first. -+<2> Use `PathPatternParserServerWebExchangeMatcher` to state that this `SecurityWebFilterChain` applies only to URL paths that start with `/api/`. -+<3> Specify the authentication mechanisms that is used for `/api/**` endpoints. -+<4> Create another instance of `SecurityWebFilterChain` with lower precedence to match all other URLs. -+<5> Specify the authentication mechanisms that is used for the rest of the application. -+==== - --In this case, that means that if the URL path starts with `/api`, then Spring Security will use `apiHttpSecurity`. --If the URL does not start with `/api` then Spring Security will default to `webHttpSecurity`, which has an implied `securityMatcher` that matches any request. -+Spring Security selects one `SecurityWebFilterChain` `@Bean` for each request. -+It matches the requests in order by the `securityMatcher` definition. - -+In this case, that means that, if the URL path starts with `/api`, Spring Security uses `apiHttpSecurity`. -+If the URL does not start with `/api`, Spring Security defaults to `webHttpSecurity`, which has an implied `securityMatcher` that matches any request. -diff --git a/docs/manual/src/docs/asciidoc/_includes/reactive/x509.adoc b/docs/manual/src/docs/asciidoc/_includes/reactive/x509.adoc -index 694b905093..515ae7533e 100644 ---- a/docs/manual/src/docs/asciidoc/_includes/reactive/x509.adoc -+++ b/docs/manual/src/docs/asciidoc/_includes/reactive/x509.adoc -@@ -1,9 +1,11 @@ - [[reactive-x509]] - = Reactive X.509 Authentication - --Similar to <>, reactive x509 authentication filter allows extracting an authentication token from a certificate provided by a client. -+Similar to <>, the reactive x509 authentication filter allows extracting an authentication token from a certificate provided by a client. - --Below is an example of a reactive x509 security configuration: -+The folloiwng example shows a reactive x509 security configuration: -+ -+==== - [source,java] - ---- - @Bean -@@ -16,11 +18,13 @@ public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) { - return http.build(); - } - ---- -+==== - --In the configuration above, when neither `principalExtractor` nor `authenticationManager` is provided defaults will be used. The default principal extractor is `SubjectDnX509PrincipalExtractor` which extracts the CN (common name) field from a certificate provided by a client. The default authentication manager is `ReactivePreAuthenticatedAuthenticationManager` which performs user account validation, checking that user account with a name extracted by `principalExtractor` exists and it is not locked, disabled, or expired. -+In the preceding configuration, when neither `principalExtractor` nor `authenticationManager` is provided, defaults are used. The default principal extractor is `SubjectDnX509PrincipalExtractor`, which extracts the CN (common name) field from a certificate provided by a client. The default authentication manager is `ReactivePreAuthenticatedAuthenticationManager`, which performs user account validation, checking that a user account with a name extracted by `principalExtractor` exists and that it is not locked, disabled, or expired. - --The next example demonstrates how these defaults can be overridden. -+The following example demonstrates how these defaults can be overridden: - -+==== - [source,java] - ---- - @Bean -@@ -46,7 +50,8 @@ public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) { - return http.build(); - } - ---- -+==== - --In this example, a username is extracted from the OU field of a client certificate instead of CN, and account lookup using `ReactiveUserDetailsService` is not performed at all. Instead, if the provided certificate issued to an OU named "Trusted Org Unit", a request will be authenticated. -+In the previous example, a username is extracted from the OU field of a client certificate instead of CN, and account lookup using `ReactiveUserDetailsService` is not performed at all. Instead, if the provided certificate issued to an OU named "`Trusted Org Unit`", a request is authenticated. - - For an example of configuring Netty and `WebClient` or `curl` command-line tool to use mutual TLS and enable X.509 authentication, please refer to https://github.com/spring-projects/spring-security-samples/tree/main/servlet/java-configuration/authentication/x509. -diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/appendix/database-schema.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/appendix/database-schema.adoc -index ab840e131f..8998047ec2 100644 ---- a/docs/manual/src/docs/asciidoc/_includes/servlet/appendix/database-schema.adoc -+++ b/docs/manual/src/docs/asciidoc/_includes/servlet/appendix/database-schema.adoc -@@ -1,19 +1,19 @@ - [[appendix-schema]] - = Security Database Schema --There are various database schema used by the framework and this appendix provides a single reference point to them all. --You only need to provide the tables for the areas of functionality you require. -+The framework uses various database schema. This appendix provides a single reference point to them all. -+You need only provide the tables for the areas of functionality you require. - - DDL statements are given for the HSQLDB database. --You can use these as a guideline for defining the schema for the database you are using. -+You can use these as a guideline for defining the schema for the database you use. - - - == User Schema --The standard JDBC implementation of the `UserDetailsService` (`JdbcDaoImpl`) requires tables to load the password, account status (enabled or disabled) and a list of authorities (roles) for the user. --You will need to adjust this schema to match the database dialect you are using. -+The standard JDBC implementation of the `UserDetailsService` (`JdbcDaoImpl`) requires tables to load the password, account status (enabled or disabled), and a list of authorities (roles) for the user. -+You need to adjust this schema to match the database dialect you use: - -+==== - [source] - ---- -- - create table users( - username varchar_ignorecase(50) not null primary key, - password varchar_ignorecase(50) not null, -@@ -27,8 +27,13 @@ create table authorities ( - ); - create unique index ix_auth_username on authorities (username,authority); - ---- -+==== - - === For Oracle database -+ -+The following listing shows the Oracle variant of the schema creation commands: -+ -+==== - [source] - ---- - CREATE TABLE USERS ( -@@ -45,15 +50,15 @@ CREATE TABLE AUTHORITIES ( - ALTER TABLE AUTHORITIES ADD CONSTRAINT AUTHORITIES_UNIQUE UNIQUE (USERNAME, AUTHORITY); - ALTER TABLE AUTHORITIES ADD CONSTRAINT AUTHORITIES_FK1 FOREIGN KEY (USERNAME) REFERENCES USERS (USERNAME) ENABLE; - ---- -+==== - - === Group Authorities - Spring Security 2.0 introduced support for group authorities in `JdbcDaoImpl`. --The table structure if groups are enabled is as follows. --You will need to adjust this schema to match the database dialect you are using. -+You need to adjust the following schema to match the database dialect you use: - -+==== - [source] - ---- -- - create table groups ( - id bigint generated by default as identity(start with 0) primary key, - group_name varchar_ignorecase(50) not null -@@ -72,16 +77,18 @@ create table group_members ( - constraint fk_group_members_group foreign key(group_id) references groups(id) - ); - ---- -+==== - --Remember that these tables are only required if you are using the provided JDBC `UserDetailsService` implementation. --If you write your own or choose to implement `AuthenticationProvider` without a `UserDetailsService`, then you have complete freedom over how you store the data, as long as the interface contract is satisfied. -+Remember that these tables are required only if you us the provided JDBC `UserDetailsService` implementation. -+If you write your own or choose to implement `AuthenticationProvider` without a `UserDetailsService`, you have complete freedom over how you store the data, as long as the interface contract is satisfied. - - - == Persistent Login (Remember-Me) Schema --This table is used to store data used by the more secure <> remember-me implementation. --If you are using `JdbcTokenRepositoryImpl` either directly or through the namespace, then you will need this table. --Remember to adjust this schema to match the database dialect you are using. -+This table is used to store the data used by the more secure <> remember-me implementation. -+If you use `JdbcTokenRepositoryImpl` either directly or through the namespace, you need this table. -+Remember to adjust this schema to match the database dialect you use: - -+==== - [source] - ---- - -@@ -93,21 +100,22 @@ create table persistent_logins ( - ); - - ---- -+==== - - [[dbschema-acl]] - == ACL Schema --There are four tables used by the Spring Security <> implementation. -+The Spring Security <> implementation uses four tables. - --. `acl_sid` stores the security identities recognised by the ACL system. --These can be unique principals or authorities which may apply to multiple principals. --. `acl_class` defines the domain object types to which ACLs apply. -+* `acl_sid` stores the security identities recognised by the ACL system. -+These can be unique principals or authorities, which may apply to multiple principals. -+* `acl_class` defines the domain object types to which ACLs apply. - The `class` column stores the Java class name of the object. --. `acl_object_identity` stores the object identity definitions of specific domain objects. --. `acl_entry` stores the ACL permissions which apply to a specific object identity and security identity. -+* `acl_object_identity` stores the object identity definitions of specific domain objects. -+* `acl_entry` stores the ACL permissions, each of which applies to a specific object identity and security identity. - --It is assumed that the database will auto-generate the primary keys for each of the identities. -+We assume that the database auto-generates the primary keys for each of the identities. - The `JdbcMutableAclService` has to be able to retrieve these when it has created a new row in the `acl_sid` or `acl_class` tables. --It has two properties which define the SQL needed to retrieve these values `classIdentityQuery` and `sidIdentityQuery`. -+It has two properties that define the SQL needed to retrieve these values `classIdentityQuery` and `sidIdentityQuery`. - Both of these default to `call identity()` - - The ACL artifact JAR contains files for creating the ACL schema in HyperSQL (HSQLDB), PostgreSQL, MySQL/MariaDB, Microsoft SQL Server, and Oracle Database. -@@ -116,9 +124,9 @@ These schemas are also demonstrated in the following sections. - === HyperSQL - The default schema works with the embedded HSQLDB database that is used in unit tests within the framework. - -+==== - [source,ddl] - ---- -- - create table acl_sid( - id bigint generated by default as identity(start with 100) not null primary key, - principal boolean not null, -@@ -159,8 +167,16 @@ create table acl_entry( - constraint foreign_fk_5 foreign key(sid) references acl_sid(id) - ); - ---- -+==== - - === PostgreSQL -+ -+For PostgreSQL, you have to set the `classIdentityQuery` and `sidIdentityQuery` properties of `JdbcMutableAclService` to the following values, respectively: -+ -+* `select currval(pg_get_serial_sequence('acl_class', 'id'))` -+* `select currval(pg_get_serial_sequence('acl_sid', 'id'))` -+ -+==== - [source,ddl] - ---- - create table acl_sid( -@@ -203,13 +219,11 @@ create table acl_entry( - constraint foreign_fk_5 foreign key(sid) references acl_sid(id) - ); - ---- -- --You will have to set the `classIdentityQuery` and `sidIdentityQuery` properties of `JdbcMutableAclService` to the following values, respectively: -- --* `select currval(pg_get_serial_sequence('acl_class', 'id'))` --* `select currval(pg_get_serial_sequence('acl_sid', 'id'))` -+==== - - === MySQL and MariaDB -+ -+==== - [source,ddl] - ---- - CREATE TABLE acl_sid ( -@@ -252,8 +266,11 @@ CREATE TABLE acl_entry ( - CONSTRAINT fk_acl_entry_acl FOREIGN KEY (sid) REFERENCES acl_sid (id) - ) ENGINE=InnoDB; - ---- -+==== - - === Microsoft SQL Server -+ -+==== - [source,ddl] - ---- - CREATE TABLE acl_sid ( -@@ -296,8 +313,10 @@ CREATE TABLE acl_entry ( - CONSTRAINT fk_acl_entry_acl FOREIGN KEY (sid) REFERENCES acl_sid (id) - ); - ---- -- -+==== - === Oracle Database -+ -+==== - [source,ddl] - ---- - CREATE TABLE ACL_SID ( -@@ -363,13 +382,14 @@ BEGIN - SELECT ACL_ENTRY_SQ.NEXTVAL INTO :NEW.ID FROM DUAL; - END; - ---- -- -+==== - - [[dbschema-oauth2-client]] - == OAuth 2.0 Client Schema --The JDBC implementation of <> (`JdbcOAuth2AuthorizedClientService`) requires a table for persisting `OAuth2AuthorizedClient`(s). --You will need to adjust this schema to match the database dialect you are using. -+The JDBC implementation of <> (`JdbcOAuth2AuthorizedClientService`) requires a table for persisting `OAuth2AuthorizedClient` instances. -+You need to adjust this schema to match the database dialect you use. - -+==== - [source,ddl] - ---- - CREATE TABLE oauth2_authorized_client ( -@@ -386,3 +406,4 @@ CREATE TABLE oauth2_authorized_client ( - PRIMARY KEY (client_registration_id, principal_name) - ); - ---- -+==== -diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/appendix/faq.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/appendix/faq.adoc -index 196c3992fe..e3481e3ab0 100644 ---- a/docs/manual/src/docs/asciidoc/_includes/servlet/appendix/faq.adoc -+++ b/docs/manual/src/docs/asciidoc/_includes/servlet/appendix/faq.adoc -@@ -1,6 +1,8 @@ - [[appendix-faq]] - == Spring Security FAQ - -+This FAQ has the following sections: -+ - * <> - * <> - * <> -@@ -9,57 +11,59 @@ - [[appendix-faq-general-questions]] - === General Questions - --. <> --. <> --. <> --. <> -+This FAQ answers the following general questions: -+ -+* <> -+* <> -+* <> -+* <> - - - [[appendix-faq-other-concerns]] --==== Will Spring Security take care of all my application security requirements? -+==== Can 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. --Check out the https://www.owasp.org/[OWASP web site] for information on the major issues facing web application developers and the countermeasures you can use against them. -+Spring Security provides you with a 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 with which you should be familiar, preferably before you start development so that you can design and code with them in mind from the beginning. -+Check out the https://www.owasp.org/[OWASP web site] for information on the major issues that face web application developers and the countermeasures you can use against them. - - - [[appendix-faq-web-xml]] --==== Why not just use web.xml security? -+==== Why Not 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: -+Suppose you are developing an enterprise application based on Spring. -+You typically need to address four security concerns : authentication, web request security, service layer security (your methods that implement business logic), and domain object instance security (different domain objects can have different permissions). With these typical requirements in mind, we have the following considerations: - --. __Authentication__: The servlet specification provides an approach to authentication. --However, you will need to configure the container to perform authentication which typically requires editing of container-specific "realm" settings. --This makes a non-portable configuration, and if you need to write an actual Java class to implement the container's authentication interface, it becomes even more non-portable. --With Spring Security you achieve complete portability - right down to the WAR level. -+* _Authentication_: The servlet specification provides an approach to authentication. -+However, you need to configure the container to perform authentication, which typically requires editing of container-specific "`realm`" settings. -+This makes a non-portable configuration. Also, if you need to write an actual Java class to implement the container's authentication interface, it becomes even more non-portable. -+With Spring Security, you achieve complete portability -- right down to the WAR level. - Also, Spring Security offers a choice of production-proven authentication providers and mechanisms, meaning you can switch your authentication approaches at deployment time. - This is particularly valuable for software vendors writing products that need to work in an unknown target environment. - --. __Web request security:__ The servlet specification provides an approach to secure your request URIs. --However, these URIs can only be expressed in the servlet specification's own limited URI path format. -+* _Web request security:_ The servlet specification provides an approach to secure your request URIs. -+However, these URIs can be expressed only in the servlet specification's own limited URI path format. - Spring Security provides a far more comprehensive approach. --For instance, you can use Ant paths or regular expressions, you can consider parts of the URI other than simply the requested page (e.g. --you can consider HTTP GET parameters) and you can implement your own runtime source of configuration data. --This means your web request security can be dynamically changed during the actual execution of your webapp. -+For instance, you can use Ant paths or regular expressions, you can consider parts of the URI other than simply the requested page (for example, -+you can consider HTTP GET parameters), and you can implement your own runtime source of configuration data. -+This means that you can dynamically change your web request security during the actual execution of your web application. - --. __Service layer and domain object security:__ The absence of support in the servlet specification for services layer security or domain object instance security represent serious limitations for multi-tiered applications. --Typically developers either ignore these requirements, or implement security logic within their MVC controller code (or even worse, inside the views). There are serious disadvantages with this approach: -+* _Service layer and domain object security:_ The absence of support in the servlet specification for services layer security or domain object instance security represents serious limitations for multi-tiered applications. -+Typically, developers either ignore these requirements or implement security logic within their MVC controller code (or, even worse, inside the views). There are serious disadvantages with this approach: - --.. __Separation of concerns:__ Authorization is a crosscutting concern and should be implemented as such. --MVC controllers or views implementing authorization code makes it more difficult to test both the controller and authorization logic, more difficult to debug, and will often lead to code duplication. -+** _Separation of concerns:_ Authorization is a crosscutting concern and should be implemented as such. -+MVC controllers or views that implement authorization code makes it more difficult to test both the controller and the authorization logic, is more difficult to debug, and often leads to code duplication. - --.. __Support for rich clients and web services:__ If an additional client type must ultimately be supported, any authorization code embedded within the web layer is non-reusable. --It should be considered that Spring remoting exporters only export service layer beans (not MVC controllers). As such authorization logic needs to be located in the services layer to support a multitude of client types. -+** _Support for rich clients and web services:_ If an additional client type must ultimately be supported, any authorization code embedded within the web layer is non-reusable. -+It should be considered that Spring remoting exporters export only service layer beans (not MVC controllers). As a result, authorization logic needs to be located in the services layer to support a multitude of client types. - --.. __Layering issues:__ An MVC controller or view is simply the incorrect architectural layer to implement authorization decisions concerning services layer methods or domain object instances. --Whilst the Principal may be passed to the services layer to enable it to make the authorization decision, doing so would introduce an additional argument on every services layer method. --A more elegant approach is to use a ThreadLocal to hold the Principal, although this would likely increase development time to a point where it would become more economical (on a cost-benefit basis) to simply use a dedicated security framework. -+** _Layering issues:_ An MVC controller or view is the incorrect architectural layer in which to implement authorization decisions concerning services layer methods or domain object instances. -+While the principal may be passed to the services layer to enable it to make the authorization decision, doing so would introduce an additional argument on every services layer method. -+A more elegant approach is to use a `ThreadLocal` to hold the principal, although this would likely increase development time to a point where it would become more economical (on a cost-benefit basis) to use a dedicated security framework. - --.. __Authorisation code quality:__ It is often said of web frameworks that they "make it easier to do the right things, and harder to do the wrong things". Security frameworks are the same, because they are designed in an abstract manner for a wide range of purposes. --Writing your own authorization code from scratch does not provide the "design check" a framework would offer, and in-house authorization code will typically lack the improvements that emerge from widespread deployment, peer review and new versions. -+** _Authorisation code quality:_ It is often said of web frameworks that they "`make it easier to do the right things, and harder to do the wrong things`". Security frameworks are the same, because they are designed in an abstract manner for a wide range of purposes. -+Writing your own authorization code from scratch does not provide the "`design check`" a framework would offer, and in-house authorization code typically lacks the improvements that emerge from widespread deployment, peer review, and new versions. - --For simple applications, servlet specification security may just be enough. -+For simple applications, servlet specification security may be enough. - Although when considered within the context of web container portability, configuration requirements, limited web request security flexibility, and non-existent services layer and domain object instance security, it becomes clear why developers often look to alternative solutions. - - -@@ -67,138 +71,141 @@ Although when considered within the context of web container portability, config - ==== 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. -+Ideally, you should use the latest release versions to avoid problems. - - Spring Security 2.0.x requires a minimum JDK version of 1.4 and is built against Spring 2.0.x. --It should also be compatible with applications using Spring 2.5.x. -+It should also be compatible with applications that use 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. --What could be wrong? -+==== I have a complex scenario. What could be wrong? -+ -+(This answer address complex scenarios in general by dealing with a particular scenario.) - --Or substitute an alternative complex scenario... -+Suppose you are new to Spring Security and 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). You have copied some configuration files but have found that it does not work. What could be wrong? - --Realistically, you need an understanding of the technologies you are intending to use before you can successfully build applications with them. -+You need an understanding of the technologies you intend to use before you can successfully build applications with them. - Security is complicated. --Setting up a simple configuration using a login form and some hard-coded users using Spring Security's namespace is reasonably straightforward. -+Setting up a simple configuration by using a login form and some hard-coded users with Spring Security's namespace is reasonably straightforward. - Moving to using a backed JDBC database is also easy enough. --But if you try and jump straight to a complicated deployment scenario like this you will almost certainly be frustrated. --There is a big jump in the learning curve required to set up systems like CAS, configure LDAP servers and install SSL certificates properly. -+However, if you try to jump straight to a complicated deployment scenario like this scenario, you are almost certain to be frustrated. -+There is a big jump in the learning curve required to set up systems such as CAS, configure LDAP servers, and install SSL certificates properly. - So you need to take things one step at a time. - --From a Spring Security perspective, the first thing you should do is follow the "Getting Started" guide on the web site. -+From a Spring Security perspective, the first thing you should do is follow the "`Getting Started`" guide on the web site. - This will take you through a series of steps to get up and running and get some idea of how the framework operates. --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. -+If you use other technologies with which you are not familiar, 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 - --. Authentication --.. <> --.. <> --.. <> --.. <> --.. <> --.. <> --. Session Management --.. <> --.. <> --.. <> --.. <> --.. <> --. Miscellaneous --.. <> --.. <> --.. <> --.. <> --.. <> -+This section addresses the most common problems that people encounter when using Spring Security: -+ -+* Authentication -+** <> -+** <> -+** <> -+** <> -+** <> -+** <> -+* Session Management -+** <> -+** <> -+** <> -+** <> -+** <> -+* Miscellaneous -+** <> -+** <> -+** <> -+** <> -+** <> - - [[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 is 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. -+It does not say why, as it is good practice to avoid giving details that might help an attacker guess account names or passwords. - --This also means that if you ask this question in the forum, you will not get an answer unless you provide additional information. --As with any issue you should check the output from the debug log, note any exception stacktraces and related messages. --Step through the code in a debugger to see where the authentication fails and why. --Write a test case which exercises your authentication configuration outside of the application. -+This also means that, if you ask this question online, you should not expect an answer unless you provide additional information. -+As with any issue, you should check the output from the debug log and note any exception stacktraces and related messages. -+You should step through the code in a debugger to see where the authentication fails and why. -+You should also write a test case which exercises your authentication configuration outside of the application. - More often than not, the failure is due to a difference in the password data stored in a database and that entered by the user. --If you are using hashed passwords, make sure the value stored in your database is __exactly__ the same as the value produced by the `PasswordEncoder` configured in your application. -+If you use hashed passwords, make sure the value stored in your database is _exactly_ the same as the value produced by the `PasswordEncoder` configured in your application. - - - [[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 is 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. -+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`. - --If your AccessDecisionManager includes an AuthenticatedVoter, you can use the attribute "IS_AUTHENTICATED_ANONYMOUSLY". This is automatically available if you are using the standard namespace configuration setup. -+If your `AccessDecisionManager` includes an `AuthenticatedVoter`, you can use the `IS_AUTHENTICATED_ANONYMOUSLY` attribute. This is automatically available if you use the standard namespace configuration setup. - --From Spring Security 2.0.1 onwards, when you are using namespace-based configuration, a check will be made on loading the application context and a warning message logged if your login page appears to be protected. -+From Spring Security 2.0.1 onwards, when you use namespace-based configuration, a check is made on loading the application context and a warning message logged if your login page appears to be protected. - - - [[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 a message of "Access is denied (user is anonymous);". What is wrong? - --This is a debug level message which occurs the first time an anonymous user attempts to access a protected resource. -+The following listing shows a debug level message that occurs the first time an anonymous user attempts to access a protected resource: - -+==== - [source] - ---- -- - DEBUG [ExceptionTranslationFilter] - Access is denied (user is anonymous); redirecting to authentication entry point - org.springframework.security.AccessDeniedException: Access is denied - at org.springframework.security.vote.AffirmativeBased.decide(AffirmativeBased.java:68) - at org.springframework.security.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:262) -- - ---- -+==== - --It is normal and shouldn't be anything to worry about. -+It is normal and is not something 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 have 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. -+The most common reason for this is that your browser has cached the page and you are seeing a copy that is being retrieved from the browsers cache. -+Verify this by checking whether the browser is actually sending the request (check your server access logs and 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. - 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 a message of "An Authentication object was not found in the SecurityContext". What is 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. -+The following listing shows another debug-level message that occurs the first time an anonymous user attempts to access a protected resource. However, this listing shows what happens when you do not have an `AnonymousAuthenticationFilter` in your filter chain configuration: - -+==== - [source] - ---- -- - DEBUG [ExceptionTranslationFilter] - Authentication exception occurred; redirecting to authentication entry point - org.springframework.security.AuthenticationCredentialsNotFoundException: - An Authentication object was not found in the SecurityContext - at org.springframework.security.intercept.AbstractSecurityInterceptor.credentialsNotFound(AbstractSecurityInterceptor.java:342) - at org.springframework.security.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:254) - ---- -+==== - --It is normal and shouldn't be anything to worry about. -+It is normal and is not something to worry about. - - - [[appendix-faq-ldap-authentication]] --==== I can't get LDAP authentication to work. --What's wrong with my configuration? -+==== I cannot get LDAP authentication to work. What is wrong with my configuration? - --Note that the permissions for an LDAP directory often do not allow you to read the password for a user. --Hence it is often not possible to use the <> where Spring Security compares the stored password with the one submitted by the user. --The most common approach is to use LDAP "bind", which is one of the operations supported by https://en.wikipedia.org/wiki/Lightweight_Directory_Access_Protocol[the LDAP protocol]. With this approach, Spring Security validates the password by attempting to authenticate to the directory as the user. -+Note that the permissions for an LDAP directory often do not let you read the password for a user. -+Hence, it is often not possible to use the <> where Spring Security compares the stored password with the one submitted by the user. -+The most common approach is to use LDAP "`bind`", which is one of the operations supported by https://en.wikipedia.org/wiki/Lightweight_Directory_Access_Protocol[the LDAP protocol]. With this approach, Spring Security validates the password by trying to authenticate to the directory as the user. - - The most common problem with LDAP authentication is a lack of knowledge of the directory server tree structure and configuration. --This will be different in different companies, so you have to find it out yourself. --Before adding a Spring Security LDAP configuration to an application, it's a good idea to write a simple test using standard Java LDAP code (without Spring Security involved), and make sure you can get that to work first. -+This differs from one company to another, so you have to find it out yourself. -+Before adding a Spring Security LDAP configuration to an application, you should write a simple test by using standard Java LDAP code (without Spring Security involved) and make sure you can get that to work first. - For example, to authenticate a user, you could use the following code: - -+==== - [source,java] - ---- -- - @Test - public void ldapAuthenticationIsSuccessful() throws Exception { - Hashtable env = new Hashtable(); -@@ -211,125 +218,126 @@ public void ldapAuthenticationIsSuccessful() throws Exception { - InitialLdapContext ctx = new InitialLdapContext(env, null); - - } -- - ---- -+==== - - ==== Session Management - --Session management issues are a common source of forum questions. -+Session management issues are a common source of 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. --You should also understand the difference between secure and non-secure cookies and the implications of using HTTP/HTTPS and switching between the two. -+You should also understand the difference between secure and non-secure cookies and the implications of using HTTP and HTTPS and switching between the two. - Spring Security has nothing to do with maintaining the session or providing session identifiers. - 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. --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? -+==== I am using Spring Security's concurrent session control to prevent users from logging in more than once at the same time. When I open another browser window after logging in, it does not stop me from logging in again. Why can I log in more than once? - - Browsers generally maintain a single session per browser instance. - You cannot have two separate sessions at once. --So if you log in again in another window or tab you are just reauthenticating in the same session. --The server doesn't know anything about tabs, windows or browser instances. --All it sees are HTTP requests and it ties those to a particular session according to the value of the JSESSIONID cookie that they contain. --When a user authenticates during a session, Spring Security's concurrent session control checks the number of __other authenticated sessions__ that they have. --If they are already authenticated with the same session, then re-authenticating will have no effect. -+So, if you log in again in another window or tab, you are reauthenticating in the same session. -+The server does not know anything about tabs, windows, or browser instances. -+All it sees are HTTP requests, and it ties those to a particular session according to the value of the `JSESSIONID` cookie that they contain. -+When a user authenticates during a session, Spring Security's concurrent session control checks the number of _other authenticated sessions_ that they have. -+If they are already authenticated with the same session, re-authenticating has no effect. - - - [[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. --If you're using an older container, Spring Security invalidates the existing session, creates a new session, and transfers the session data to the new session. --Changing the session identifier in this manner prevents"session-fixation" attacks. -+If you us a Servlet 3.1 or newer container, the session ID is simply changed. -+If you use an older container, Spring Security invalidates the existing session, creates a new session, and transfers the session data to the new session. -+Changing the session identifier in this manner prevents "`session-fixation`" attacks. - 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. --It doesn't work - I just end up back at the login page after authenticating. -+==== I use Tomcat (or some other servlet container) and have enabled HTTPS for my login page, switching back to HTTP afterwards. It does not work. I 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. -+This happens because sessions created under HTTPS, for which the session cookie is marked as "`secure`", cannot subsequently be used under HTTP. The browser does not send the cookie back to the server, and any session state (including the security context information) is lost. Starting a session in HTTP first should work, as the session cookie is not marked as secure. - However, Spring Security's https://docs.spring.io/spring-security/site/docs/3.1.x/reference/springsecurity-single.html#ns-session-fixation[Session Fixation Protection] can interfere with this because it results in a new session ID cookie being sent back to the user's browser, usually with the secure flag. --To get around this, you can disable session fixation protection, but in newer Servlet containers you can also configure session cookies to never use the secure flag. --Note that switching between HTTP and HTTPS is not a good idea in general, as any application which uses HTTP at all is vulnerable to man-in-the-middle attacks. -+To get around this, you can disable session fixation protection. However, in newer Servlet containers, you can also configure session cookies to never use the secure flag. -+ -+IMPORTANT: Switching between HTTP and HTTPS is not a good idea in general, as any application that uses HTTP at all is vulnerable to man-in-the-middle attacks. - To be truly secure, the user should begin accessing your site in HTTPS and continue using it until they log out. - Even clicking on an HTTPS link from a page accessed over HTTP is potentially risky. --If you need more convincing, check out a tool like https://www.thoughtcrime.org/software/sslstrip/[sslstrip]. -+If you need more convincing, check out a tool such as https://www.thoughtcrime.org/software/sslstrip/[sslstrip]. - - --==== I'm not switching between HTTP and HTTPS but my session is still getting lost -+==== I am not switching between HTTP and HTTPS, but my session is still lost. What happened? - --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. -+Sessions are maintained either by exchanging a session cookie or by adding a `jsessionid` parameter to URLs (this happens automatically if you use 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`, the session is 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 am trying to use the concurrent session-control support, but it does not let me log back in, even if I am sure I have logged out and have not exceeded the allowed sessions. What is wrong? - --Make sure you have added the listener to your web.xml file. -+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. --Without it, the session information will not be removed from the registry. -- -+Without it, the session information is not removed from the registry. -+The following example adds a listener in a `web.xml` file: - -+==== - [source,xml] - ---- - - org.springframework.security.web.session.HttpSessionEventPublisher - - ---- -+==== - - [[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 creates a session somewhere, even though I have configured it not to, by setting the create-session attribute to never. What is wrong? - --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. --To prevent a JSP from creating a session, add the directive `<%@ page session="false" %>` to the top of the page. -+This usually means that the user's application is creating a session somewhere but that they are not aware of it. -+The most common culprit is a JSP. Many people are not aware that JSPs create sessions by default. -+To prevent a JSP from creating a session, add the `<%@ page session="false" %>` directive to the top of the page. - --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. -+If you have 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 is to add a `javax.servlet.http.HttpSessionListener`, which calls `Thread.dumpStack()` in the `sessionCreated` method, to your application. - - [[appendix-faq-forbidden-csrf]] --==== I get a 403 Forbidden when performing a POST -+==== I get a 403 Forbidden when performing a POST. What is wrong? - --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). -+If an HTTP 403 Forbidden error is returned for HTTP POST but it works for HTTP GET, 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 (the latter is 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 am forwarding a request to another URL by using the RequestDispatcher, but my security constraints are not 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 element, a child element of . -+By default, filters are not applied to forwards or includes. -+If you really want the security filters to be applied to forwards or includes, you have to configure these explicitly in your `web.xml` file by using the `` element, which is a child element of the `` element. - - - [[appendix-faq-method-security-in-web-context]] --==== I have added Spring Security's 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 element to my application context, but, if I add security annotations to my Spring MVC controller beans (Struts actions etc.), they do not seem to have an effect. Why not? - --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. --The beans in these "child" contexts are not visible to the rest of the application. --The"parent" application context is loaded by the `ContextLoaderListener` you define in your `web.xml` and is visible to all the child contexts. --This parent context is usually where you define your security configuration, including the `` element). As a result any security constraints applied to methods in these web beans will not be enforced, since the beans cannot be seen from the `DispatcherServlet` context. --You need to either move the `` declaration to the web context or moved the beans you want secured into the main application context. -+In a Spring web application, the application context that 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 the `web.xml` file. An application can have multiple `DispatcherServlet` instances, each with its own isolated application context. -+The beans in these "`child`" contexts are not visible to the rest of the application. -+The "`parent`" application context is loaded by the `ContextLoaderListener` you define in your `web.xml` file and is visible to all the child contexts. -+This parent context is usually where you define your security configuration, including the `` element. As a result, any security constraints applied to methods in these web beans are not enforced, since the beans cannot be seen from the `DispatcherServlet` context. -+You need to either move the `` declaration to the web context or move the beans you want secured into the main application context. - --Generally we would recommend applying method security at the service layer rather than on individual web controllers. -+Generally, we recommend applying method security at the service layer rather than on individual web controllers. - - - [[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. --Why can't I see the user information? -+==== 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 I not see the user information? - --If you have excluded the request from the security filter chain using the attribute `filters='none'` in the `` element that matches the URL pattern, then the `SecurityContextHolder` will not be populated for that request. -+If you have excluded the request from the security filter chain by using the `filters='none'` attribute in the `` element that matches the URL pattern, the `SecurityContextHolder` is not populated for that request. - Check the debug log to see whether the request is passing through the filter chain. --(You are reading the debug log, right?). -+(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 does not respect my method security annotations when using the URL attribute. Why not? - --Method security will not hide links when using the `url` attribute in `` 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. -+Method security does not hide links when using the `url` attribute in ``, because we cannot readily reverse engineer what URL is mapped to what controller endpoint. We are limited because controllers can rely on headers, the current user, and other details to determine what method to invoke. - - [[appendix-faq-architecture]] - === Spring Security Architecture Questions - -+This section addresses common Spring Security architecture questions: -+ - . <> - . <> - . <> -@@ -342,56 +350,56 @@ Method security will not hide links when using the `url` attribute in `> that lists the first-level dependencies for each Spring Security module, with some information on whether they are optional and when they are required. - --If you are building your project with maven, then adding the appropriate Spring Security modules as dependencies to your pom.xml will automatically pull in the core jars that the framework requires. --Any which are marked as "optional" in the Spring Security POM files will have to be added to your own pom.xml file if you need them. -+If you build your project with Maven, adding the appropriate Spring Security modules as dependencies to your `pom.xml` file automatically pulls in the core jars that the framework requires. -+Any that are marked as "`optional`" in the Spring Security `pom.xml` files have to be added to your own `pom.xml` file if you need them. - - - [[appendix-faq-apacheds-deps]] - ==== 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: -+If you use Maven, you need to add the following to your `pom.xml` file dependencies: - -+==== - [source] - ---- -- - - org.apache.directory.server - apacheds-core -@@ -404,8 +412,8 @@ If you are using Maven, you need to add the following to your pom dependencies: - 1.5.5 - runtime - -- - ---- -+==== - - The other required jars should be pulled in transitively. - -@@ -413,16 +421,18 @@ The other required jars should be pulled in transitively. - ==== 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. -+It has no function other than to load that data for use by other components within the framework. - It is not responsible for authenticating the user. --Authenticating a user with a username/password combination is most commonly performed by the `DaoAuthenticationProvider`, which is injected with a `UserDetailsService` to allow it to load the password (and other data) for a user in order to compare it with the submitted value. --Note that if you are using LDAP, <>. -+Authenticating a user with a username and password combination is most commonly performed by the `DaoAuthenticationProvider`, which is injected with a `UserDetailsService` to let it to load the password (and other data) for a user, to compare it with the submitted value. -+Note that, if you use LDAP, <>. - --If you want to customize the authentication process then you should implement `AuthenticationProvider` yourself. --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. -+If you want to customize the authentication process, you should implement `AuthenticationProvider` yourself. -+See this https://spring.io/blog/2010/08/02/spring-security-in-google-app-engine/[ blog article] for an example that integrate Spring Security authentication with Google App Engine. - - [[appendix-faq-howto]] --=== Common "Howto" Requests -+=== Common "How to" Questions -+ -+This section addresses the most common "How to" (or "How do I") questions about Spring Security: - - . <> - . <> -@@ -435,72 +445,70 @@ 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. --How do I add support for extra login fields (e.g. --a company name)? -+==== I need to login in with more information than just the username. How do I add support for extra login fields (such as a company name)? - --This question comes up repeatedly in the Spring Security forum so you will find more information there by searching the archives (or through google). -+This question comes up repeatedly, so you can find more information by searching online. - --The submitted login information is processed by an instance of `UsernamePasswordAuthenticationFilter`. You will need to customize this class to handle the extra data field(s). One option is to use your own customized authentication token class (rather than the standard `UsernamePasswordAuthenticationToken`), another is simply to concatenate the extra fields with the username (for example, using a ":" as the separator) and pass them in the username property of `UsernamePasswordAuthenticationToken`. -+The submitted login information is processed by an instance of `UsernamePasswordAuthenticationFilter`. You need to customize this class to handle the extra data fields. One option is to use your own customized authentication token class (rather than the standard `UsernamePasswordAuthenticationToken`). Another option is to concatenate the extra fields with the username (for example, by using a `:` character as the separator) and pass them in the username property of `UsernamePasswordAuthenticationToken`. - --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. -+You also need to customize the actual authentication process. -+If you use a custom authentication token class, for example, you will have to write an `AuthenticationProvider` (or extend the standard `DaoAuthenticationProvider`) to handle it. If you have concatenated the fields, you can implement your own `UserDetailsService` to split them up and load 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 (such as /thing1#thing2 and /thing1#thing3? - --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. -+You cannot do this, since the fragment is not transmitted from the browser to the server. -+From the server's perspective, the URLs are identical. - 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? - --Obviously you can't (without resorting to something like thread-local variables) since the only information supplied to the interface is the username. -+You cannot (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. - --In a standard web setup, the `getDetails()` method on the `Authentication` object will return an instance of `WebAuthenticationDetails`. If you need additional information, you can inject a custom `AuthenticationDetailsSource` into the authentication filter you are using. --If you are using the namespace, for example with the `` element, then you should remove this element and replace it with a `` declaration pointing to an explicitly configured `UsernamePasswordAuthenticationFilter`. -+In a standard web setup, the `getDetails()` method on the `Authentication` object returns an instance of `WebAuthenticationDetails`. If you need additional information, you can inject a custom `AuthenticationDetailsSource` into the authentication filter you are using. -+If you use the namespace, for example with the `` element, you should remove this element and replace it with a `` declaration that points to an explicitly configured `UsernamePasswordAuthenticationFilter`. - - - [[appendix-faq-access-session-from-user-service]] - ==== 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. -+You cannot, since the `UserDetailsService` has no awareness of the servlet API. If you want to store custom user data, you should customize the `UserDetails` object that is returned. -+This can then be accessed at any point, through the thread-local `SecurityContextHolder`. A call to `SecurityContextHolder.getContext().getAuthentication().getPrincipal()` returns this custom object. - --If you really need to access the session, then it must be done by customizing the web tier. -+If you really need to access the session, you must do so by by customizing the web tier. - - - [[appendix-faq-password-in-user-service]] - ==== How do I access the user's password in a UserDetailsService? - --You can't (and shouldn't). You are probably misunderstanding its purpose. --See "<>" above. -+You cannot (and should not, even if you find a way to do so). You are probably misunderstanding its purpose. -+See "<>", earlier in the FAQ. - - - [[appendix-faq-dynamic-url-metadata]] --==== How do I define the secured URLs within an application dynamically? -+==== How do I dynamically define the secured URLs within an application? - --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. -+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. - - The first thing you should ask yourself is if you really need to do this. --If an application requires securing, then it also requires that the security be tested thoroughly based on a defined policy. -+If an application needs to be secure, it also requires that the security be tested thoroughly based on a defined policy. - It may require auditing and acceptance testing before being rolled out into a production environment. --A security-conscious organization should be aware that the benefits of their diligent testing process could be wiped out instantly by allowing the security settings to be modified at runtime by changing a row or two in a configuration database. --If you have taken this into account (perhaps using multiple layers of security within your application) then Spring Security allows you to fully customize the source of security metadata. -+A security-conscious organization should be aware that the benefits of their diligent testing process could be wiped out instantly by letting the security settings be modified at runtime by changing a row or two in a configuration database. -+If you have taken this into account (perhaps by using multiple layers of security within your application), Spring Security lets you fully customize the source of security metadata. - You can make it fully dynamic if you choose. - --Both method and web security are protected by subclasses of `AbstractSecurityInterceptor` which is configured with a `SecurityMetadataSource` from which it obtains the metadata for a particular method or filter invocation. --For web security, the interceptor class is `FilterSecurityInterceptor` and it uses the marker interface `FilterInvocationSecurityMetadataSource`. The "secured object" type it operates on is a `FilterInvocation`. The default implementation which is used (both in the namespace `` and when configuring the interceptor explicitly, stores the list of URL patterns and their corresponding list of "configuration attributes" (instances of `ConfigAttribute`) in an in-memory map. -+Both method and web security are protected by subclasses of `AbstractSecurityInterceptor`, which is configured with a `SecurityMetadataSource` from which it obtains the metadata for a particular method or filter invocation. -+For web security, the interceptor class is `FilterSecurityInterceptor`, and it uses the `FilterInvocationSecurityMetadataSource` marker interface. The "`secured object`" type it operates on is a `FilterInvocation`. The default implementation (which is used both in the namespace `` and when configuring the interceptor explicitly) stores the list of URL patterns and their corresponding list of "`configuration attributes`" (instances of `ConfigAttribute`) in an in-memory map. - --To load the data from an alternative source, you must be using an explicitly declared security filter chain (typically Spring Security's `FilterChainProxy`) in order to customize the `FilterSecurityInterceptor` bean. --You can't use the namespace. --You would then implement `FilterInvocationSecurityMetadataSource` to load the data as you please for a particular `FilterInvocation` footnote:[The `FilterInvocation` object contains the `HttpServletRequest`, so you can obtain the URL or any other relevant information on which to base your decision on what the list of returned attributes will contain.]. A very basic outline would look something like this: -+To load the data from an alternative source, you must use an explicitly declared security filter chain (typically Spring Security's `FilterChainProxy`) to customize the `FilterSecurityInterceptor` bean. -+You cannot use the namespace. -+You would then implement `FilterInvocationSecurityMetadataSource` to load the data as you please for a particular `FilterInvocation`. The `FilterInvocation` object contains the `HttpServletRequest`, so you can obtain the URL or any other relevant information on which to base your decision, based on what the list of returned attributes contains. A basic outline would look something like the following example: - -+==== - [source,java] - ---- -- - public class MyFilterSecurityMetadataSource implements FilterInvocationSecurityMetadataSource { - - public List getAttributes(Object object) { -@@ -523,8 +531,8 @@ You would then implement `FilterInvocationSecurityMetadataSource` to load the da - return FilterInvocation.class.isAssignableFrom(clazz); - } - } -- - ---- -+==== - - For more information, look at the code for `DefaultFilterInvocationSecurityMetadataSource`. - -@@ -532,54 +540,53 @@ 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? - --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. -+The `LdapAuthenticationProvider` bean (which handles normal LDAP authentication in Spring Security) is configured with two separate strategy interfaces, one that performs the authentication and one that 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 let you specify how these should be retrieved. - --To use JDBC instead, you can implement the interface yourself, using whatever SQL is appropriate for your schema: -+To use JDBC instead, you can implement the interface yourself, by using whatever SQL is appropriate for your schema: - -+==== - [source,java] - ---- -- -- public class MyAuthoritiesPopulator implements LdapAuthoritiesPopulator { -- @Autowired -- JdbcTemplate template; -- -- List getGrantedAuthorities(DirContextOperations userData, String username) { -- List = template.query("select role from roles where username = ?", -- new String[] {username}, -- new RowMapper() { -- /** -- * We're assuming here that you're using the standard convention of using the role -- * prefix "ROLE_" to mark attributes which are supported by Spring Security's RoleVoter. -- */ -- public GrantedAuthority mapRow(ResultSet rs, int rowNum) throws SQLException { -- return new SimpleGrantedAuthority("ROLE_" + rs.getString(1); -- } -- } -- } -- } -- -+public class MyAuthoritiesPopulator implements LdapAuthoritiesPopulator { -+ @Autowired -+ JdbcTemplate template; -+ -+ List getGrantedAuthorities(DirContextOperations userData, String username) { -+ List = template.query("select role from roles where username = ?", -+ new String[] {username}, -+ new RowMapper() { -+ /** -+ * We assume here that you use the standard convention of using the role -+ * prefix (`ROLE_`) to mark attributes that are supported by Spring Security's RoleVoter. -+ */ -+ public GrantedAuthority mapRow(ResultSet rs, int rowNum) throws SQLException { -+ return new SimpleGrantedAuthority("ROLE_" + rs.getString(1); -+ } -+ }); -+ } -+} - ---- -+==== - --You would then add a bean of this type to your application context and inject it into the `LdapAuthenticationProvider`. This is covered in the section on configuring LDAP using explicit Spring beans in the LDAP chapter of the reference manual. --Note that you can't use the namespace for configuration in this case. --You should also consult the Javadoc for the relevant classes and interfaces. -+You would then add a bean of this type to your application context and inject it into the `LdapAuthenticationProvider`. This is covered in the section on configuring LDAP by using explicit Spring beans in the LDAP chapter of the reference manual. -+Note that you cannot use the namespace for configuration in this case. -+You should also consult the security-api-url[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. --What can I do short of abandoning namespace use? -+==== 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. --If you want to do something simple, like modify a bean, or inject a different dependency, you can do this by adding a `BeanPostProcessor` to your configuration. --More information can be found in the https://docs.spring.io/spring/docs/3.0.x/spring-framework-reference/htmlsingle/spring-framework-reference.html#beans-factory-extension-bpp[Spring Reference Manual]. In order to do this, you need to know a bit about which beans are created, so you should also read the blog article in the above question on <>. -+The namespace functionality is intentionally limited, so it does not cover everything that you can do with plain beans. -+If you want to do something simple, such as modifying a bean or injecting a different dependency, you can do so by adding a `BeanPostProcessor` to your configuration. -+You can find more information in the https://docs.spring.io/spring/docs/3.0.x/spring-framework-reference/htmlsingle/spring-framework-reference.html#beans-factory-extension-bpp[Spring Reference Manual]. To do so, you need to know a bit about which beans are created, so you should also read the blog article mentioned in the earlier question on <>. - --Normally, you would add the functionality you require to the `postProcessBeforeInitialization` method of `BeanPostProcessor`. Let's say that you want to customize the `AuthenticationDetailsSource` used by the `UsernamePasswordAuthenticationFilter`, (created by the `form-login` element). You want to extract a particular header called `CUSTOM_HEADER` from the request and make use of it while authenticating the user. --The processor class would look like this: -+Normally, you would add the functionality you require to the `postProcessBeforeInitialization` method of `BeanPostProcessor`. Suppose that you want to customize the `AuthenticationDetailsSource` used by the `UsernamePasswordAuthenticationFilter` (created by the `form-login` element). You want to extract a particular header called `CUSTOM_HEADER` from the request and use it while authenticating the user. -+The processor class would look like the following listing: - -+==== - [source,java] - ---- -- - public class BeanPostProcessor implements BeanPostProcessor { - - public Object postProcessAfterInitialization(Object bean, String name) { -@@ -599,8 +606,8 @@ public class BeanPostProcessor implements BeanPostProcessor { - return bean; - } - } -- - ---- -+==== - - You would then register this bean in your application context. --Spring will automatically invoke it on the beans defined in the application context. -+Spring automatically invoke it on the beans defined in the application context. -diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/appendix/index.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/appendix/index.adoc -index 5f01cc38d0..682e833a16 100644 ---- a/docs/manual/src/docs/asciidoc/_includes/servlet/appendix/index.adoc -+++ b/docs/manual/src/docs/asciidoc/_includes/servlet/appendix/index.adoc -@@ -1,6 +1,8 @@ - - = Appendix - -+This appendix contains additional information that may help you understand topics within the Spring Security Reference Guide. -+ - include::database-schema.adoc[leveloffset=+1] - - include::namespace.adoc[] -diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/appendix/namespace.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/appendix/namespace.adoc -index 87d802ca8e..9630a228c0 100644 ---- a/docs/manual/src/docs/asciidoc/_includes/servlet/appendix/namespace.adoc -+++ b/docs/manual/src/docs/asciidoc/_includes/servlet/appendix/namespace.adoc -@@ -9,27 +9,29 @@ If you are familiar with this format, you may wish to examine the https://raw.gi - [[nsa-web]] - === Web Application Security - -+This section deals with the XML namespace elements and attributes that deal with the security of web applications. -+ - [[nsa-debug]] - ==== - Enables Spring Security debugging infrastructure. --This will provide human-readable (multi-line) debugging information to monitor requests coming into the security filters. --This may include sensitive information, such as request parameters or headers, and should only be used in a development environment. -+This element provides human-readable (multi-line) debugging information to monitor requests that come to the security filters. -+This may include sensitive information (such as request parameters or headers) and should only be used in a development environment. - - [[nsa-http]] - ==== --If you use an `` element within your application, a `FilterChainProxy` bean named "springSecurityFilterChain" is created and the configuration within the element is used to build a filter chain within -+If you use an `` element within your application, a `FilterChainProxy` bean named `springSecurityFilterChain` is created, and the configuration within the element is used to build a filter chain within - `FilterChainProxy`. --As of Spring Security 3.1, additional `http` elements can be used to add extra filter chains footnote:[See the pass:specialcharacters,macros[<>] for how to set up the mapping from your `web.xml` ]. --Some core filters are always created in a filter chain and others will be added to the stack depending on the attributes and child elements which are present. -+As of Spring Security 3.1, you can use additional `http` elements to add extra filter chains. See the <> for how to set up the mapping from your `web.xml`. -+Some core filters are always created in a filter chain and others are added to the stack depending on the attributes and child elements that are present. - The positions of the standard filters are fixed (see - <> in the namespace introduction), removing a common source of errors with previous versions of the framework when users had to configure the filter chain explicitly in the - `FilterChainProxy` bean. --You can, of course, still do this if you need full control of the configuration. -+You can still controle the order of the filters if you need full control of the configuration. - - --All filters which require a reference to the <> will be automatically injected with the internal instance created by the namespace configuration. -+All filters that require a reference to the <> are automatically injected with the internal instance created by the namespace configuration. - --Each `` namespace block always creates an `SecurityContextPersistenceFilter`, an `ExceptionTranslationFilter` and a `FilterSecurityInterceptor`. -+Each `` namespace block always creates an `SecurityContextPersistenceFilter`, an `ExceptionTranslationFilter`, and a `FilterSecurityInterceptor`. - These are fixed and cannot be replaced with alternatives. - - -@@ -39,119 +41,126 @@ The attributes on the `` element control some of the properties on the cor - - - [[nsa-http-access-decision-manager-ref]] --* **access-decision-manager-ref** --Optional attribute specifying the ID of the `AccessDecisionManager` implementation which should be used for authorizing HTTP requests. --By default an `AffirmativeBased` implementation is used for with a `RoleVoter` and an `AuthenticatedVoter`. -+`access-decision-manager-ref`:: -+Optional attribute specifying the ID of the `AccessDecisionManager` implementation that should be used for authorizing HTTP requests. -+By default, an `AffirmativeBased` implementation is used for with a `RoleVoter` and an `AuthenticatedVoter`. - - - [[nsa-http-authentication-manager-ref]] --* **authentication-manager-ref** -+`authentication-manager-ref`:: - A reference to the `AuthenticationManager` used for the `FilterChain` created by this http element. - - - [[nsa-http-auto-config]] --* **auto-config** --Automatically registers a login form, BASIC authentication, logout services. --If set to "true", all of these capabilities are added (although you can still customize the configuration of each by providing the respective element). --If unspecified, defaults to "false". -+`auto-config`:: -+Automatically registers a login form, BASIC authentication, and logout services. -+If set to `true`, all of these capabilities are added. (You can still customize the configuration of each by providing the respective element). -+If unspecified, it defaults to `false`. - Use of this attribute is not recommended. --Use explicit configuration elements instead to avoid confusion. -+Instead, you should use explicit configuration elements to avoid confusion. - - - [[nsa-http-create-session]] --* **create-session** -+`create-session`:: - Controls the eagerness with which an HTTP session is created by Spring Security classes. - Options include: - --** `always` - Spring Security will proactively create a session if one does not exist. --** `ifRequired` - Spring Security will only create a session only if one is required (default value). --** `never` - Spring Security will never create a session, but will make use of one if the application does. --** `stateless` - Spring Security will not create a session and ignore the session for obtaining a Spring `Authentication`. -+* `always`: Spring Security proactively creates a session if one does not exist. -+* `ifRequired` (default): Spring Security creates a session only if one is required. -+* `never`: Spring Security never creates a session, but it will make use of one if the application creates one. -+* `stateless`: Spring Security does not create a session and ignores the session for obtaining a Spring `Authentication`. - - [[nsa-http-disable-url-rewriting]] --* **disable-url-rewriting** -+`disable-url-rewriting`:: - Prevents session IDs from being appended to URLs in the application. - Clients must use cookies if this attribute is set to `true`. - The default is `true`. - - - [[nsa-http-entry-point-ref]] --* **entry-point-ref** --Normally the `AuthenticationEntryPoint` used will be set depending on which authentication mechanisms have been configured. --This attribute allows this behaviour to be overridden by defining a customized `AuthenticationEntryPoint` bean which will start the authentication process. -+`entry-point-ref`:: -+Normally, which `AuthenticationEntryPoint` is used depends on which authentication mechanisms have been configured. -+This attribute lets this behavior be overridden by defining a customized `AuthenticationEntryPoint` bean, which starts the authentication process. - - - [[nsa-http-jaas-api-provision]] --* **jaas-api-provision** --If available, runs the request as the `Subject` acquired from the `JaasAuthenticationToken` which is implemented by adding a `JaasApiIntegrationFilter` bean to the stack. -+`jaas-api-provision`:: -+If available, runs the request as the `Subject` acquired from the `JaasAuthenticationToken`, which is implemented by adding a `JaasApiIntegrationFilter` bean to the stack. - Defaults to `false`. - - - [[nsa-http-name]] --* **name** --A bean identifier, used for referring to the bean elsewhere in the context. -+`name`:: -+A bean identifier used for referring to the bean elsewhere in the context. - - - [[nsa-http-once-per-request]] --* **once-per-request** -+`once-per-request`:: - Corresponds to the `observeOncePerRequest` property of `FilterSecurityInterceptor`. - Defaults to `true`. - - - [[nsa-http-pattern]] --* **pattern** --Defining a pattern for the <> element controls the requests which will be filtered through the list of filters which it defines. -+`pattern`:: -+Defines a pattern for the <> element controls the requests which are filtered through the list of filters that it defines. - The interpretation is dependent on the configured <>. --If no pattern is defined, all requests will be matched, so the most specific patterns should be declared first. -+If no pattern is defined, all requests are matched, so the most specific patterns should be declared first. - - - [[nsa-http-realm]] --* **realm** -+`realm`:: - Sets the realm name used for basic authentication (if enabled). - Corresponds to the `realmName` property on `BasicAuthenticationEntryPoint`. - - - [[nsa-http-request-matcher]] --* **request-matcher** -+`request-matcher`:: - Defines the `RequestMatcher` strategy used in the `FilterChainProxy` and the beans created by the `intercept-url` to match incoming requests. --Options are currently `mvc`, `ant`, `regex` and `ciRegex`, for Spring MVC, ant, regular-expression and case-insensitive regular-expression respectively. --A separate instance is created for each <> element using its <>, <> and <> attributes. --Ant paths are matched using an `AntPathRequestMatcher`, regular expressions are matched using a `RegexRequestMatcher` and for Spring MVC path matching the `MvcRequestMatcher` is used. -+The current options are -+ -+* `mvc`: Spring MVC -+* `ant` (default): Ant -+* `regex`: Regular expression -+* `ciRegex`: Case-insensitive regular-expression respectively. -+A separate instance is created for each <> element, by using its <>, <>, and <> attributes. -+Ant paths are matched by using an `AntPathRequestMatcher`. Regular expressions are matched by using a `RegexRequestMatcher`. For Spring MVC path matching, the `MvcRequestMatcher` is used. - See the Javadoc for these classes for more details on exactly how the matching is performed. --Ant paths are the default strategy. - - - [[nsa-http-request-matcher-ref]] --* **request-matcher-ref** --A reference to a bean that implements `RequestMatcher` that will determine if this `FilterChain` should be used. --This is a more powerful alternative to <>. -+`request-matcher-ref`:: -+A reference to a bean that implements `RequestMatcher`, which determines whenter this `FilterChain` should be used. -+This is a more powerful alternative to <>. - - - [[nsa-http-security]] --* **security** --A request pattern can be mapped to an empty filter chain, by setting this attribute to `none`. --No security will be applied and none of Spring Security's features will be available. -+`security`:: -+A request pattern can be mapped to an empty filter chain by setting this attribute to `none`. -+In that case, no security is applied and none of Spring Security's features are available. - - - [[nsa-http-security-context-repository-ref]] --* **security-context-repository-ref** -+`security-context-repository-ref`:: - Allows injection of a custom `SecurityContextRepository` into the `SecurityContextPersistenceFilter`. - - - [[nsa-http-servlet-api-provision]] --* **servlet-api-provision** --Provides versions of `HttpServletRequest` security methods such as `isUserInRole()` and `getPrincipal()` which are implemented by adding a `SecurityContextHolderAwareRequestFilter` bean to the stack. --Defaults to `true`. -+`servlet-api-provision`:: -+Provides versions of `HttpServletRequest` security methods, such as `isUserInRole()` and `getPrincipal()`, which are implemented by adding a `SecurityContextHolderAwareRequestFilter` bean to the stack. -+Default: `true`. - - - [[nsa-http-use-expressions]] --* **use-expressions** -+`use-expressions`:: - Enables EL-expressions in the `access` attribute, as described in the chapter on <>. --The default value is true. -+Default: `true`. - - - [[nsa-http-children]] - ===== Child Elements of -+ -+The `` element has the following child elements, which we describe later in this appendix: -+ - * <> - * <> - * <> -@@ -177,26 +186,26 @@ The default value is true. - - [[nsa-access-denied-handler]] - ==== --This element allows you to set the `errorPage` property for the default `AccessDeniedHandler` used by the `ExceptionTranslationFilter`, using the <> attribute, or to supply your own implementation using the<> attribute. --This is discussed in more detail in the section on the <>. -+This element lets you set the `errorPage` property for the default `AccessDeniedHandler` used by the `ExceptionTranslationFilter` (by using the <> attribute) or to supply your own implementation by using the<> attribute. -+This is discussed in more detail in the section on the <>. - - - [[nsa-access-denied-handler-parents]] - ===== Parent Elements of - --* <> -+The parent element of the `` element is <>. - - [[nsa-access-denied-handler-attributes]] - ===== Attributes - - - [[nsa-access-denied-handler-error-page]] --* **error-page** --The access denied page that an authenticated user will be redirected to if they request a page which they don't have the authority to access. -+`error-page`:: -+The access denied page to which an authenticated user is redirected if they request a page to which they do not have access. - - - [[nsa-access-denied-handler-ref]] --* **ref** -+`ref`:: - Defines a reference to a Spring bean of type `AccessDeniedHandler`. - - -@@ -207,26 +216,26 @@ If no `CorsFilter` or `CorsConfigurationSource` is specified and Spring MVC is o - - [[nsa-cors-attributes]] - ===== Attributes --The attributes on the `` element control the headers element. -+The attributes on the `` element control the headers element are: - - [[nsa-cors-ref]] --* **ref** -+`ref`:: - Optional attribute that specifies the bean name of a `CorsFilter`. - - [[nsa-cors-configuration-source-ref]] --* **cors-configuration-source-ref** -+cors-configuration-source-ref:: - Optional attribute that specifies the bean name of a `CorsConfigurationSource` to be injected into a `CorsFilter` created by the XML namespace. - - [[nsa-cors-parents]] - ===== Parent Elements of - --* <> -+The parent element of the `` element is <>. - - [[nsa-headers]] - ==== --This element allows for configuring additional (security) headers to be send with the response. --It enables easy configuration for several headers and also allows for setting custom headers through the <> element. --Additional information, can be found in the <> section of the reference. -+This element allows for configuring additional (security) headers to be sent with the response. -+It enables configuration for several headers and also allows for setting custom headers through the <> element. -+You can find additional information in the <> section of the reference. - - ** `Cache-Control`, `Pragma`, and `Expires` - Can be set using the <> element. - This ensures that the browser does not cache your secured pages. -@@ -248,30 +257,30 @@ https://www.w3.org/TR/CSP2/[Content Security Policy (CSP)] is a mechanism that w - - [[nsa-headers-attributes]] - ===== Attributes --The attributes on the `` element control the headers element. -+The attributes on the `` element control the `` element in the HTML output. - - - [[nsa-headers-defaults-disabled]] --* **defaults-disabled** --Optional attribute that specifies to disable the default Spring Security's HTTP response headers. --The default is false (the default headers are included). -+`defaults-disabled`:: -+Optional attribute that specifies whether to disable the default Spring Security's HTTP response headers. -+The default is `false` (the default headers are included). - - [[nsa-headers-disabled]] --* **disabled** --Optional attribute that specifies to disable Spring Security's HTTP response headers. -+`disabled`:: -+Optional attribute that specifies whether to disable Spring Security's HTTP response headers. - The default is false (the headers are enabled). - - - [[nsa-headers-parents]] - ===== Parent Elements of - --* <> -- -+The parent element of the `` element is the <`>> element. - - - [[nsa-headers-children]] - ===== Child Elements of - -+The `` element has the following possible children: - - * <> - * <> -@@ -285,318 +294,329 @@ The default is false (the headers are enabled). - * <> - - -- - [[nsa-cache-control]] - ==== --Adds `Cache-Control`, `Pragma`, and `Expires` headers to ensure that the browser does not cache your secured pages. -+The `` element adds the `Cache-Control`, `Pragma`, and `Expires` headers to ensure that the browser does not cache your secured pages. - - - [[nsa-cache-control-attributes]] - ===== Attributes - -+The `` element can have the following attribute: -+ - [[nsa-cache-control-disabled]] --* **disabled** --Specifies if Cache Control should be disabled. --Default false. -+`disabled`:: -+Specifies whether cache control should be disabled. -+Default: `false`. - - - [[nsa-cache-control-parents]] - ===== Parent Elements of - -- --* <> -- -+The parent of the `` element is the <`>> element. - - - [[nsa-hsts]] - ==== --When enabled adds the https://tools.ietf.org/html/rfc6797[Strict-Transport-Security] header to the response for any secure request. --This allows the server to instruct browsers to automatically use HTTPS for future requests. -+When enabled, the `` element adds the https://tools.ietf.org/html/rfc6797[Strict-Transport-Security] header to the response for any secure request. -+This lets the server instruct browsers to automatically use HTTPS for future requests. - - - [[nsa-hsts-attributes]] - ===== Attributes - -+The `` element has the following available attributes: -+ - [[nsa-hsts-disabled]] --* **disabled** --Specifies if Strict-Transport-Security should be disabled. --Default false. -+`disabled`:: -+Specifies whether Strict-Transport-Security should be disabled. -+Default: `false`. - - [[nsa-hsts-include-subdomains]] --* **include-sub-domains** --Specifies if subdomains should be included. --Default true. -+`include-sub-domains`:: -+Specifies whether subdomains should be included. -+Default: true. - - - [[nsa-hsts-max-age-seconds]] --* **max-age-seconds** -+`max-age-seconds`:: - Specifies the maximum amount of time the host should be considered a Known HSTS Host. - Default one year. - - - [[nsa-hsts-request-matcher-ref]] --* **request-matcher-ref** --The RequestMatcher instance to be used to determine if the header should be set. --Default is if HttpServletRequest.isSecure() is true. -+`request-matcher-ref`:: -+The `RequestMatcher` instance to be used to determine if the header should be set. -+The default is to see whether `HttpServletRequest.isSecure()` is `true`. - - [[nsa-hsts-preload]] --* **preload** --Specifies if preload should be included. --Default false. -+preload:: -+Specifies whether preload should be included. -+Default: `false`. - - [[nsa-hsts-parents]] - ===== Parent Elements of - --* <> -- -+The parent element of the `` element is the <`>> element. - - - [[nsa-hpkp]] - ==== --When enabled adds the https://tools.ietf.org/html/rfc7469[Public Key Pinning Extension for HTTP] header to the response for any secure request. --This allows HTTPS websites to resist impersonation by attackers using mis-issued or otherwise fraudulent certificates. -+When enabled, the `` element adds the https://tools.ietf.org/html/rfc7469[Public Key Pinning Extension for HTTP] header to the response for any secure request. -+This lets HTTPS websites resist impersonation by attackers that use mis-issued or otherwise fraudulent certificates. - - - [[nsa-hpkp-attributes]] - ===== Attributes - -+The `` element can have the following elements: -+ - [[nsa-hpkp-disabled]] --* **disabled** -+`disabled`:: - Specifies if HTTP Public Key Pinning (HPKP) should be disabled. --Default true. -+Default: `true`. - - [[nsa-hpkp-include-subdomains]] --* **include-sub-domains** --Specifies if subdomains should be included. --Default false. -+`include-sub-domains`:: -+Specifies whether subdomains should be included. -+Default: `false`. - - - [[nsa-hpkp-max-age-seconds]] --* **max-age-seconds** --Sets the value for the max-age directive of the Public-Key-Pins header. --Default 60 days. -+max-age-seconds:: -+Sets the value for the `max-age` directive of the `Public-Key-Pins` header. -+Default: 60 days (5,184,000 seconds) - - - [[nsa-hpkp-report-only]] --* **report-only** --Specifies if the browser should only report pin validation failures. --Default true. -+`report-only`:: -+Specifies whether the browser should report only pin validation failures. -+Default: `true`. - - - [[nsa-hpkp-report-uri]] --* **report-uri** -+`report-uri`: - Specifies the URI to which the browser should report pin validation failures. - - - [[nsa-hpkp-parents]] - ===== Parent Elements of - --* <> -+The parent element of the element is the <`>> element. - - - [[nsa-pins]] - ==== --The list of pins -+This section describes the attributes and child elements of the `` element. - - - [[nsa-pins-children]] - ===== Child Elements of - --* <> -+The element has a single child element: <`>>. There can be multiple elements. - - - [[nsa-pin]] - ==== --A pin is specified using the base64-encoded SPKI fingerprint as value and the cryptographic hash algorithm as attribute -+A element is specified by using the base64-encoded SPKI fingerprint as the value and the cryptographic hash algorithm as the attribute. - - [[nsa-pin-attributes]] - ===== Attributes - - [[nsa-pin-algorithm]] --* **algorithm** -+`algorithm`:: - The cryptographic hash algorithm. --Default is SHA256. -+Default: SHA256. - - - [[nsa-pin-parents]] - ===== Parent Elements of - --* <> -+The parent element of the element is the <`>> element. - - - - [[nsa-content-security-policy]] - ==== --When enabled adds the https://www.w3.org/TR/CSP2/[Content Security Policy (CSP)] header to the response. --CSP is a mechanism that web applications can leverage to mitigate content injection vulnerabilities, such as cross-site scripting (XSS). -+When enabled, the `` element adds the https://www.w3.org/TR/CSP2/[Content Security Policy (CSP)] header to the response. -+CSP is a mechanism that web applications can use to mitigate content injection vulnerabilities, such as cross-site scripting (XSS). - - [[nsa-content-security-policy-attributes]] - ===== Attributes - -+The element has the following attributes: -+ - [[nsa-content-security-policy-policy-directives]] --* **policy-directives** --The security policy directive(s) for the Content-Security-Policy header or if report-only is set to true, then the Content-Security-Policy-Report-Only header is used. -+`policy-directives`:: -+The security policy directive(s) for the Content-Security-Policy header. If report-only is set to `true`, the Content-Security-Policy-Report-Only header is used. - - [[nsa-content-security-policy-report-only]] --* **report-only** --Set to true, to enable the Content-Security-Policy-Report-Only header for reporting policy violations only. --Defaults to false. -+`report-only`:: -+Whether to enable the Content-Security-Policy-Report-Only header for reporting policy violations only. -+Default: `false`. - - [[nsa-content-security-policy-parents]] - ===== Parent Elements of - --* <> -+The parent element of the element is <`>>. - - - - [[nsa-referrer-policy]] - ==== --When enabled adds the https://www.w3.org/TR/referrer-policy/[Referrer Policy] header to the response. -+When enabled, the `` element adds the https://www.w3.org/TR/referrer-policy/[Referrer Policy] header to the response. - - [[nsa-referrer-policy-attributes]] - ===== Attributes - -+The `` element has the following attribute: -+ - [[nsa-referrer-policy-policy]] --* **policy** --The policy for the Referrer-Policy header. --Default "no-referrer". -+policy:: -+The policy for the `Referrer-Policy` header. -+Default: `no-referrer`. - - [[nsa-referrer-policy-parents]] - ===== Parent Elements of - --* <> -+The parent element of the `` element is the <`>> element. - - - - [[nsa-feature-policy]] - ==== --When enabled adds the https://wicg.github.io/feature-policy/[Feature Policy] header to the response. -+When enabled, the `` element adds the https://wicg.github.io/feature-policy/[Feature Policy] header to the response. - - [[nsa-feature-policy-attributes]] - ===== Attributes - -+The `` element has the following attribute: -+ - [[nsa-feature-policy-policy-directives]] --* **policy-directives** -+`policy-directives`:: - The security policy directive(s) for the Feature-Policy header. - - [[nsa-feature-policy-parents]] - ===== Parent Elements of - --* <> -+The parent element of the element is the <`>> element. - - - - [[nsa-frame-options]] - ==== --When enabled adds the https://tools.ietf.org/html/draft-ietf-websec-x-frame-options[X-Frame-Options header] to the response, this allows newer browsers to do some security checks and prevent https://en.wikipedia.org/wiki/Clickjacking[clickjacking] attacks. -+When enabled, the `` element adds the https://tools.ietf.org/html/draft-ietf-websec-x-frame-options[X-Frame-Options header] to the response. Doing so lets newer browsers do some security checks and prevent https://en.wikipedia.org/wiki/Clickjacking[clickjacking] attacks. - - - [[nsa-frame-options-attributes]] - ===== Attributes - -+The `` element has the following attributes: -+ - [[nsa-frame-options-disabled]] --* **disabled** --If disabled, the X-Frame-Options header will not be included. --Default false. -+`disabled`:: -+If disabled, the X-Frame-Options header is not included. -+Default: `false`. - - [[nsa-frame-options-policy]] --* **policy** --** `DENY` The page cannot be displayed in a frame, regardless of the site attempting to do so. -+`policy`:: -+* `DENY` (default): The page cannot be displayed in a frame, regardless of the site attempting to do so. - This is the default when frame-options-policy is specified. --** `SAMEORIGIN` The page can only be displayed in a frame on the same origin as the page itself -+* `SAMEORIGIN`: The page can be displayed in a frame only on the same origin as the page itself. - --+ -- --In other words, if you specify DENY, not only will attempts to load the page in a frame fail when loaded from other sites, attempts to do so will fail when loaded from the same site. --On the other hand, if you specify SAMEORIGIN, you can still use the page in a frame as long as the site including it in a frame it is the same as the one serving the page. -+In other words, if you specify `DENY`, not only do attempts to load the page in a frame fail when loaded from other sites, attempts to do so fail when loaded from the same site. -+On the other hand, if you specify `SAMEORIGIN`, you can still use the page in a frame as long as the site including it in a frame is the same site as the one serving the page. - - - - [[nsa-frame-options-parents]] - ===== Parent Elements of - --* <> -+The parent element of the `` element is the <`>> element. - - - - [[nsa-xss-protection]] - ==== --Adds the https://blogs.msdn.com/b/ie/archive/2008/07/02/ie8-security-part-iv-the-xss-filter.aspx[X-XSS-Protection header] to the response to assist in protecting against https://en.wikipedia.org/wiki/Cross-site_scripting#Non-Persistent[reflected / Type-1 Cross-Site Scripting (XSS)] attacks. --This is in no-way a full protection to XSS attacks! -+The `` adds the https://blogs.msdn.com/b/ie/archive/2008/07/02/ie8-security-part-iv-the-xss-filter.aspx[X-XSS-Protection header] to the response, to assist in protecting against https://en.wikipedia.org/wiki/Cross-site_scripting#Non-Persistent[reflected / Type-1 Cross-Site Scripting (XSS)] attacks. -+NOTE: Full protection against XSS attacks is not possible. - - - [[nsa-xss-protection-attributes]] - ===== Attributes - -+The `` element has the following attributes: - - [[nsa-xss-protection-disabled]] --* **xss-protection-disabled** --Do not include the header for https://en.wikipedia.org/wiki/Cross-site_scripting#Non-Persistent[reflected / Type-1 Cross-Site Scripting (XSS)] protection. -+`xss-protection-disabled`:: -+If set to `true`, do not include the header for https://en.wikipedia.org/wiki/Cross-site_scripting#Non-Persistent[reflected / Type-1 Cross-Site Scripting (XSS)] protection. - - - [[nsa-xss-protection-enabled]] - * **xss-protection-enabled** --Explicitly enable or disable https://en.wikipedia.org/wiki/Cross-site_scripting#Non-Persistent[reflected / Type-1 Cross-Site Scripting (XSS)] protection. -+Whether to explicitly enable or disable https://en.wikipedia.org/wiki/Cross-site_scripting#Non-Persistent[reflected / Type-1 Cross-Site Scripting (XSS)] protection. - - - [[nsa-xss-protection-block]] - * **xss-protection-block** --When true and xss-protection-enabled is true, adds mode=block to the header. -+When `true` and `xss-protection-enabled` is `true`, adds `mode=block` to the header. - This indicates to the browser that the page should not be loaded at all. --When false and xss-protection-enabled is true, the page will still be rendered when an reflected attack is detected but the response will be modified to protect against the attack. --Note that there are sometimes ways of bypassing this mode which can often times make blocking the page more desirable. -+When `false` and `xss-protection-enabled` is `true`, the page is still rendered when a reflected attack is detected, but the response is modified to protect against the attack. -+Note that there are sometimes ways of bypassing this mode, which can often times make blocking the page more desirable. - - - [[nsa-xss-protection-parents]] - ===== Parent Elements of - --* <> -+The parent element of the `` is the <`>> element. - - - - [[nsa-content-type-options]] - ==== --Add the X-Content-Type-Options header with the value of nosniff to the response. -+The `` element adds the `X-Content-Type-Options` header with a value of `nosniff` to the response. - This https://blogs.msdn.com/b/ie/archive/2008/09/02/ie8-security-part-vi-beta-2-update.aspx[disables MIME-sniffing] for IE8+ and Chrome extensions. - - - [[nsa-content-type-options-attributes]] - ===== Attributes - -+The `` element has the following attribute: -+ - [[nsa-content-type-options-disabled]] --* **disabled** --Specifies if Content Type Options should be disabled. --Default false. -+`disabled`:: -+Specifies whether Content Type Options should be disabled. -+Default: `false`. - - [[nsa-content-type-options-parents]] - ===== Parent Elements of - -- --* <> -+The parent element of the `` element is the <`>> element. - - - - [[nsa-header]] - ====
--Add additional headers to the response, both the name and value need to be specified. -+The `
` element adds additional headers to the response. Both the name and value of each added header need to be specified in a `` element (a child of the `
` element). To add multiple headers, add multiple `` elements. - - - [[nsa-header-attributes]] - ===== Attributes - -+The `` element has the following attributes: - - [[nsa-header-name]] --* **header-name** --The `name` of the header. -+`header-name`:: -+The `name` of the header to add. - - - [[nsa-header-value]] --* **value** -+value:: - The `value` of the header to add. - - - [[nsa-header-ref]] --* **ref** -+`ref`:: - Reference to a custom implementation of the `HeaderWriter` interface. - - -@@ -604,335 +624,341 @@ Reference to a custom implementation of the `HeaderWriter` interface. - ===== Parent Elements of
- - --* <> -+The parent element of the `
` is the <`>> element. - - - - [[nsa-anonymous]] - ==== --Adds an `AnonymousAuthenticationFilter` to the stack and an `AnonymousAuthenticationProvider`. --Required if you are using the `IS_AUTHENTICATED_ANONYMOUSLY` attribute. -+The `` element adds an `AnonymousAuthenticationFilter` to the stack and adds an `AnonymousAuthenticationProvider`. -+This element is required if you use the `IS_AUTHENTICATED_ANONYMOUSLY` attribute. - - - [[nsa-anonymous-parents]] - ===== Parent Elements of - -- --* <> -+The parent element of the `` element is the <`>> element. - - - - [[nsa-anonymous-attributes]] - ===== Attributes - -+The `` element has the following attributes: - - [[nsa-anonymous-enabled]] --* **enabled** --With the default namespace setup, the anonymous "authentication" facility is automatically enabled. --You can disable it using this property. -+`enabled`:: -+With the default namespace setup, the anonymous "`authentication`" facility is automatically enabled. -+You can disable it by setting this property. - - - [[nsa-anonymous-granted-authority]] --* **granted-authority** -+`granted-authority`:: - The granted authority that should be assigned to the anonymous request. --Commonly this is used to assign the anonymous request particular roles, which can subsequently be used in authorization decisions. --If unset, defaults to `ROLE_ANONYMOUS`. -+Commonly, this attribute is used to assign the anonymous request particular roles, which can subsequently be used in authorization decisions. -+If unset, it defaults to `ROLE_ANONYMOUS`. - - - [[nsa-anonymous-key]] --* **key** --The key shared between the provider and filter. -+`key`:: -+The key shared between the provider and the filter. - This generally does not need to be set. --If unset, it will default to a secure randomly generated value. --This means setting this value can improve startup time when using the anonymous functionality since secure random values can take a while to be generated. -+If unset, it defaults to a secure randomly generated value. -+This means that setting this value can improve startup time when using the anonymous functionality, since secure random values can take a while to be generated. - - - [[nsa-anonymous-username]] --* **username** -+username:: - The username that should be assigned to the anonymous request. --This allows the principal to be identified, which may be important for logging and auditing. --if unset, defaults to `anonymousUser`. -+This lets the principal be identified, which may be important for logging and auditing. -+Defaults: `anonymousUser` - - - [[nsa-csrf]] - ==== --This element will add https://en.wikipedia.org/wiki/Cross-site_request_forgery[Cross Site Request Forger (CSRF)] protection to the application. --It also updates the default RequestCache to only replay "GET" requests upon successful authentication. --Additional information can be found in the <> section of the reference. -+The `> section of the reference. - - - [[nsa-csrf-parents]] --===== Parent Elements of -+===== Parent Element of - -- --* <> -+The parent element of the `` element is the <> element. - - - - [[nsa-csrf-attributes]] - ===== Attributes - -+The `` element has the following attributes: -+ - [[nsa-csrf-disabled]] --* **disabled** --Optional attribute that specifies to disable Spring Security's CSRF protection. --The default is false (CSRF protection is enabled). --It is highly recommended to leave CSRF protection enabled. -+`disabled`:: -+Optional attribute that specifies whether to disable Spring Security's CSRF protection. -+Default: `false` (CSRF protection is enabled) -+We highly recommended leaving CSRF protection enabled. - - [[nsa-csrf-token-repository-ref]] --* **token-repository-ref** --The CsrfTokenRepository to use. --The default is `HttpSessionCsrfTokenRepository`. -+`token-repository-ref`:: -+The `CsrfTokenRepository` to use. -+Default: `HttpSessionCsrfTokenRepository` - - - [[nsa-csrf-request-matcher-ref]] --* **request-matcher-ref** --The RequestMatcher instance to be used to determine if CSRF should be applied. --Default is any HTTP method except "GET", "TRACE", "HEAD", "OPTIONS". -+request-matcher-ref:: -+The `RequestMatcher` instance to be used to determine whether CSRF should be applied. -+The default is any HTTP method except `GET`, `TRACE`, `HEAD`, `OPTIONS`. - - - [[nsa-custom-filter]] - ==== --This element is used to add a filter to the filter chain. --It doesn't create any additional beans but is used to select a bean of type `javax.servlet.Filter` which is already defined in the application context and add that at a particular position in the filter chain maintained by Spring Security. -+The `` element adds a filter to the filter chain. -+It does not create any additional beans but is used to select a bean of type `javax.servlet.Filter` which is already defined in the application context and add that at a particular position in the filter chain maintained by Spring Security. - Full details can be found in the <>. - - - [[nsa-custom-filter-parents]] - ===== Parent Elements of - -- --* <> -+The parent element of the `` is the <`>> element. - - - - [[nsa-custom-filter-attributes]] - ===== Attributes - -+The `` element has the following attributes: - - [[nsa-custom-filter-after]] --* **after** --The filter immediately after which the custom-filter should be placed in the chain. --This feature will only be needed by advanced users who wish to mix their own filters into the security filter chain and have some knowledge of the standard Spring Security filters. -+`after`:: -+The filter immediately after which the custom filter should be placed in the chain. -+This feature is needed only by advanced users who wish to mix their own filters into the security filter chain and have some knowledge of the standard Spring Security filters. - The filter names map to specific Spring Security implementation filters. - - - [[nsa-custom-filter-before]] --* **before** --The filter immediately before which the custom-filter should be placed in the chain -+`before`:: -+The filter immediately before which the custom filter should be placed in the chain. - - - [[nsa-custom-filter-position]] --* **position** --The explicit position at which the custom-filter should be placed in the chain. --Use if you are replacing a standard filter. -+`position`:: -+The explicit position at which the custom filter should be placed in the chain. -+Use this attribute to replace a standard filter. - - - [[nsa-custom-filter-ref]] --* **ref** -+ref:: - Defines a reference to a Spring bean that implements `Filter`. - - - [[nsa-expression-handler]] - ==== --Defines the `SecurityExpressionHandler` instance which will be used if expression-based access-control is enabled. --A default implementation (with no ACL support) will be used if not supplied. -+Defines the `SecurityExpressionHandler` instance to be used if expression-based access control is enabled. -+A default implementation (with no ACL support) is used if none is supplied. - - - [[nsa-expression-handler-parents]] - ===== Parent Elements of - -+The `` has the following parent elements: - --* <> --* <> --* <> -+* <> -+* <> -+* <> - - - - [[nsa-expression-handler-attributes]] - ===== Attributes - -+The `` element has the following attribute: - - [[nsa-expression-handler-ref]] --* **ref** -+`ref`:: - Defines a reference to a Spring bean that implements `SecurityExpressionHandler`. - - - [[nsa-form-login]] - ==== --Used to add an `UsernamePasswordAuthenticationFilter` to the filter stack and an `LoginUrlAuthenticationEntryPoint` to the application context to provide authentication on demand. --This will always take precedence over other namespace-created entry points. --If no attributes are supplied, a login page will be generated automatically at the URL "/login" footnote:[ --This feature is really just provided for convenience and is not intended for production (where a view technology will have been chosen and can be used to render a customized login page). --The class `DefaultLoginPageGeneratingFilter` is responsible for rendering the login page and will provide login forms for both normal form login and/or OpenID if required. --] The behaviour can be customized using the <` Attributes>>. -+Used to add an `UsernamePasswordAuthenticationFilter` to the filter stack and a `LoginUrlAuthenticationEntryPoint` to the application context, to provide authentication on demand. -+This always takes precedence over other namespace-created entry points. -+If no attributes are supplied, a login page is generated automatically at the `/login` URL. -+You can customize this behavior by setting the <` Attributes>>. -+ -+NOTE: This feature is provided for convenience and is not intended for production (where a view technology should have been chosen and can be used to render a customized login page). -+The class `DefaultLoginPageGeneratingFilter` class is responsible for rendering the login page and provide login forms for both normal form login and OpenID if required. - - - [[nsa-form-login-parents]] - ===== Parent Elements of - - --* <> -+The parent element of the `` element is the <`>> element. - - - - [[nsa-form-login-attributes]] - ===== Attributes -+The `form-login` element has the following attributes: - - - [[nsa-form-login-always-use-default-target]] --* **always-use-default-target** --If set to `true`, the user will always start at the value given by <>, regardless of how they arrived at the login page. -+`always-use-default-target` -+If set to `true`, the user always starts at the value given by <>, regardless of how they arrived at the login page. - Maps to the `alwaysUseDefaultTargetUrl` property of `UsernamePasswordAuthenticationFilter`. --Default value is `false`. -+Default: `false`. - - - [[nsa-form-login-authentication-details-source-ref]] --* **authentication-details-source-ref** --Reference to an `AuthenticationDetailsSource` which will be used by the authentication filter -+`authentication-details-source-ref`:: -+Reference to an `AuthenticationDetailsSource`, which is used by the authentication filter. - - - [[nsa-form-login-authentication-failure-handler-ref]] --* **authentication-failure-handler-ref** --Can be used as an alternative to <>, giving you full control over the navigation flow after an authentication failure. -+`authentication-failure-handler-ref`:: -+Can be used as an alternative to <>, giving you full control over the navigation flow after an authentication failure. - The value should be the name of an `AuthenticationFailureHandler` bean in the application context. - - - [[nsa-form-login-authentication-failure-url]] - * **authentication-failure-url** - Maps to the `authenticationFailureUrl` property of `UsernamePasswordAuthenticationFilter`. --Defines the URL the browser will be redirected to on login failure. --Defaults to `/login?error`, which will be automatically handled by the automatic login page generator, re-rendering the login page with an error message. -+Defines the URL to which the browser is redirected on login failure. -+Defaults to `/login?error`, which is automatically handled by the automatic login page generator, re-rendering the login page with an error message. - - - [[nsa-form-login-authentication-success-handler-ref]] --* **authentication-success-handler-ref** --This can be used as an alternative to <> and <>, giving you full control over the navigation flow after a successful authentication. -+`authentication-success-handler-ref`:: -+You an use this as an alternative to <> and <>, giving you full control over the navigation flow after a successful authentication. - The value should be the name of an `AuthenticationSuccessHandler` bean in the application context. --By default, an implementation of `SavedRequestAwareAuthenticationSuccessHandler` is used and injected with the <>. -+By default, an implementation of `SavedRequestAwareAuthenticationSuccessHandler` is used and injected with the <>. - - - [[nsa-form-login-default-target-url]] --* **default-target-url** -+default-target-url:: - Maps to the `defaultTargetUrl` property of `UsernamePasswordAuthenticationFilter`. --If not set, the default value is "/" (the application root). --A user will be taken to this URL after logging in, provided they were not asked to login while attempting to access a secured resource, when they will be taken to the originally requested URL. -+If not set, the default value is `/` (the application root). -+A user is taken to this URL after logging in, provided they were not asked to login while attempting to access a secured resource, when they will be taken to the originally requested URL. - - - [[nsa-form-login-login-page]] --* **login-page** -+`login-page`:: - The URL that should be used to render the login page. - Maps to the `loginFormUrl` property of the `LoginUrlAuthenticationEntryPoint`. --Defaults to "/login". -+Default: `/login`. - - - [[nsa-form-login-login-processing-url]] --* **login-processing-url** -+`login-processing-url`:: - Maps to the `filterProcessesUrl` property of `UsernamePasswordAuthenticationFilter`. --The default value is "/login". -+Default: `/login`. - - - [[nsa-form-login-password-parameter]] - * **password-parameter** --The name of the request parameter which contains the password. --Defaults to "password". -+The name of the request parameter that contains the password. -+Default: `password`. - - - [[nsa-form-login-username-parameter]] --* **username-parameter** --The name of the request parameter which contains the username. --Defaults to "username". -+username-parameter:: -+The name of the request parameter that contains the username. -+Default: `username`. - - [[nsa-form-login-authentication-success-forward-url]] --* **authentication-success-forward-url** --Maps a `ForwardAuthenticationSuccessHandler` to `authenticationSuccessHandler` property of `UsernamePasswordAuthenticationFilter`. -+`authentication-success-forward-url`:: -+Maps a `ForwardAuthenticationSuccessHandler` to the `authenticationSuccessHandler` property of `UsernamePasswordAuthenticationFilter`. - - - [[nsa-form-login-authentication-failure-forward-url]] --* **authentication-failure-forward-url** --Maps a `ForwardAuthenticationFailureHandler` to `authenticationFailureHandler` property of `UsernamePasswordAuthenticationFilter`. -+`authentication-failure-forward-url`:: -+Maps a `ForwardAuthenticationFailureHandler` to the `authenticationFailureHandler` property of `UsernamePasswordAuthenticationFilter`. - - - [[nsa-oauth2-login]] - ==== --The <> feature configures authentication support using an OAuth 2.0 and/or OpenID Connect 1.0 Provider. -+The <> feature configures authentication support by using an OAuth 2.0 or OpenID Connect 1.0 Provider. - - - [[nsa-oauth2-login-parents]] - ===== Parent Elements of - --* <> -+The parent element of the `` element is the <`>> element. - - [[nsa-oauth2-login-attributes]] - ===== Attributes - -+The `` has the following attributes: - - [[nsa-oauth2-login-client-registration-repository-ref]] --* **client-registration-repository-ref** -+`client-registration-repository-ref`:: - Reference to the `ClientRegistrationRepository`. - - - [[nsa-oauth2-login-authorized-client-repository-ref]] --* **authorized-client-repository-ref** -+`authorized-client-repository-ref`:: - Reference to the `OAuth2AuthorizedClientRepository`. - - - [[nsa-oauth2-login-authorized-client-service-ref]] --* **authorized-client-service-ref** -+`authorized-client-service-ref`:: - Reference to the `OAuth2AuthorizedClientService`. - - - [[nsa-oauth2-login-authorization-request-repository-ref]] --* **authorization-request-repository-ref** -+`authorization-request-repository-ref`:: - Reference to the `AuthorizationRequestRepository`. - - - [[nsa-oauth2-login-authorization-request-resolver-ref]] --* **authorization-request-resolver-ref** -+`authorization-request-resolver-ref`:: - Reference to the `OAuth2AuthorizationRequestResolver`. - - - [[nsa-oauth2-login-access-token-response-client-ref]] --* **access-token-response-client-ref** -+`access-token-response-client-ref`:: - Reference to the `OAuth2AccessTokenResponseClient`. - - - [[nsa-oauth2-login-user-authorities-mapper-ref]] --* **user-authorities-mapper-ref** -+`user-authorities-mapper-ref`:: - Reference to the `GrantedAuthoritiesMapper`. - - - [[nsa-oauth2-login-user-service-ref]] --* **user-service-ref** -+`user-service-ref`:: - Reference to the `OAuth2UserService`. - - - [[nsa-oauth2-login-oidc-user-service-ref]] --* **oidc-user-service-ref** -+`oidc-user-service-ref`:: - Reference to the OpenID Connect `OAuth2UserService`. - - - [[nsa-oauth2-login-login-processing-url]] --* **login-processing-url** -+`login-processing-url`:: - The URI where the filter processes authentication requests. - - - [[nsa-oauth2-login-login-page]] --* **login-page** --The URI to send users to login. -+`login-page`:: -+The URI to which to send users to login. - - - [[nsa-oauth2-login-authentication-success-handler-ref]] --* **authentication-success-handler-ref** -+`authentication-success-handler-ref`:: - Reference to the `AuthenticationSuccessHandler`. - - - [[nsa-oauth2-login-authentication-failure-handler-ref]] --* **authentication-failure-handler-ref** -+`authentication-failure-handler-ref`:: - Reference to the `AuthenticationFailureHandler`. - - - [[nsa-oauth2-login-jwt-decoder-factory-ref]] --* **jwt-decoder-factory-ref** -+`jwt-decoder-factory-ref`:: - Reference to the `JwtDecoderFactory` used by `OidcAuthorizationCodeAuthenticationProvider`. - - -@@ -944,31 +970,32 @@ Configures <> support. - [[nsa-oauth2-client-parents]] - ===== Parent Elements of - --* <> -+The parent of the `` is the <`>> element. - - [[nsa-oauth2-client-attributes]] - ===== Attributes - -+The `` element has the following attributes: - - [[nsa-oauth2-client-client-registration-repository-ref]] --* **client-registration-repository-ref** -+`client-registration-repository-ref`:: - Reference to the `ClientRegistrationRepository`. - - - [[nsa-oauth2-client-authorized-client-repository-ref]] --* **authorized-client-repository-ref** -+`authorized-client-repository-ref`:: - Reference to the `OAuth2AuthorizedClientRepository`. - - - [[nsa-oauth2-client-authorized-client-service-ref]] --* **authorized-client-service-ref** -+`authorized-client-service-ref`:: - Reference to the `OAuth2AuthorizedClientService`. - - - [[nsa-oauth2-client-children]] - ===== Child Elements of - --* <> -+The `` has one child element: <`>>. - - - [[nsa-authorization-code-grant]] -@@ -979,49 +1006,52 @@ Configures < - [[nsa-authorization-code-grant-parents]] - ===== Parent Elements of - --* <> -+The parent element of the `` element is the <> element. - - - [[nsa-authorization-code-grant-attributes]] - ===== Attributes - -+The `` element has the following attributes: - - [[nsa-authorization-code-grant-authorization-request-repository-ref]] --* **authorization-request-repository-ref** -+`authorization-request-repository-ref`:: - Reference to the `AuthorizationRequestRepository`. - - - [[nsa-authorization-code-grant-authorization-request-resolver-ref]] --* **authorization-request-resolver-ref** -+`authorization-request-resolver-ref`:: - Reference to the `OAuth2AuthorizationRequestResolver`. - - - [[nsa-authorization-code-grant-access-token-response-client-ref]] --* **access-token-response-client-ref** -+`access-token-response-client-ref`:: - Reference to the `OAuth2AccessTokenResponseClient`. - - - [[nsa-client-registrations]] - ==== --A container element for client(s) registered (<>) with an OAuth 2.0 or OpenID Connect 1.0 Provider. -+The `` is a container element for client(s) registered (<>) with an OAuth 2.0 or OpenID Connect 1.0 Provider. - - - [[nsa-client-registrations-children]] - ===== Child Elements of - -+The `` element has the following child elements: -+ - * <> - * <> - - - [[nsa-client-registration]] - ==== --Represents a client registered with an OAuth 2.0 or OpenID Connect 1.0 Provider. -+The `` represents a client registered with an OAuth 2.0 or OpenID Connect 1.0 Provider. You can have multiple `` elements. - - - [[nsa-client-registration-parents]] - ===== Parent Elements of - --* <> -+The parent element of the `` is the <>. - - - [[nsa-client-registration-attributes]] -@@ -1029,966 +1059,960 @@ Represents a client registered with an OAuth 2.0 or OpenID Connect 1.0 Provider. - - - [[nsa-client-registration-registration-id]] --* **registration-id** -+registration-`id`:: - The ID that uniquely identifies the `ClientRegistration`. - - - [[nsa-client-registration-client-id]] --* **client-id** -+`client-id`:: - The client identifier. - - - [[nsa-client-registration-client-secret]] --* **client-secret** -+`client-secret`:: - The client secret. - - - [[nsa-client-registration-client-authentication-method]] --* **client-authentication-method** --The method used to authenticate the Client with the Provider. --The supported values are *client_secret_basic*, *client_secret_post* and *none* https://tools.ietf.org/html/rfc6749#section-2.1[(public clients)]. -+`client-authentication-method`:: -+The method used to authenticate the client with the provider. -+The supported values are `client_secret_basic`, `client_secret_post`, and `none` (https://tools.ietf.org/html/rfc6749#section-2.1[public clients]). - - - [[nsa-client-registration-authorization-grant-type]] --* **authorization-grant-type** -+`authorization-grant-type`:: - The OAuth 2.0 Authorization Framework defines four https://tools.ietf.org/html/rfc6749#section-1.3[Authorization Grant] types. --The supported values are `authorization_code`, `client_credentials` and `password`. -+The supported values are `authorization_code`, `client_credentials`, and `password`. - - - [[nsa-client-registration-redirect-uri]] --* **redirect-uri** --The client's registered redirect URI that the _Authorization Server_ redirects the end-user's user-agent to after the end-user has authenticated and authorized access to the client. -+`redirect-uri`:: -+The client's registered redirect URI to which the _Authorization Server_ redirects the end-user's user-agent after the end-user has authenticated and authorized access to the client. - - - [[nsa-client-registration-scope]] --* **scope** --The scope(s) requested by the client during the Authorization Request flow, such as openid, email, or profile. -+`scope`:: -+The scope(s) requested by the client during the Authorization Request flow, such as `openid`, `email`, or `profile`. - - - [[nsa-client-registration-client-name]] --* **client-name** -+`client-name`:: - A descriptive name used for the client. - The name may be used in certain scenarios, such as when displaying the name of the client in the auto-generated login page. - - [[nsa-client-registration-provider-id]] --* **provider-id** --A reference to the associated provider. May reference a `` element or use one of the common providers (google, github, facebook, okta). -+`provider-id` -+A reference to the associated provider. May reference a `` element or use one of the common providers (Google, Github, Facebook, Okta, and others). - - - [[nsa-provider]] - ==== --The configuration information for an OAuth 2.0 or OpenID Connect 1.0 Provider. -+The `` element contains the configuration information for an OAuth 2.0 or OpenID Connect 1.0 Provider. - - - [[nsa-provider-parents]] - ===== Parent Elements of - --* <> -+The parent element of the `` element is the <`>> element. - - - [[nsa-provider-attributes]] - ===== Attributes - -+The `` element has the following attributes: -+ - - [[nsa-provider-provider-id]] --* **provider-id** -+`provider-id`:: - The ID that uniquely identifies the provider. - - - [[nsa-provider-authorization-uri]] --* **authorization-uri** --The Authorization Endpoint URI for the Authorization Server. -+`authorization-uri`:: -+The authorization endpoint URI for the authorization server. - - - [[nsa-provider-token-uri]] --* **token-uri** --The Token Endpoint URI for the Authorization Server. -+`token-uri`:: -+The token endpoint URI for the authorization server. - - - [[nsa-provider-user-info-uri]] --* **user-info-uri** --The UserInfo Endpoint URI used to access the claims/attributes of the authenticated end-user. -+`user-info-uri`:: -+The UserInfo endpoint URI used to access the claims and attributes of the authenticated end user. - - - [[nsa-provider-user-info-authentication-method]] --* **user-info-authentication-method** --The authentication method used when sending the access token to the UserInfo Endpoint. --The supported values are *header*, *form* and *query*. -+`user-info-authentication-method`:: -+The authentication method used when sending the access token to the UserInfo endpoint. -+The supported values are `header`, `form`, and `query`. - - - [[nsa-provider-user-info-user-name-attribute]] --* **user-info-user-name-attribute** --The name of the attribute returned in the UserInfo Response that references the Name or Identifier of the end-user. -+`user-info-user-name-attribute`:: -+The name of the attribute returned in the UserInfo response that references the name or edentifier of the end-user. - - - [[nsa-provider-jwk-set-uri]] --* **jwk-set-uri** --The URI used to retrieve the https://tools.ietf.org/html/rfc7517[JSON Web Key (JWK)] Set from the Authorization Server, which contains the cryptographic key(s) used to verify the https://tools.ietf.org/html/rfc7515[JSON Web Signature (JWS)] of the ID Token and optionally the UserInfo Response. -+`jwk-set-uri`:: -+The URI used to retrieve the https://tools.ietf.org/html/rfc7517[JSON Web Key (JWK)] set from the authorization server, which contains the cryptographic key(s) used to verify the https://tools.ietf.org/html/rfc7515[JSON Web Signature (JWS)] of the ID Token and (optionally) the UserInfo response. - - - [[nsa-provider-issuer-uri]] --* **issuer-uri** --The URI used to initially configure a `ClientRegistration` using discovery of an OpenID Connect Provider's https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfig[Configuration endpoint] or an Authorization Server's https://tools.ietf.org/html/rfc8414#section-3[Metadata endpoint]. -+issuer-uri:: -+The URI used to initially configure a `ClientRegistration` by using discovery of an OpenID Connect Provider's https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfig[configuration endpoint] or an Authorization Server's https://tools.ietf.org/html/rfc8414#section-3[metadata endpoint]. - - [[nsa-oauth2-resource-server]] - ==== --Adds a `BearerTokenAuthenticationFilter`, `BearerTokenAuthenticationEntryPoint`, and `BearerTokenAccessDeniedHandler` to the configuration. -+Adds a `BearerTokenAuthenticationFilter`, a `BearerTokenAuthenticationEntryPoint`, and a `BearerTokenAccessDeniedHandler` to the configuration. - In addition, either `` or `` must be specified. - - [[nsa-oauth2-resource-server-parents]] - ===== Parents Elements of - --* <> -+The parent element of the `` is the <`>> element. - - [[nsa-oauth2-resource-server-children]] - ===== Child Elements of - --* <> --* <> -+The `` element has the following child elements: -+ -+* <`>> -+* <`>> - - [[nsa-oauth2-resource-server-attributes]] - ===== Attributes - -+The `` element has the following attributes: -+ - [[nsa-oauth2-resource-server-authentication-manager-resolver-ref]] --* **authentication-manager-resolver-ref** --Reference to an `AuthenticationManagerResolver` which will resolve the `AuthenticationManager` at request time -+`authentication-manager-resolver-ref`:: -+Reference to an `AuthenticationManagerResolver`, which resolves the `AuthenticationManager` at request time. - - [[nsa-oauth2-resource-server-bearer-token-resolver-ref]] --* **bearer-token-resolver-ref** --Reference to a `BearerTokenResolver` which will retrieve the bearer token from the request -+`bearer-token-resolver-ref`:: -+Reference to a `BearerTokenResolver`, which retrieves the bearer token from the request. - - [[nsa-oauth2-resource-server-entry-point-ref]] --* **entry-point-ref** --Reference to a `AuthenticationEntryPoint` which will handle unauthorized requests -+`entry-point-ref`:: -+Reference to a `AuthenticationEntryPoint`, which handles unauthorized requests. - - [[nsa-jwt]] --==== --Represents an OAuth 2.0 Resource Server that will authorize JWTs -+==== The element -+The `` element represents an OAuth 2.0 Resource Server that authorizes JWTs (JSON Web Tokens). - - - [[nsa-jwt-parents]] - ===== Parent Elements of - --* <> -+The parent element of the `` element is the <`>> element. - - - [[nsa-jwt-attributes]] - ===== Attributes - -+The `` element has the following attributes: -+ - [[nsa-jwt-jwt-authentication-converter-ref]] --* **jwt-authentication-converter-ref** --Reference to a `Converter` -+`jwt-authentication-converter-ref`:: -+Reference to a `Converter`. - - [[nsa-jwt-decoder-ref]] --* **jwt-decoder-ref** --Reference to a `JwtDecoder`. This is a larger component that overrides `jwk-set-uri` -+`jwt-decoder-ref`:: -+Reference to a `JwtDecoder`. This is a larger component that overrides `jwk-set-uri`. - - [[nsa-jwt-jwk-set-uri]] --* **jwk-set-uri** --The JWK Set Uri used to load signing verification keys from an OAuth 2.0 Authorization Server -+`jwk-set-uri`:: -+The JWK Set URI used to load signing verification keys from an OAuth 2.0 Authorization Server. - - [[nsa-opaque-token]] --==== --Represents an OAuth 2.0 Resource Server that will authorize opaque tokens -+==== The Element -+Represents an OAuth 2.0 Resource Server that authorizes opaque tokens. - - [[nsa-opaque-token-parents]] - ===== Parent Elements of - --* <> -+The parent element of the `> element. - - [[nsa-opaque-token-attributes]] - ===== Attributes - - [[nsa-opaque-token-introspector-ref]] --* **introspector-ref** -+`introspector-ref`:: - Reference to an `OpaqueTokenIntrospector`. This is a larger component that overrides `introspection-uri`, `client-id`, and `client-secret`. - - [[nsa-opaque-token-introspection-uri]] --* **introspection-uri** --The Introspection Uri used to introspect the details of an opaque token. Should be accompanied with a `client-id` and `client-secret`. -+`introspection-uri`:: -+The Introspection URI used to introspect the details of an opaque token. It should be accompanied by a `client-id` and `client-secret`. - - [[nsa-opaque-token-client-id]] --* **client-id** --The Client Id to use for client authentication against the provided `introspection-uri`. -+`client-id`:: -+The client ID to use for client authentication against the provided `introspection-uri`. - - [[nsa-opaque-token-client-secret]] --* **client-secret** --The Client Secret to use for client authentication against the provided `introspection-uri`. -+`client-secret`:: -+The client secret to use for client authentication against the provided `introspection-uri`. - - [[nsa-http-basic]] - ==== --Adds a `BasicAuthenticationFilter` and `BasicAuthenticationEntryPoint` to the configuration. --The latter will only be used as the configuration entry point if form-based login is not enabled. -+The adds a `BasicAuthenticationFilter` and `BasicAuthenticationEntryPoint` to the configuration. -+The latter is used as the configuration entry point only if form-based login is not enabled. - - - [[nsa-http-basic-parents]] - ===== Parent Elements of - - --* <> -+The parent element of the `` element is the <`>> element. - - - - [[nsa-http-basic-attributes]] - ===== Attributes - -+The `` element has the following attributes: -+ - - [[nsa-http-basic-authentication-details-source-ref]] --* **authentication-details-source-ref** --Reference to an `AuthenticationDetailsSource` which will be used by the authentication filter -+`authentication-details-source-ref`:: -+Reference to an `AuthenticationDetailsSource`, which is used by the authentication filter. - - - [[nsa-http-basic-entry-point-ref]] --* **entry-point-ref** --Sets the `AuthenticationEntryPoint` which is used by the `BasicAuthenticationFilter`. -+`entry-point-ref`:: -+Sets the `AuthenticationEntryPoint`, which is used by the `BasicAuthenticationFilter`. - - - [[nsa-http-firewall]] - ==== Element --This is a top-level element which can be used to inject a custom implementation of `HttpFirewall` into the `FilterChainProxy` created by the namespace. -+`` is a top-level element that you can use to inject a custom implementation of `HttpFirewall` into the `FilterChainProxy` created by the namespace. - The default implementation should be suitable for most applications. - - - [[nsa-http-firewall-attributes]] - ===== Attributes - -+`` has a single attribute: - - [[nsa-http-firewall-ref]] --* **ref** -+`ref`:: - Defines a reference to a Spring bean that implements `HttpFirewall`. - - - [[nsa-intercept-url]] - ==== --This element is used to define the set of URL patterns that the application is interested in and to configure how they should be handled. --It is used to construct the `FilterInvocationSecurityMetadataSource` used by the `FilterSecurityInterceptor`. --It is also responsible for configuring a `ChannelProcessingFilter` if particular URLs need to be accessed by HTTPS, for example. -+`` element defines the set of URL patterns that the application is interested in and configures how they should be handled. -+It constructs the `FilterInvocationSecurityMetadataSource` used by the `FilterSecurityInterceptor`. -+It is also responsible for configuring a `ChannelProcessingFilter` (if particular URLs need to be accessed by HTTPS, for example). - When matching the specified patterns against an incoming request, the matching is done in the order in which the elements are declared. --So the most specific patterns should come first and the most general should come last. -+So, the most specific patterns should come first and the most general should come last. - - - [[nsa-intercept-url-parents]] - ===== Parent Elements of - -+The parent elements of the `` element are: - --* <> --* <> -- -+* <`>> -+* <`>> - - - [[nsa-intercept-url-attributes]] - ===== Attributes - -+The `` element has the following parameters: - - [[nsa-intercept-url-access]] --* **access** --Lists the access attributes which will be stored in the `FilterInvocationSecurityMetadataSource` for the defined URL pattern/method combination. -+`access`:: -+Lists the access attributes, which are stored in the `FilterInvocationSecurityMetadataSource` for the defined URL pattern and method combination. - This should be a comma-separated list of the security configuration attributes (such as role names). - - - [[nsa-intercept-url-method]] --* **method** --The HTTP Method which will be used in combination with the pattern and servlet path (optional) to match an incoming request. --If omitted, any method will match. --If an identical pattern is specified with and without a method, the method-specific match will take precedence. -+`method`:: -+The HTTP Method that is used in combination with the pattern and servlet path (optional) to match an incoming request. -+If omitted, any method matchs. -+If an identical pattern is specified with and without a method, the method-specific match takes precedence. - - - [[nsa-intercept-url-pattern]] --* **pattern** --The pattern which defines the URL path. --The content will depend on the `request-matcher` attribute from the containing http element, so will default to ant path syntax. -+`pattern`:: -+The pattern that defines the URL path. -+The content depends on the `request-matcher` attribute from the containing `` element, so it defaults to Ant path syntax. - - - [[nsa-intercept-url-request-matcher-ref]] --* **request-matcher-ref** --A reference to a `RequestMatcher` that will be used to determine if this `` is used. -+`request-matcher-ref`:: -+A reference to a `RequestMatcher` that is used to determine if this `` is used. - - - [[nsa-intercept-url-requires-channel]] --* **requires-channel** --Can be "http" or "https" depending on whether a particular URL pattern should be accessed over HTTP or HTTPS respectively. --Alternatively the value "any" can be used when there is no preference. --If this attribute is present on any `` element, then a `ChannelProcessingFilter` will be added to the filter stack and its additional dependencies added to the application context. -+`requires-channel`:: -+Can be `http` or `https`, depending on whether a particular URL pattern should be accessed over HTTP or HTTPS, respectively. -+Alternatively, you can use a value of `any` when you have no preference. -+If this attribute is present on any `` element, a `ChannelProcessingFilter` is added to the filter stack and its additional dependencies are added to the application context. - --If a `` configuration is added, this will be used to by the `SecureChannelProcessor` and `InsecureChannelProcessor` beans to determine the ports used for redirecting to HTTP/HTTPS. -+If a `` configuration is added, it is used by the `SecureChannelProcessor` and `InsecureChannelProcessor` beans to determine the ports used for redirecting to HTTP and HTTPS. - --NOTE: This property is invalid for <> -+NOTE: This property is invalid for <> - - [[nsa-intercept-url-servlet-path]] --* **servlet-path** --The servlet path which will be used in combination with the pattern and HTTP method to match an incoming request. --This attribute is only applicable when <> is 'mvc'. --In addition, the value is only required in the following 2 use cases: 1) There are 2 or more `HttpServlet` 's registered in the `ServletContext` that have mappings starting with `'/'` and are different; 2) The pattern starts with the same value of a registered `HttpServlet` path, excluding the default (root) `HttpServlet` `'/'`. -+`servlet-path`:: -+The servlet path to be used, in combination with the pattern and HTTP method, to match an incoming request. -+This attribute is only applicable when <> is `mvc`. -+In addition, the value is only required in the following two use cases: -+* Two or more `HttpServlet` instances that have mappings starting with `/` and are different are registered in the `ServletContext`. -+* The pattern starts with the same value of a registered `HttpServlet` path, excluding the default (root) `HttpServlet` `/`. - --NOTE: This property is invalid for <> -+NOTE: This property is invalid for <> - - - [[nsa-jee]] - ==== --Adds a J2eePreAuthenticatedProcessingFilter to the filter chain to provide integration with container authentication. - - --[[nsa-jee-parents]] --===== Parent Elements of -+The `` element a dds a `J2eePreAuthenticatedProcessingFilter` to the filter chain to provide integration with container authentication. - - --* <> -+[[nsa-jee-parents]] -+===== Parent Elements of - -+The parent element of the `` element is the <`>> element. - - - [[nsa-jee-attributes]] - ===== Attributes - -+The `` element has the following attributes: - - [[nsa-jee-mappable-roles]] --* **mappable-roles** --A comma-separate list of roles to look for in the incoming HttpServletRequest. -+`mappable-roles`:: -+A comma-separated list of roles to look for in the incoming `HttpServletRequest`. - - - [[nsa-jee-user-service-ref]] --* **user-service-ref** --A reference to a user-service (or UserDetailsService bean) Id -+`user-service-ref`:: -+A reference to a user-service (or `UserDetailsService` bean) ID. - - - [[nsa-logout]] - ==== --Adds a `LogoutFilter` to the filter stack. --This is configured with a `SecurityContextLogoutHandler`. -+The `` element adds a `LogoutFilter` to the filter stack. -+It is configured by a `SecurityContextLogoutHandler`. - - - [[nsa-logout-parents]] - ===== Parent Elements of - -- --* <> -- -+The parent element of the `` element is the <`>> element. - - - [[nsa-logout-attributes]] - ===== Attributes - -+The `` element has the following attributes: - - [[nsa-logout-delete-cookies]] --* **delete-cookies** --A comma-separated list of the names of cookies which should be deleted when the user logs out. -+`delete-cookies`:: -+A comma-separated list of the names of cookies that should be deleted when the user logs out. - - - [[nsa-logout-invalidate-session]] --* **invalidate-session** -+`invalidate-session`:: - Maps to the `invalidateHttpSession` of the `SecurityContextLogoutHandler`. --Defaults to "true", so the session will be invalidated on logout. -+Default: `true` (the session is invalidated on logout) - - - [[nsa-logout-logout-success-url]] --* **logout-success-url** --The destination URL which the user will be taken to after logging out. --Defaults to /?logout (i.e. /login?logout) -- -+`logout-success-url`:: -+The destination URL to which the user is taken after logging out. -+Default: `/?logout` (usually `/login?logout`) - + -- --Setting this attribute will inject the `SessionManagementFilter` with a `SimpleRedirectInvalidSessionStrategy` configured with the attribute value. --When an invalid session ID is submitted, the strategy will be invoked, redirecting to the configured URL. -+Setting this attribute injects the `SessionManagementFilter` with a `SimpleRedirectInvalidSessionStrategy` configured with the attribute value. -+When an invalid session ID is submitted, the strategy is invoked, redirecting to the configured URL. - - - [[nsa-logout-logout-url]] --* **logout-url** --The URL which will cause a logout (i.e. which will be processed by the filter). --Defaults to "/logout". -+`logout-url`:: -+The URL that causes a logout (which is processed by the filter). -+Default: `/logout` - - - [[nsa-logout-success-handler-ref]] --* **success-handler-ref** --May be used to supply an instance of `LogoutSuccessHandler` which will be invoked to control the navigation after logging out. -+`success-handler-ref`:: -+Can be used to supply an instance of `LogoutSuccessHandler` that is invoked to control the navigation after logging out. - - - [[nsa-openid-login]] - ==== --Similar to `` and has the same attributes. --The default value for `login-processing-url` is "/login/openid". --An `OpenIDAuthenticationFilter` and `OpenIDAuthenticationProvider` will be registered. -+The `` element is similar to the `` element and has the same attributes. -+The default value for `login-processing-url` is `/login/openid`. -+An `OpenIDAuthenticationFilter` and a `OpenIDAuthenticationProvider` are registered. - The latter requires a reference to a `UserDetailsService`. --Again, this can be specified by `id`, using the `user-service-ref` attribute, or will be located automatically in the application context. -+You can specify this reference by `id`, by using the `user-service-ref` attribute, or you can let it be automatically located in the application context. - - - [[nsa-openid-login-parents]] - ===== Parent Elements of - -- --* <> -- -+The parent element of the `` element is the <`>> element. - - - [[nsa-openid-login-attributes]] - ===== Attributes - -+The `` element has the following attributes: - - [[nsa-openid-login-always-use-default-target]] --* **always-use-default-target** --Whether the user should always be redirected to the default-target-url after login. -+`always-use-default-target`:: -+Whether the user should always be redirected to the `default-target-url` after login. - - - [[nsa-openid-login-authentication-details-source-ref]] --* **authentication-details-source-ref** --Reference to an AuthenticationDetailsSource which will be used by the authentication filter -+`authentication-details-source-ref`:: -+Reference to an `AuthenticationDetailsSource` that is used by the authentication filter. - - - [[nsa-openid-login-authentication-failure-handler-ref]] --* **authentication-failure-handler-ref** --Reference to an AuthenticationFailureHandler bean which should be used to handle a failed authentication request. --Should not be used in combination with authentication-failure-url as the implementation should always deal with navigation to the subsequent destination -+`authentication-failure-handler-ref`:: -+Reference to an `AuthenticationFailureHandler` bean that should be used to handle a failed authentication request. -+It should not be used in combination with `authentication-failure-url`, as the implementation should always deal with navigation to the subsequent destination. - - - [[nsa-openid-login-authentication-failure-url]] --* **authentication-failure-url** -+authentication-failure-url:: - The URL for the login failure page. --If no login failure URL is specified, Spring Security will automatically create a failure login URL at /login?login_error and a corresponding filter to render that login failure URL when requested. -+If no login failure URL is specified, Spring Security automatically creates a failure login URL at `/login?login_error` and a corresponding filter to render that login failure URL when requested. - - - [[nsa-openid-login-authentication-success-forward-url]] --* **authentication-success-forward-url** -+authentication-success-forward-url:: - Maps a `ForwardAuthenticationSuccessHandler` to `authenticationSuccessHandler` property of `UsernamePasswordAuthenticationFilter`. - - - [[nsa-openid-login-authentication-failure-forward-url]] --* **authentication-failure-forward-url** -+`authentication-failure-forward-url`:: - Maps a `ForwardAuthenticationFailureHandler` to `authenticationFailureHandler` property of `UsernamePasswordAuthenticationFilter`. - - - [[nsa-openid-login-authentication-success-handler-ref]] --* **authentication-success-handler-ref** --Reference to an AuthenticationSuccessHandler bean which should be used to handle a successful authentication request. --Should not be used in combination with <> (or <>) as the implementation should always deal with navigation to the subsequent destination -+`authentication-success-handler-ref`:: -+Reference to an `AuthenticationSuccessHandler` bean that should be used to handle a successful authentication request. -+Should not be used in combination with <> (or <>) as the implementation should always deal with navigation to the subsequent destination - - - [[nsa-openid-login-default-target-url]] --* **default-target-url** --The URL that will be redirected to after successful authentication, if the user's previous action could not be resumed. -+`default-target-url`:: -+The URL to which to redirect after successful authentication, if the user's previous action could not be resumed. - This generally happens if the user visits a login page without having first requested a secured operation that triggers authentication. --If unspecified, defaults to the root of the application. -+If unspecified, it defaults to the root of the application. - - - [[nsa-openid-login-login-page]] --* **login-page** -+`login-page`:: - The URL for the login page. --If no login URL is specified, Spring Security will automatically create a login URL at /login and a corresponding filter to render that login URL when requested. -+If no login URL is specified, Spring Security automatically creates a login URL at `/login` and a corresponding filter to render that login URL when requested. - - - [[nsa-openid-login-login-processing-url]] --* **login-processing-url** --The URL that the login form is posted to. --If unspecified, it defaults to /login. -+`login-processing-url`:: -+The URL to which the login form is posted. -+If unspecified, it defaults to `/login`. - - - [[nsa-openid-login-password-parameter]] --* **password-parameter** --The name of the request parameter which contains the password. --Defaults to "password". -+`password-parameter`:: -+The name of the request parameter that contains the password. -+Default: `password` - - - [[nsa-openid-login-user-service-ref]] --* **user-service-ref** --A reference to a user-service (or UserDetailsService bean) Id -+`user-service-ref`:: -+A reference to a user-service (or `UserDetailsService` bean) ID - - - [[nsa-openid-login-username-parameter]] --* **username-parameter** --The name of the request parameter which contains the username. --Defaults to "username". -+`username-parameter`:: -+The name of the request parameter that contains the username. -+Default: `username` - - - [[nsa-openid-login-children]] - ===== Child Elements of --* <> - -+The `` element has only one child attribute: <`>>. - - - [[nsa-attribute-exchange]] --==== --The `attribute-exchange` element defines the list of attributes which should be requested from the identity provider. --An example can be found in the <> section of the namespace configuration chapter. --More than one can be used, in which case each must have an `identifier-match` attribute, containing a regular expression which is matched against the supplied OpenID identifier. --This allows different attribute lists to be fetched from different providers (Google, Yahoo etc). -+==== Element -+The `` element defines the list of attributes to request from the identity provider. -+You can find an example in the <> section of the namespace configuration chapter. -+You can use more than one. In that case, each must have an `identifier-match` attribute that contains a regular expression, which is matched against the supplied OpenID identifier. -+This lets different attribute lists be fetched from different providers (Google, Yahoo, and others). - - - [[nsa-attribute-exchange-parents]] - ===== Parent Elements of - -- --* <> -- -+The parent element of the `` element is the <`>> element. - - - [[nsa-attribute-exchange-attributes]] - ===== Attributes - -+The `` element has a single attribute: -+ - - [[nsa-attribute-exchange-identifier-match]] --* **identifier-match** --A regular expression which will be compared against the claimed identity, when deciding which attribute-exchange configuration to use during authentication. -+`identifier-match`:: -+A regular expression that is compared against the claimed identity when deciding which `attribute-exchange` configuration to use during authentication. - - - [[nsa-attribute-exchange-children]] - ===== Child Elements of - -- --* <> -- -+The `` element has a single child attribute: <`>>. - - - [[nsa-openid-attribute]] - ==== --Attributes used when making an OpenID AX https://openid.net/specs/openid-attribute-exchange-1_0.html#fetch_request[ Fetch Request] -+The `` element defines the attributes to use when making an OpenID AX https://openid.net/specs/openid-attribute-exchange-1_0.html#fetch_request[ Fetch Request]. - - - [[nsa-openid-attribute-parents]] - ===== Parent Elements of - -- --* <> -- -+The parent element of the `` element is the <> element. - - - [[nsa-openid-attribute-attributes]] - ===== Attributes - -+The `` element has the following attributes: - - [[nsa-openid-attribute-count]] --* **count** --Specifies the number of attributes that you wish to get back. --For example, return 3 emails. --The default value is 1. -+`count`:: -+Specifies the number of attributes that you wish to get back -- for example, return three emails. -+Default: 1 - - - [[nsa-openid-attribute-name]] --* **name** --Specifies the name of the attribute that you wish to get back. --For example, email. -+`name`:: -+Specifies the name of the attribute that you wish to get back -- for example, `email`. - - - [[nsa-openid-attribute-required]] --* **required** --Specifies if this attribute is required to the OP, but does not error out if the OP does not return the attribute. --Default is false. -+`required`:: -+Specifies whether this attribute is required to the OP but does not error out if the OP does not return the attribute. -+Default: `false` - - - [[nsa-openid-attribute-type]] --* **type** --Specifies the attribute type. --For example, https://axschema.org/contact/email. -+`type`:: -+Specifies the attribute type -- for example, `https://axschema.org/contact/email`. - See your OP's documentation for valid attribute types. - - - [[nsa-port-mappings]] --==== --By default, an instance of `PortMapperImpl` will be added to the configuration for use in redirecting to secure and insecure URLs. --This element can optionally be used to override the default mappings which that class defines. -+==== Element -+By default, an instance of `PortMapperImpl` is added to the configuration for use in redirecting to secure and insecure URLs. -+You can optionally use the `` element to override the default mappings that `PortMapperImpl` defines. - Each child `` element defines a pair of HTTP:HTTPS ports. --The default mappings are 80:443 and 8080:8443. --An example of overriding these can be found in <>. -+The default mappings are `80:443` and `8080:8443`. -+You can find an example of overriding these values in <>. - - - [[nsa-port-mappings-parents]] --===== Parent Elements of -- -- --* <> -+===== Parent Element of - -+The parent element of the `` element is the <`>> element. - - - [[nsa-port-mappings-children]] - ===== Child Elements of - -- --* <> -- -+The `` element has a single child element: <>. - - - [[nsa-port-mapping]] - ==== --Provides a method to map http ports to https ports when forcing a redirect. -+The `` element provides a method to map HTTP ports to HTTPS ports when forcing a redirect. - - - [[nsa-port-mapping-parents]] - ===== Parent Elements of - -- --* <> -+The parent element of the `` element is the <`>> element. - - - - [[nsa-port-mapping-attributes]] - ===== Attributes - -+The `` element has the following attributes: - - [[nsa-port-mapping-http]] --* **http** --The http port to use. -+`http`:: -+The HTTP port to use. - - - [[nsa-port-mapping-https]] --* **https** --The https port to use. -+`https`:: -+The HTTPS port to use. - - - [[nsa-remember-me]] - ==== --Adds the `RememberMeAuthenticationFilter` to the stack. --This in turn will be configured with either a `TokenBasedRememberMeServices`, a `PersistentTokenBasedRememberMeServices` or a user-specified bean implementing `RememberMeServices` depending on the attribute settings. -+The `` element adds the `RememberMeAuthenticationFilter` to the stack. -+This filter is, in turn, configured with either a `TokenBasedRememberMeServices`, a `PersistentTokenBasedRememberMeServices`, or a user-specified bean that implements `RememberMeServices`, depending on the attribute settings. - - - [[nsa-remember-me-parents]] - ===== Parent Elements of - -- --* <> -- -+The parent element of the `` element is the <`>> element. - - - [[nsa-remember-me-attributes]] - ===== Attributes - -+The `` element has the following attributes: - - [[nsa-remember-me-authentication-success-handler-ref]] --* **authentication-success-handler-ref** --Sets the `authenticationSuccessHandler` property on the `RememberMeAuthenticationFilter` if custom navigation is required. -+`authentication-success-handler-ref`:: -+Sets the `authenticationSuccessHandler` property on the `RememberMeAuthenticationFilter` when custom navigation is required. - The value should be the name of a `AuthenticationSuccessHandler` bean in the application context. - - - [[nsa-remember-me-data-source-ref]] --* **data-source-ref** -+`data-source-ref`:: - A reference to a `DataSource` bean. --If this is set, `PersistentTokenBasedRememberMeServices` will be used and configured with a `JdbcTokenRepositoryImpl` instance. -+If this attribute is set, `PersistentTokenBasedRememberMeServices` is used and configured with a `JdbcTokenRepositoryImpl` instance. - - - [[nsa-remember-me-remember-me-parameter]] --* **remember-me-parameter** --The name of the request parameter which toggles remember-me authentication. --Defaults to "remember-me". --Maps to the "parameter" property of `AbstractRememberMeServices`. -+`remember-me-parameter`:: -+The name of the request parameter that toggles remember-me authentication. -+Defaults: `remember-me` -+Maps to the `parameter` property of `AbstractRememberMeServices`. - - - [[nsa-remember-me-remember-me-cookie]] --* **remember-me-cookie** --The name of cookie which store the token for remember-me authentication. --Defaults to "remember-me". --Maps to the "cookieName" property of `AbstractRememberMeServices`. -+`remember-me-cookie`:: -+The name of the cookie that stores the token for remember-me authentication. -+Defaults: `remember-me` -+This attribute maps to the `cookieName` property of `AbstractRememberMeServices`. - - - [[nsa-remember-me-key]] --* **key** --Maps to the "key" property of `AbstractRememberMeServices`. --Should be set to a unique value to ensure that remember-me cookies are only valid within the one application footnote:[ --This doesn't affect the use of `PersistentTokenBasedRememberMeServices`, where the tokens are stored on the server side. --]. --If this is not set a secure random value will be generated. --Since generating secure random values can take a while, setting this value explicitly can help improve startup times when using the remember-me functionality. -+`key`:: -+Maps to the `key` property of `AbstractRememberMeServices`. -+Should be set to a unique value to ensure that remember-me cookies are valid only within one application -+This key does not affect the use of `PersistentTokenBasedRememberMeServices`, where the tokens are stored on the server side. -+If this key is not set, a secure random value is generated. -+Since generating secure random values can take a while, explicitly setting this value can help improve startup times when you use the remember-me functionality. - - - [[nsa-remember-me-services-alias]] --* **services-alias** --Exports the internally defined `RememberMeServices` as a bean alias, allowing it to be used by other beans in the application context. -+`services-alias`:: -+Exports the internally defined `RememberMeServices` as a bean alias, letting it be used by other beans in the application context. - - - [[nsa-remember-me-services-ref]] --* **services-ref** --Allows complete control of the `RememberMeServices` implementation that will be used by the filter. --The value should be the `id` of a bean in the application context which implements this interface. --Should also implement `LogoutHandler` if a logout filter is in use. -+`services-ref`:: -+Allows complete control of the `RememberMeServices` implementation that is used by the filter. -+The value should be the `id` of a bean in the application context that implements this interface. -+It should also implement `LogoutHandler` if a logout filter is in use. - - - [[nsa-remember-me-token-repository-ref]] --* **token-repository-ref** -+`token-repository-ref`:: - Configures a `PersistentTokenBasedRememberMeServices` but allows the use of a custom `PersistentTokenRepository` bean. - - - [[nsa-remember-me-token-validity-seconds]] --* **token-validity-seconds** -+`token-validity-seconds`:: - Maps to the `tokenValiditySeconds` property of `AbstractRememberMeServices`. - Specifies the period in seconds for which the remember-me cookie should be valid. --By default it will be valid for 14 days. -+By default, it is valid for 14 days. - - - [[nsa-remember-me-use-secure-cookie]] --* **use-secure-cookie** --It is recommended that remember-me cookies are only submitted over HTTPS and thus should be flagged as "secure". --By default, a secure cookie will be used if the connection over which the login request is made is secure (as it should be). --If you set this property to `false`, secure cookies will not be used. --Setting it to `true` will always set the secure flag on the cookie. -+`use-secure-cookie`:: -+We recommend that you submit remember-me cookies over HTTPS and that you flag as "`secure`". -+By default, a secure cookie is used if the connection for the login request is secure (as it should be). -+If you set this property to `false`, secure cookies are not used. -+Setting it to `true` always sets the secure flag on the cookie. - This attribute maps to the `useSecureCookie` property of `AbstractRememberMeServices`. - - - [[nsa-remember-me-user-service-ref]] --* **user-service-ref** -+`user-service-ref`:: - The remember-me services implementations require access to a `UserDetailsService`, so there has to be one defined in the application context. --If there is only one, it will be selected and used automatically by the namespace configuration. --If there are multiple instances, you can specify a bean `id` explicitly using this attribute. -+If there is only one, it is selected and automatically used by the namespace configuration. -+If there are multiple instances, you can specify a bean `id` explicitly by setting this attribute. - - - [[nsa-request-cache]] - ==== Element --Sets the `RequestCache` instance which will be used by the `ExceptionTranslationFilter` to store request information before invoking an `AuthenticationEntryPoint`. -+Sets the `RequestCache` instance, which is used by the `ExceptionTranslationFilter` to store request information before invoking an `AuthenticationEntryPoint`. - - - [[nsa-request-cache-parents]] - ===== Parent Elements of - --* <> -+The parent element of the `` element is the <`>> element. - - [[nsa-request-cache-attributes]] - ===== Attributes - -+The `` element has only one attribute: - - [[nsa-request-cache-ref]] --* **ref** -+`ref`:: - Defines a reference to a Spring bean that is a `RequestCache`. - - - [[nsa-session-management]] - ==== --Session-management related functionality is implemented by the addition of a `SessionManagementFilter` to the filter stack. -+Session-management functionality is implemented by the addition of a `SessionManagementFilter` to the filter stack. This element adds that filter. - - - [[nsa-session-management-parents]] - ===== Parent Elements of - - --* <> -- -+The parent element of the `` element is the <`>> element. - - - [[nsa-session-management-attributes]] - ===== Attributes - -+The `` has the following attributes: - - [[nsa-session-management-invalid-session-url]] --* **invalid-session-url** --Setting this attribute will inject the `SessionManagementFilter` with a `SimpleRedirectInvalidSessionStrategy` configured with the attribute value. --When an invalid session ID is submitted, the strategy will be invoked, redirecting to the configured URL. -+`invalid-session-url`:: -+Setting this attribute injects a `SessionManagementFilter` with a `SimpleRedirectInvalidSessionStrategy` that is configured with the attribute value. -+When an invalid session ID is submitted, the strategy is invoked, redirecting to the configured URL. - - [[nsa-session-management-invalid-session-strategy-ref]] --* **invalid-session-url** --Allows injection of the InvalidSessionStrategy instance used by the SessionManagementFilter. --Use either this or the `invalid-session-url` attribute but not both. -+`invalid-session-url`:: -+Allows injection of the `InvalidSessionStrategy` instance, which is used by the `SessionManagementFilter`. -+Use either this attribute or the `invalid-session-url` attribute but not both. - - [[nsa-session-management-session-authentication-error-url]] --* **session-authentication-error-url** --Defines the URL of the error page which should be shown when the SessionAuthenticationStrategy raises an exception. --If not set, an unauthorized (401) error code will be returned to the client. --Note that this attribute doesn't apply if the error occurs during a form-based login, where the URL for authentication failure will take precedence. -+`session-authentication-error-url` -+Defines the URL of the error page, which should be shown when the `SessionAuthenticationStrategy` raises an exception. -+If not set, an unauthorized (401) error code is returned to the client. -+Note that this attribute does not apply if the error occurs during a form-based login, where the URL for authentication failure takes precedence. - - - [[nsa-session-management-session-authentication-strategy-ref]] --* **session-authentication-strategy-ref** --Allows injection of the SessionAuthenticationStrategy instance used by the SessionManagementFilter -+`session-authentication-strategy-ref`:: -+Allows injection of a `SessionAuthenticationStrategy` instance, which is used by the `SessionManagementFilter`. - - - [[nsa-session-management-session-fixation-protection]] --* **session-fixation-protection** --Indicates how session fixation protection will be applied when a user authenticates. --If set to "none", no protection will be applied. --"newSession" will create a new empty session, with only Spring Security-related attributes migrated. --"migrateSession" will create a new session and copy all session attributes to the new session. --In Servlet 3.1 (Java EE 7) and newer containers, specifying "changeSessionId" will keep the existing session and use the container-supplied session fixation protection (HttpServletRequest#changeSessionId()). --Defaults to "changeSessionId" in Servlet 3.1 and newer containers, "migrateSession" in older containers. --Throws an exception if "changeSessionId" is used in older containers. -- --+ -- -+session-fixation-protection:: -+Indicates how session fixation protection is applied when a user authenticates. -+If set to `none`, no protection is applied. -+`newSession` creates a new empty session, with only Spring Security-related attributes migrated. -+`migrateSession` creates a new session and copies all session attributes to the new session. -+In Servlet 3.1 (Java EE 7) and newer containers, specifying `changeSessionId` keeps the existing session and uses the container-supplied session fixation protection (`HttpServletRequest#changeSessionId()`). -+It defaults to `changeSessionId` in Servlet 3.1 and newer containers, `migrateSession` in older containers. -+It throws an exception if `changeSessionId` is used in older containers. - If session fixation protection is enabled, the `SessionManagementFilter` is injected with an appropriately configured `DefaultSessionAuthenticationStrategy`. --See the Javadoc for this class for more details. -+See the {security-api-url}org/springframework/security/web/session/SessionManagementFilter.html[Javadoc for `SessionManagementFilter`] for more details. - - - [[nsa-session-management-children]] - ===== Child Elements of - -- --* <> -- -+The `` element has only one child element: <`>> - - - [[nsa-concurrency-control]] - ==== --Adds support for concurrent session control, allowing limits to be placed on the number of active sessions a user can have. --A `ConcurrentSessionFilter` will be created, and a `ConcurrentSessionControlAuthenticationStrategy` will be used with the `SessionManagementFilter`. --If a `form-login` element has been declared, the strategy object will also be injected into the created authentication filter. --An instance of `SessionRegistry` (a `SessionRegistryImpl` instance unless the user wishes to use a custom bean) will be created for use by the strategy. -+The `` adds support for concurrent session control, letting limits be placed on the number of active sessions a user can have. -+A `ConcurrentSessionFilter` is created, and a `ConcurrentSessionControlAuthenticationStrategy` is used with the `SessionManagementFilter`. -+If a `form-login` element has been declared, the strategy object is also injected into the created authentication filter. -+An instance of `SessionRegistry` (a `SessionRegistryImpl` instance unless the user wishes to use a custom bean) is created for use by the strategy. - - - [[nsa-concurrency-control-parents]] - ===== Parent Elements of - -- --* <> -- -+The parent element of the `` element is the <`>> element. - - - [[nsa-concurrency-control-attributes]] - ===== Attributes - -+The `` element has the following attributes: -+ - - [[nsa-concurrency-control-error-if-maximum-exceeded]] --* **error-if-maximum-exceeded** --If set to "true" a `SessionAuthenticationException` will be raised when a user attempts to exceed the maximum allowed number of sessions. --The default behaviour is to expire the original session. -+`error-if-maximum-exceeded`:: -+If set to `true`, a `SessionAuthenticationException` is raised when a user attempts to exceed the maximum allowed number of sessions. -+The default behavior is to expire the original session. - - - [[nsa-concurrency-control-expired-url]] --* **expired-url** --The URL a user will be redirected to if they attempt to use a session which has been "expired" by the concurrent session controller because the user has exceeded the number of allowed sessions and has logged in again elsewhere. --Should be set unless `exception-if-maximum-exceeded` is set. --If no value is supplied, an expiry message will just be written directly back to the response. -+`expired-url`:: -+The URL to which a user is redirected if they attempt to use a session which has been "`expired`" by the concurrent session controller because the user has exceeded the number of allowed sessions and has logged in again elsewhere. -+This attribute should be set unless `exception-if-maximum-exceeded` is set. -+If no value is supplied, an expiry message is written directly back to the response. - - [[nsa-concurrency-control-expired-session-strategy-ref]] --* **expired-url** --Allows injection of the ExpiredSessionStrategy instance used by the ConcurrentSessionFilter -+`expired-url`:: -+Allows injection of an `ExpiredSessionStrategy` instance, which is used by the `ConcurrentSessionFilter`. - - [[nsa-concurrency-control-max-sessions]] --* **max-sessions** -+`max-sessions`:: - Maps to the `maximumSessions` property of `ConcurrentSessionControlAuthenticationStrategy`. - Specify `-1` as the value to support unlimited sessions. - - - [[nsa-concurrency-control-session-registry-alias]] --* **session-registry-alias** -+`session-registry-alias`:: -+Exposes an internal bean and gives it a name that you use elsewhere in your configuration - It can also be useful to have a reference to the internal session registry for use in your own beans or an admin interface. --You can expose the internal bean using the `session-registry-alias` attribute, giving it a name that you can use elsewhere in your configuration. - - - [[nsa-concurrency-control-session-registry-ref]] --* **session-registry-ref** --The user can supply their own `SessionRegistry` implementation using the `session-registry-ref` attribute. --The other concurrent session control beans will be wired up to use it. -+`session-registry-ref`:: -+Specifies a `SessionRegistry` implementation to use. -+The other concurrent session control beans are wired up to use it. - - - [[nsa-x509]] - ==== --Adds support for X.509 authentication. --An `X509AuthenticationFilter` will be added to the stack and an `Http403ForbiddenEntryPoint` bean will be created. --The latter will only be used if no other authentication mechanisms are in use (its only functionality is to return an HTTP 403 error code). --A `PreAuthenticatedAuthenticationProvider` will also be created which delegates the loading of user authorities to a `UserDetailsService`. -+The `` element adds support for X.509 authentication. -+An `X509AuthenticationFilter` is added to the stack, and an `Http403ForbiddenEntryPoint` bean is created. -+The latter is used only if no other authentication mechanisms are in use. (Its only functionality is to return an HTTP 403 error code.) -+A `PreAuthenticatedAuthenticationProvider` is also created. It delegates the loading of user authorities to a `UserDetailsService`. - - - [[nsa-x509-parents]] - ===== Parent Elements of - -- --* <> -- -+The parent element of the `` element is the <`>> element. - - - [[nsa-x509-attributes]] - ===== Attributes - -+The `` element has the following attributes: - - [[nsa-x509-authentication-details-source-ref]] --* **authentication-details-source-ref** --A reference to an `AuthenticationDetailsSource` -+`authentication-details-source-ref`:: -+A reference to an `AuthenticationDetailsSource`. - - - [[nsa-x509-subject-principal-regex]] --* **subject-principal-regex** --Defines a regular expression which will be used to extract the username from the certificate (for use with the `UserDetailsService`). -+`subject-principal-regex`:: -+Defines a regular expression, which is used to extract the username from the certificate (for use with the `UserDetailsService`). - - - [[nsa-x509-user-service-ref]] --* **user-service-ref** --Allows a specific `UserDetailsService` to be used with X.509 in the case where multiple instances are configured. --If not set, an attempt will be made to locate a suitable instance automatically and use that. -+`user-service-ref`:: -+Lets a specific `UserDetailsService` be used with X.509 when where multiple instances are configured. -+If not set, an attempt is made to locate a suitable instance automatically and use that. - - - [[nsa-filter-chain-map]] - ==== --Used to explicitly configure a FilterChainProxy instance with a FilterChainMap -+The `` explicitly configures a `FilterChainProxy` instance with a `FilterChainMap`. - - - [[nsa-filter-chain-map-attributes]] - ===== Attributes - -+The `` element has one attribute: -+ - - [[nsa-filter-chain-map-request-matcher]] --* **request-matcher** -+`request-matcher`:: - Defines the strategy to use for matching incoming requests. --Currently the options are 'ant' (for ant path patterns), 'regex' for regular expressions and 'ciRegex' for case-insensitive regular expressions. -+Currently, the options are `ant` (for Ant path patterns), `regex` (for regular expressions), and `ciRegex` (for case-insensitive regular expressions). - - - [[nsa-filter-chain-map-children]] - ===== Child Elements of - -- --* <> -- -+The `` element has one child element: <`>>. - - - [[nsa-filter-chain]] - ==== --Used within to define a specific URL pattern and the list of filters which apply to the URLs matching that pattern. --When multiple filter-chain elements are assembled in a list in order to configure a FilterChainProxy, the most specific patterns must be placed at the top of the list, with most general ones at the bottom. -+ -+The `` element is used within a `` to define a specific URL pattern and the list of filters that apply to the URLs that match that pattern. -+When multiple `` elements are assembled in a list, to configure a `FilterChainProxy`, the most specific patterns must be placed at the top of the list, with the most general ones at the bottom. - - - [[nsa-filter-chain-parents]] - ===== Parent Elements of - -- --* <> -- -+The parent element of the `` element is the <`>> element. - - - [[nsa-filter-chain-attributes]] - ===== Attributes - -+The `` element has the following attributes: - - [[nsa-filter-chain-filters]] --* **filters** --A comma separated list of references to Spring beans that implement `Filter`. --The value "none" means that no `Filter` should be used for this `FilterChain`. -+`filters`:: -+A comma-separated list of references to Spring beans that implement `Filter`. -+A value of `none` means that no `Filter` should be used for this `FilterChain`. - - - [[nsa-filter-chain-pattern]] --* **pattern** --A pattern that creates RequestMatcher in combination with the <> -+`pattern`:: -+A pattern that creates `RequestMatcher` in combination with the <`>> element. - - - [[nsa-filter-chain-request-matcher-ref]] --* **request-matcher-ref** --A reference to a `RequestMatcher` that will be used to determine if any `Filter` from the `filters` attribute should be invoked. -+`request-matcher-ref`:: -+A reference to a `RequestMatcher` that is used to determine if any `Filter` from the `filters` attribute should be invoked. - - - [[nsa-filter-security-metadata-source]] --==== --Used to explicitly configure a FilterSecurityMetadataSource bean for use with a FilterSecurityInterceptor. --Usually only needed if you are configuring a FilterChainProxy explicitly, rather than using the element. --The intercept-url elements used should only contain pattern, method and access attributes. --Any others will result in a configuration error. -+==== Element -+The `` is used to explicitly configure a `FilterSecurityMetadataSource` bean for use with a `FilterSecurityInterceptor`. -+The `` is usually only needed if you explicitly configure a `FilterChainProxy` rather than use the `` element. -+The `` elements should contain only pattern, method, and access attributes. -+Any others result in a configuration error. - - - [[nsa-filter-security-metadata-source-attributes]] - ===== Attributes - -+The `` element has the following attributes: - - [[nsa-filter-security-metadata-source-id]] --* **id** --A bean identifier, used for referring to the bean elsewhere in the context. -+`id`:: -+A bean identifier, which is used for referring to the bean elsewhere in the context. - - - [[nsa-filter-security-metadata-source-request-matcher]] --* **request-matcher** -+`request-matcher`:: - Defines the strategy use for matching incoming requests. --Currently the options are 'ant' (for ant path patterns), 'regex' for regular expressions and 'ciRegex' for case-insensitive regular expressions. -+Currently the options are `ant` (for Ant path patterns), `regex` (for regular expressions), and `ciRegex` (for case-insensitive regular expressions). - - - [[nsa-filter-security-metadata-source-use-expressions]] --* **use-expressions** --Enables the use of expressions in the 'access' attributes in elements rather than the traditional list of configuration attributes. --Defaults to 'true'. -+use-expressions:: -+Enables the use of expressions in the `access` attributes in `` elements rather than the traditional list of configuration attributes. -+Default: `true` - If enabled, each attribute should contain a single Boolean expression. --If the expression evaluates to 'true', access will be granted. -+If the expression evaluates to `true`, access is granted. - - - [[nsa-filter-security-metadata-source-children]] - ===== Child Elements of - -- --* <> -+The `` has a single child element: <`>>. - - [[nsa-websocket-security]] - === WebSocket Security -@@ -1997,145 +2021,160 @@ Spring Security 4.0+ provides support for authorizing messages. - One concrete example of where this is useful is to provide authorization in WebSocket based applications. - - [[nsa-websocket-message-broker]] --==== -+==== Element - --The websocket-message-broker element has two different modes. --If the <> is not specified, then it will do the following things: -+The `` element has two different modes. -+If the <> is not specified, it does the following things: - --* Ensure that any SimpAnnotationMethodMessageHandler has the AuthenticationPrincipalArgumentResolver registered as a custom argument resolver. --This allows the use of `@AuthenticationPrincipal` to resolve the principal of the current `Authentication` --* Ensures that the SecurityContextChannelInterceptor is automatically registered for the clientInboundChannel. --This populates the SecurityContextHolder with the user that is found in the Message --* Ensures that a ChannelSecurityInterceptor is registered with the clientInboundChannel. -+* Ensure that any `SimpAnnotationMethodMessageHandler` has the `AuthenticationPrincipalArgumentResolver` registered as a custom argument resolver. -+This allows the use of `@AuthenticationPrincipal` to resolve the principal of the current `Authentication`. -+* Ensures that the `SecurityContextChannelInterceptor` is automatically registered for the `clientInboundChannel`. -+This populates the `SecurityContextHolder` with the user that is found in the message. -+* Ensures that a `ChannelSecurityInterceptor` is registered with the `clientInboundChannel`. - This allows authorization rules to be specified for a message. --* Ensures that a CsrfChannelInterceptor is registered with the clientInboundChannel. -+* Ensures that a `CsrfChannelInterceptor` is registered with the `clientInboundChannel`. - This ensures that only requests from the original domain are enabled. --* Ensures that a CsrfTokenHandshakeInterceptor is registered with WebSocketHttpRequestHandler, TransportHandlingSockJsService, or DefaultSockJsService. --This ensures that the expected CsrfToken from the HttpServletRequest is copied into the WebSocket Session attributes. -+* Ensures that a `CsrfTokenHandshakeInterceptor` is registered with a `WebSocketHttpRequestHandler`, a `TransportHandlingSockJsService`, or a `DefaultSockJsService`. -+This ensures that the expected `CsrfToken` from the `HttpServletRequest` is copied into the WebSocket Session attributes. - --If additional control is necessary, the id can be specified and a ChannelSecurityInterceptor will be assigned to the specified id. --All the wiring with Spring's messaging infrastructure can then be done manually. --This is more cumbersome, but provides greater control over the configuration. -+If additional control is necessary, you can specify the ID, and a `ChannelSecurityInterceptor` is assigned to the specified ID. -+You can then manually wire Spring's messaging infrastructure. -+This is more cumbersome, but doing so provides greater control over the configuration. - - - [[nsa-websocket-message-broker-attributes]] - ===== Attributes - -+The `` element has the following attributes: -+ - [[nsa-websocket-message-broker-id]] --* **id** A bean identifier, used for referring to the ChannelSecurityInterceptor bean elsewhere in the context. -+`id`:: -+A bean identifier, used to refer to the `ChannelSecurityInterceptor` bean elsewhere in the context. - If specified, Spring Security requires explicit configuration within Spring Messaging. --If not specified, Spring Security will automatically integrate with the messaging infrastructure as described in <> -+If not specified, Spring Security automatically integrates with the messaging infrastructure, as described in <> - - [[nsa-websocket-message-broker-same-origin-disabled]] --* **same-origin-disabled** Disables the requirement for CSRF token to be present in the Stomp headers (default false). --Changing the default is useful if it is necessary to allow other origins to make SockJS connections. -+`same-origin-disabled`:: -+Disables the requirement for a CSRF token to be present in the Stomp headers. -+Default: `false` -+Changing the default lets other origins make SockJS connections. - - [[nsa-websocket-message-broker-children]] - ===== Child Elements of - -+The `` element has the following child elements: - --* <> --* <> -+* <`>> -+* <`>> - - [[nsa-intercept-message]] --==== -+==== Element - --Defines an authorization rule for a message. -+The `` defines an authorization rule for a message. - - - [[nsa-intercept-message-parents]] - ===== Parent Elements of - -- --* <> -+The parent element of the `` element is the <> element. - - - [[nsa-intercept-message-attributes]] - ===== Attributes - -+The `` element has the following attributes: -+ - [[nsa-intercept-message-pattern]] --* **pattern** An ant based pattern that matches on the Message destination. --For example, "/**" matches any Message with a destination; "/admin/**" matches any Message that has a destination that starts with "/admin/**". -+`pattern`:: -+An Ant-based pattern that matches on the message destination. -+For example, `/**` matches any message with a destination, while `/admin/**` matches any message that has a destination that starts with `/admin/`. - - [[nsa-intercept-message-type]] --* **type** The type of message to match on. --Valid values are defined in SimpMessageType (i.e. CONNECT, CONNECT_ACK, HEARTBEAT, MESSAGE, SUBSCRIBE, UNSUBSCRIBE, DISCONNECT, DISCONNECT_ACK, OTHER). -+`type`:: -+The type of message to match on. -+SimpMessageType defines the valid values: `CONNECT`, `CONNECT_ACK`, `HEARTBEAT`, `MESSAGE`, `SUBSCRIBE`, `UNSUBSCRIBE`, `DISCONNECT`, `DISCONNECT_ACK`, and `OTHER`). - - [[nsa-intercept-message-access]] --* **access** The expression used to secure the Message. --For example, "denyAll" will deny access to all of the matching Messages; "permitAll" will grant access to all of the matching Messages; "hasRole('ADMIN') requires the current user to have the role 'ROLE_ADMIN' for the matching Messages. -+`access`:: -+The expression used to secure the message. -+Here are some examples: -++ -+* `denyAll`: Denies access to all of the matching messages. -+* `permitAll`: Grants access to all of the matching Messages. -+* `hasRole('ADMIN')`: Requires the current user to have a role of `ROLE_ADMIN` for the matching messages. - - [[nsa-authentication]] - === Authentication Services - Before Spring Security 3.0, an `AuthenticationManager` was automatically registered internally. --Now you must register one explicitly using the `` element. --This creates an instance of Spring Security's `ProviderManager` class, which needs to be configured with a list of one or more `AuthenticationProvider` instances. --These can either be created using syntax elements provided by the namespace, or they can be standard bean definitions, marked for addition to the list using the `authentication-provider` element. -+Now you must register one explicitly by using the `` element. -+Doing so creates an instance of Spring Security's `ProviderManager` class, which needs to be configured with a list of one or more `AuthenticationProvider` instances. -+You can create these instances either by using syntax elements provided by the namespace or by using standard bean definitions, marked for addition to the list by using the `authentication-provider` element. - - - [[nsa-authentication-manager]] --==== --Every Spring Security application which uses the namespace must have include this element somewhere. --It is responsible for registering the `AuthenticationManager` which provides authentication services to the application. --All elements which create `AuthenticationProvider` instances should be children of this element. -+==== Element -+Every Spring Security application that uses the namespace must include the `` element somewhere. -+It is responsible for registering the `AuthenticationManager`, which provides authentication services to the application. -+All elements that create `AuthenticationProvider` instances should be children of this element. - - - [[nsa-authentication-manager-attributes]] - ===== Attributes - -+The `` element has the following attributes: - - [[nsa-authentication-manager-alias]] --* **alias** --This attribute allows you to define an alias name for the internal instance for use in your own configuration. -+`alias`:: -+This attribute lets you define an alias name for the internal instance to use in your own configuration. - - - [[nsa-authentication-manager-erase-credentials]] --* **erase-credentials** --If set to true, the AuthenticationManager will attempt to clear any credentials data in the returned Authentication object, once the user has been authenticated. --Literally it maps to the `eraseCredentialsAfterAuthentication` property of the <>. -+`erase-credentials`:: -+If set to `true`, the `AuthenticationManager` tries to clear any credentials data in the returned `Authentication` object, once the user has been authenticated. -+Literally, it maps to the `eraseCredentialsAfterAuthentication` property of the <>. - - - [[nsa-authentication-manager-id]] --* **id** --This attribute allows you to define an id for the internal instance for use in your own configuration. --It is the same as the alias element, but provides a more consistent experience with elements that use the id attribute. -+`id`:: -+This attribute lets you define an ID for the internal instance to use in your own configuration. -+It is the same as the `alias` element but provides a more consistent experience with elements that use the `id` attribute. - - - [[nsa-authentication-manager-children]] - ===== Child Elements of - -+The `` element has the following child elements: - --* <> --* <> -+* <`>> -+* <`>> - - - - [[nsa-authentication-provider]] --==== --Unless used with a `ref` attribute, this element is shorthand for configuring a `DaoAuthenticationProvider`. --`DaoAuthenticationProvider` loads user information from a `UserDetailsService` and compares the username/password combination with the values supplied at login. --The `UserDetailsService` instance can be defined either by using an available namespace element (`jdbc-user-service` or by using the `user-service-ref` attribute to point to a bean defined elsewhere in the application context). -- -+==== Element -+Unless used with a `ref` attribute, the `` element is shorthand for configuring a `DaoAuthenticationProvider`. -+A `DaoAuthenticationProvider` loads user information from a `UserDetailsService` and compares the username and password combination with the values supplied at login. -+You can define the `UserDetailsService` instance either by using an available namespace element (`jdbc-user-service`) or by using the `user-service-ref` attribute to point to a bean defined elsewhere in the application context. - - - [[nsa-authentication-provider-parents]] - ===== Parent Elements of - -- --* <> -- -+The parent element of the `` element is the <`>> element. - - - [[nsa-authentication-provider-attributes]] - ===== Attributes - -+The `` element has the following attributes: - - [[nsa-authentication-provider-ref]] --* **ref** -+ref:: - Defines a reference to a Spring bean that implements `AuthenticationProvider`. -- --If you have written your own `AuthenticationProvider` implementation (or want to configure one of Spring Security's own implementations as a traditional bean for some reason, then you can use the following syntax to add it to the internal list of `ProviderManager`: -- -++ -+If you have written your own `AuthenticationProvider` implementation (or want to configure one of Spring Security's implementations as a traditional bean for some reason), you can use the following syntax to add it to the internal list of `ProviderManager`: -++ -+==== - [source,xml] - ---- - -@@ -2145,66 +2184,63 @@ If you have written your own `AuthenticationProvider` implementation (or want to - - - ---- -- -- -+==== - - - [[nsa-authentication-provider-user-service-ref]] --* **user-service-ref** --A reference to a bean that implements UserDetailsService that may be created using the standard bean element or the custom user-service element. -+`user-service-ref`:: -+A reference to a bean that implements `UserDetailsService`, which may be created by using the standard bean element or the custom user-service element. - - - [[nsa-authentication-provider-children]] - ===== Child Elements of - -+The `` element has the following child elements: - --* <> --* <> --* <> --* <> -- -+* <`>> -+* <`>> -+* <`>> -+* <`>> - - - [[nsa-jdbc-user-service]] - ==== --Causes creation of a JDBC-based UserDetailsService. -+The `` element causes the creation of a JDBC-based `UserDetailsService`. - - - [[nsa-jdbc-user-service-attributes]] - ===== Attributes - -+The `` element has the following attributes: - - [[nsa-jdbc-user-service-authorities-by-username-query]] --* **authorities-by-username-query** -+`authorities-by-username-query`:: - An SQL statement to query for a user's granted authorities given a username. -- --The default is -- -++ -+The default is as follows: -+==== - [source] - ---- - select username, authority from authorities where username = ? - ---- -- -- -- -+==== - - [[nsa-jdbc-user-service-cache-ref]] --* **cache-ref** --Defines a reference to a cache for use with a UserDetailsService. -+`cache-ref`:: -+Defines a reference to a cache for use with a `UserDetailsService`. - - - [[nsa-jdbc-user-service-data-source-ref]] --* **data-source-ref** --The bean ID of the DataSource which provides the required tables. -+`data-source-ref`:: -+The bean ID of the DataSource that provides the required tables. - - - [[nsa-jdbc-user-service-group-authorities-by-username-query]] --* **group-authorities-by-username-query** --An SQL statement to query user's group authorities given a username. --The default is -- -+`group-authorities-by-username-query`:: -+An SQL statement to query user's group authorities, given a username. -+The default is as follows: - + -- -+==== - [source] - ---- - select -@@ -2214,750 +2250,718 @@ groups g, group_members gm, group_authorities ga - where - gm.username = ? and g.id = ga.group_id and g.id = gm.group_id - ---- -- -- -- -+==== - - [[nsa-jdbc-user-service-id]] --* **id** --A bean identifier, used for referring to the bean elsewhere in the context. -- -+`id`:: -+A bean identifier, which is used for referring to the bean elsewhere in the context. - - [[nsa-jdbc-user-service-role-prefix]] --* **role-prefix** --A non-empty string prefix that will be added to role strings loaded from persistent storage (default is "ROLE_"). --Use the value "none" for no prefix in cases where the default is non-empty. -- -+`role-prefix`:: -+A non-empty string prefix that is added to role strings loaded from persistent storage. -+Default: `ROLE_` -+Use a value of `none` for no prefix in cases where the default should be non-empty. - - [[nsa-jdbc-user-service-users-by-username-query]] --* **users-by-username-query** --An SQL statement to query a username, password, and enabled status given a username. --The default is -- -+`users-by-username-query`:: -+An SQL statement to query a username, password, and enabled status, given a username. -+The default is as follows: - + -- -+==== - [source] - ---- - select username, password, enabled from users where username = ? - ---- -- -+==== - - - - [[nsa-password-encoder]] --==== --Authentication providers can optionally be configured to use a password encoder as described in the <>. --This will result in the bean being injected with the appropriate `PasswordEncoder` instance. -+==== Element -+Injects a bean with the appropriate `PasswordEncoder` instance. -+Authentication providers can optionally be configured to use a password encoder, as described in the <>. - - - [[nsa-password-encoder-parents]] - ===== Parent Elements of - -+The `` element has the following parent elements: - --* <> --* <> -+* <`>> -+* <`>> - - - - [[nsa-password-encoder-attributes]] - ===== Attributes - -+The `` element has the following attributes: - - [[nsa-password-encoder-hash]] --* **hash** --Defines the hashing algorithm used on user passwords. --We recommend strongly against using MD4, as it is a very weak hashing algorithm. -+`hash`:: -+Defines the hashing algorithm for user passwords. -+IMPORTANT: We recommend strongly against using MD4, as it is a very weak hashing algorithm. - - - [[nsa-password-encoder-ref]] --* **ref** -+`ref`:: - Defines a reference to a Spring bean that implements `PasswordEncoder`. - - - [[nsa-user-service]] --==== --Creates an in-memory UserDetailsService from a properties file or a list of "user" child elements. --Usernames are converted to lower-case internally to allow for case-insensitive lookups, so this should not be used if case-sensitivity is required. -+==== Element -+The `` element creates an in-memory `UserDetailsService` from a properties file or a list of `` child elements. -+Usernames are converted to lower case internally, to allow for case-insensitive lookups, so do not use this element if you need case-sensitivity. - - - [[nsa-user-service-attributes]] - ===== Attributes - -+The `` element has the following attributes: - - [[nsa-user-service-id]] --* **id** --A bean identifier, used for referring to the bean elsewhere in the context. -+`id`:: -+A bean identifier, used to refer to the bean elsewhere in the context. - - - [[nsa-user-service-properties]] --* **properties** --The location of a Properties file where each line is in the format of -- -+`properties`:: -+The location of a properties file, in which each line is in the format of - + -- -+==== - [source] - ---- - username=password,grantedAuthority[,grantedAuthority][,enabled|disabled] - ---- -- -- -+==== - - - [[nsa-user-service-children]] --===== Child Elements of -- -- --* <> -+===== Child Element of - -+The `` element has a single child element: <`>>. -+Multiple `` elements can be present. - - - [[nsa-user]] --==== --Represents a user in the application. -+==== Element -+The `` represents a user in the application. - - - [[nsa-user-parents]] --===== Parent Elements of -- -- --* <> -+===== Parent Element of - -+The parent element of the `` element is the <`>> element. - - - [[nsa-user-attributes]] - ===== Attributes - -+The `` element has the following elements: - - [[nsa-user-authorities]] --* **authorities** --One of more authorities granted to the user. --Separate authorities with a comma (but no space). --For example, "ROLE_USER,ROLE_ADMINISTRATOR" -- -+`authorities`:: -+One of more authorities to be granted to the user. -+Separate authorities with a comma (but no space) -- for example, `ROLE_USER,ROLE_ADMINISTRATOR`. - - [[nsa-user-disabled]] --* **disabled** --Can be set to "true" to mark an account as disabled and unusable. -- -+`disabled`:: -+Set to `true` to mark an account as disabled and unusable. - - [[nsa-user-locked]] --* **locked** --Can be set to "true" to mark an account as locked and unusable. -- -+`locked`:: -+Set to `true` to mark an account as locked and unusable. - - [[nsa-user-name]] --* **name** -+`name`:: - The username assigned to the user. - -- - [[nsa-user-password]] --* **password** -+`password`:: - The password assigned to the user. --This may be hashed if the corresponding authentication provider supports hashing (remember to set the "hash" attribute of the "user-service" element). --This attribute be omitted in the case where the data will not be used for authentication, but only for accessing authorities. --If omitted, the namespace will generate a random value, preventing its accidental use for authentication. --Cannot be empty. -+This value may be hashed if the corresponding authentication provider supports hashing (remember to set the `hash` attribute of the `user-service` element). -+You can omit this attribute when the data is not used for authentication but only for accessing authorities. -+If omitted, the namespace generates a random value, preventing its accidental use for authentication. -+This attribute cannot be empty. - - - [[nsa-method-security]] - === Method Security - -+The Spring Security namespace provides a number elements to enable method security. -+ - - [[nsa-global-method-security]] --==== --This element is the primary means of adding support for securing methods on Spring Security beans. --Methods can be secured by the use of annotations (defined at the interface or class level) or by defining a set of pointcuts as child elements, using AspectJ syntax. -+==== element -+The `` element is the primary means of adding support for securing methods on Spring Security beans. -+You can secure methods by using annotations (defined at the interface or class level) or by defining a set of pointcuts as child elements with AspectJ syntax. - - - [[nsa-global-method-security-attributes]] - ===== Attributes - -+The `` element has the following attributes: - - [[nsa-global-method-security-access-decision-manager-ref]] --* **access-decision-manager-ref** --Method security uses the same `AccessDecisionManager` configuration as web security, but this can be overridden using this attribute. --By default an AffirmativeBased implementation is used for with a RoleVoter and an AuthenticatedVoter. -- -+`access-decision-manager-ref`:: -+Method security uses the same `AccessDecisionManager` configuration as web security, but using this attribute can override this arrangement. -+By default, an `AffirmativeBased` implementation is used with a `RoleVoter` and an `AuthenticatedVoter`. - - [[nsa-global-method-security-authentication-manager-ref]] --* **authentication-manager-ref** --A reference to an `AuthenticationManager` that should be used for method security. -- -+`authentication-manager-ref`:: -+A reference to the `AuthenticationManager` that should be used for method security. - - [[nsa-global-method-security-jsr250-annotations]] --* **jsr250-annotations** --Specifies whether JSR-250 style attributes are to be used (for example "RolesAllowed"). --This will require the javax.annotation.security classes on the classpath. --Setting this to true also adds a `Jsr250Voter` to the `AccessDecisionManager`, so you need to make sure you do this if you are using a custom implementation and want to use these annotations. -+`jsr250-annotations`:: -+Specifies whether JSR-250 style attributes are to be used (for example, `RolesAllowed`). -+Doing so requires the `javax.annotation.security` classes to be on the classpath. -+Setting this to `true` also adds a `Jsr250Voter` to the `AccessDecisionManager`, so you need to make sure that you do so if you use a custom implementation and want to use these annotations. - - - [[nsa-global-method-security-metadata-source-ref]] --* **metadata-source-ref** --An external `MethodSecurityMetadataSource` instance can be supplied which will take priority over other sources (such as the default annotations). -- -+metadata-source-ref:: -+You can supply an external `MethodSecurityMetadataSource` instance, which will take priority over other sources (such as the default annotations). - - [[nsa-global-method-security-mode]] --* **mode** --This attribute can be set to "aspectj" to specify that AspectJ should be used instead of the default Spring AOP. --Secured methods must be woven with the `AnnotationSecurityAspect` from the `spring-security-aspects` module. -- --It is important to note that AspectJ follows Java's rule that annotations on interfaces are not inherited. --This means that methods that define the Security annotations on the interface will not be secured. --Instead, you must place the Security annotation on the class when using AspectJ. -- -+mode:: -+You can set this attribute to `aspectj` to specify that AspectJ should be used instead of the default Spring AOP. -+You must weave secured methods with the `AnnotationSecurityAspect` from the `spring-security-aspects` module. -++ -+NOTE: AspectJ follows Java's rule that annotations on interfaces are not inherited. -+This means that methods that define the Security annotations on the interface are not secured. -+Instead, you must place the Security annotation on the class when you use AspectJ. - - [[nsa-global-method-security-order]] --* **order** --Allows the advice "order" to be set for the method security interceptor. -- -+`order`:: -+Lets the `order` advice be set for the method security interceptor. - - [[nsa-global-method-security-pre-post-annotations]] --* **pre-post-annotations** --Specifies whether the use of Spring Security's pre and post invocation annotations (@PreFilter, @PreAuthorize, @PostFilter, @PostAuthorize) should be enabled for this application context. --Defaults to "disabled". -- -+`pre-post-annotations`:: -+Specifies whether the use of Spring Security's pre- and post-invocation annotations (`@PreFilter`, `@PreAuthorize`, `@PostFilter`, and `@PostAuthorize`) should be enabled for this application context. -+Default: `disabled` - - [[nsa-global-method-security-proxy-target-class]] --* **proxy-target-class** --If true, class based proxying will be used instead of interface based proxying. -- -+`proxy-target-class`:: -+If `true`, class-based proxying is used instead of interface-based proxying. - - [[nsa-global-method-security-run-as-manager-ref]] --* **run-as-manager-ref** --A reference to an optional `RunAsManager` implementation which will be used by the configured `MethodSecurityInterceptor` -- -+`run-as-manager-ref`:: -+A reference to an optional `RunAsManager` implementation, which is used by the configured `MethodSecurityInterceptor`. - - [[nsa-global-method-security-secured-annotations]] --* **secured-annotations** --Specifies whether the use of Spring Security's @Secured annotations should be enabled for this application context. --Defaults to "disabled". -+`secured-annotations`:: -+Specifies whether the use of Spring Security's `@Secured` annotations should be enabled for this application context. -+Default: `disabled` - - - [[nsa-global-method-security-children]] - ===== Child Elements of - -+The `` has the following child elements: - --* <> --* <> --* <> --* <> -- -+* <`>> -+* <`>> -+* <`>> -+* <`>> - - - [[nsa-after-invocation-provider]] --==== --This element can be used to decorate an `AfterInvocationProvider` for use by the security interceptor maintained by the `` namespace. --You can define zero or more of these within the `global-method-security` element, each with a `ref` attribute pointing to an `AfterInvocationProvider` bean instance within your application context. -+==== Element -+You can use the `` element to decorate an `AfterInvocationProvider` for use by the security interceptor that is maintained by the `` namespace. -+You can define zero or more of these elements within the `global-method-security` element, each with a `ref` attribute that points to an `AfterInvocationProvider` bean instance within your application context. - - - [[nsa-after-invocation-provider-parents]] - ===== Parent Elements of - -- --* <> -- -+The parent element of the `` is the <`>> element. - - - [[nsa-after-invocation-provider-attributes]] - ===== Attributes - -+The `` element has a single attribute: - - [[nsa-after-invocation-provider-ref]] --* **ref** -+`ref`:: - Defines a reference to a Spring bean that implements `AfterInvocationProvider`. - - - [[nsa-pre-post-annotation-handling]] - ==== --Allows the default expression-based mechanism for handling Spring Security's pre and post invocation annotations (@PreFilter, @PreAuthorize, @PostFilter, @PostAuthorize) to be replaced entirely. --Only applies if these annotations are enabled. -+The `` lets us entirely replace the default expression-based mechanism for handling Spring Security's pre- and post-invocation annotations (`@PreFilter`, `@PreAuthorize`, `@PostFilter`, `@PostAuthorize`). -+It applies only if these annotations are enabled. - - - [[nsa-pre-post-annotation-handling-parents]] - ===== Parent Elements of - -- --* <> -- -+The parent element of the `` element is the <`>> element. - - - [[nsa-pre-post-annotation-handling-children]] - ===== Child Elements of - -+The `` element has the following children: - --* <> --* <> --* <> -+* <`>> -+* <`>> -+* <`>> - - - - [[nsa-invocation-attribute-factory]] - ==== --Defines the PrePostInvocationAttributeFactory instance which is used to generate pre and post invocation metadata from the annotated methods. -+The `` element defines the `PrePostInvocationAttributeFactory` instance to use to generate pre- and post-invocation metadata from the annotated methods. - - - [[nsa-invocation-attribute-factory-parents]] - ===== Parent Elements of - -- --* <> -- -+The parent element of the `` element is the <> element. - - - [[nsa-invocation-attribute-factory-attributes]] - ===== Attributes - -+The `` has a single attribute: - - [[nsa-invocation-attribute-factory-ref]] --* **ref** --Defines a reference to a Spring bean Id. -+`ref`:: -+Defines a reference to a Spring bean ID. - - - [[nsa-post-invocation-advice]] - ==== --Customizes the `PostInvocationAdviceProvider` with the ref as the `PostInvocationAuthorizationAdvice` for the element. -+The `` element customizes the `PostInvocationAdviceProvider` with the value of the `ref` attribute as the `PostInvocationAuthorizationAdvice` for the `` element. - - - [[nsa-post-invocation-advice-parents]] - ===== Parent Elements of - -- --* <> -- -+The parent element of the `` element is the <`>> element. - - - [[nsa-post-invocation-advice-attributes]] - ===== Attributes - -+The `` has a single attribute: - - [[nsa-post-invocation-advice-ref]] --* **ref** --Defines a reference to a Spring bean Id. -+`ref`:: -+Defines a reference to a Spring bean ID. - - - [[nsa-pre-invocation-advice]] - ==== --Customizes the `PreInvocationAuthorizationAdviceVoter` with the ref as the `PreInvocationAuthorizationAdviceVoter` for the element. -+The `` element customizes the `PreInvocationAuthorizationAdviceVoter` with the value of the `ref` attribute as the `PreInvocationAuthorizationAdviceVoter` for the `` element. - - - [[nsa-pre-invocation-advice-parents]] - ===== Parent Elements of - -- --* <> -- -+The parent element of the `` is the <`>> element. - - - [[nsa-pre-invocation-advice-attributes]] - ===== Attributes - -+The `` element has a single attribute: - - [[nsa-pre-invocation-advice-ref]] --* **ref** --Defines a reference to a Spring bean Id. -+ref:: -+Defines a reference to a Spring bean ID. - - - [[nsa-protect-pointcut]] --==== Securing Methods using --`` --Rather than defining security attributes on an individual method or class basis using the `@Secured` annotation, you can define cross-cutting security constraints across whole sets of methods and interfaces in your service layer using the `` element. -+==== Securing Methods by Using -+Rather than defining security attributes on an individual method or class basis by using the `@Secured` annotation, you can define cross-cutting security constraints across whole sets of methods and interfaces in your service layer by using the `` element. - You can find an example in the <>. - - - [[nsa-protect-pointcut-parents]] - ===== Parent Elements of - -- --* <> -+The parent element of the `` element is the <`>> element. - - - - [[nsa-protect-pointcut-attributes]] - ===== Attributes - -+The `` has the following attributes: - - [[nsa-protect-pointcut-access]] --* **access** --Access configuration attributes list that applies to all methods matching the pointcut, e.g. --"ROLE_A,ROLE_B" -+`access`:: -+Access configuration attributes list that applies to all methods that match the pointcut -- for example, -+`ROLE_A,ROLE_B`. - - - [[nsa-protect-pointcut-expression]] --* **expression** --An AspectJ expression, including the `execution` keyword. --For example, `execution(int com.foo.TargetObject.countLength(String))`. -+`expression`:: -+An AspectJ expression, including the `execution` keyword -- for example, `execution(int com.foo.TargetObject.countLength(String))`. - - - [[nsa-intercept-methods]] - ==== --Can be used inside a bean definition to add a security interceptor to the bean and set up access configuration attributes for the bean's methods -+You can use the `` element inside a bean definition to add a security interceptor to the bean and set up access configuration attributes for the bean's methods - - - [[nsa-intercept-methods-attributes]] - ===== Attributes - -+The `` element has a single attribute: - - [[nsa-intercept-methods-access-decision-manager-ref]] --* **access-decision-manager-ref** --Optional AccessDecisionManager bean ID to be used by the created method security interceptor. -+`access-decision-manager-ref`:: -+Optional `AccessDecisionManager` bean ID to be used by the created method security interceptor. - - - [[nsa-intercept-methods-children]] - ===== Child Elements of - -- --* <> -- -+The parent element of the `` is the <`>> element. - - - [[nsa-method-security-metadata-source]] - ==== --Creates a MethodSecurityMetadataSource instance -+The `` element creates a `MethodSecurityMetadataSource` instance. - - - [[nsa-method-security-metadata-source-attributes]] - ===== Attributes - -+The `` element has the following attributes: - - [[nsa-method-security-metadata-source-id]] --* **id** -+`id`:: - A bean identifier, used for referring to the bean elsewhere in the context. - - - [[nsa-method-security-metadata-source-use-expressions]] --* **use-expressions** --Enables the use of expressions in the 'access' attributes in elements rather than the traditional list of configuration attributes. --Defaults to 'false'. -+`use-expressions`:: -+Enables the use of expressions in the `access` attributes of `` elements rather than the traditional list of configuration attributes. -+Default: `false` - If enabled, each attribute should contain a single Boolean expression. --If the expression evaluates to 'true', access will be granted. -+If the expression evaluates to `true`, access is granted. - - - [[nsa-method-security-metadata-source-children]] - ===== Child Elements of - -- --* <> -- -+The `` has a single child element: <`>>. - - - [[nsa-protect]] - ==== --Defines a protected method and the access control configuration attributes that apply to it. --We strongly advise you NOT to mix "protect" declarations with any services provided "global-method-security". -+The `` element defines a protected method and the access control configuration attributes that apply to it. -+We strongly advise you NOT to mix "`protect`" declarations with any services provided by `` element. - - - [[nsa-protect-parents]] - ===== Parent Elements of - -+The `` element has two parent elements: - --* <> --* <> -- -+* <`>> -+* <`>> - - - [[nsa-protect-attributes]] - ===== Attributes - -+The `` element has the following attributes: - - [[nsa-protect-access]] --* **access** --Access configuration attributes list that applies to the method, e.g. --"ROLE_A,ROLE_B". -+`access`:: -+Access configuration attributes list that applies to the method -- for example, -+`ROLE_A,ROLE_B`. - - - [[nsa-protect-method]] --* **method** --A method name -+`method`:: -+A method name. - - - [[nsa-ldap]] - === LDAP Namespace Options --LDAP is covered in some details in <>. --We will expand on that here with some explanation of how the namespace options map to Spring beans. -+LDAP is covered in some detail in <>. -+We expand on that here with some explanation of how the namespace options map to Spring beans. - The LDAP implementation uses Spring LDAP extensively, so some familiarity with that project's API may be useful. - - - [[nsa-ldap-server]] --==== Defining the LDAP Server using the --`` Element --This element sets up a Spring LDAP `ContextSource` for use by the other LDAP beans, defining the location of the LDAP server and other information (such as a username and password, if it doesn't allow anonymous access) for connecting to it. --It can also be used to create an embedded server for testing. -+==== Defining the LDAP Server by Using the Element -+The `` element sets up a Spring LDAP `ContextSource` for use by the other LDAP beans, defining the location of the LDAP server and other information (such as a username and password, if it does not allow anonymous access) for connecting to it. -+You can also use it to create an embedded server for testing. - Details of the syntax for both options are covered in the <>. --The actual `ContextSource` implementation is `DefaultSpringSecurityContextSource` which extends Spring LDAP's `LdapContextSource` class. -+The actual `ContextSource` implementation is `DefaultSpringSecurityContextSource`, which extends Spring LDAP's `LdapContextSource` class. - The `manager-dn` and `manager-password` attributes map to the latter's `userDn` and `password` properties respectively. - --If you only have one server defined in your application context, the other LDAP namespace-defined beans will use it automatically. --Otherwise, you can give the element an "id" attribute and refer to it from other namespace beans using the `server-ref` attribute. -+If you have only one server defined in your application context, the other LDAP namespace-defined beans use it automatically. -+Otherwise, you can give the element an `id` attribute and refer to it from other namespace beans by using the `server-ref` attribute. - This is actually the bean `id` of the `ContextSource` instance, if you want to use it in other traditional Spring beans. - - - [[nsa-ldap-server-attributes]] - ===== Attributes - -+The `` element has the following attributes: -+ - [[nsa-ldap-server-mode]] --* **mode** --Explicitly specifies which embedded ldap server should use. Values are `apacheds` and `unboundid`. By default, it will depends if the library is available in the classpath. -+`mode`:: -+Explicitly specifies which embedded LDAP server to use. Valid values are `apacheds` and `unboundid`. By default, it depends on whether the library is available in the classpath. - - [[nsa-ldap-server-id]] --* **id** -+`id`:: - A bean identifier, used for referring to the bean elsewhere in the context. - - - [[nsa-ldap-server-ldif]] --* **ldif** -+`ldif`:: - Explicitly specifies an ldif file resource to load into an embedded LDAP server. --The ldif should be a Spring resource pattern (i.e. classpath:init.ldif). --The default is classpath*:*.ldif -+The ldif file should be a Spring resource pattern (such as `classpath:init.ldif`). -+Default: `classpath*:*.ldif` - - - [[nsa-ldap-server-manager-dn]] --* **manager-dn** --Username (DN) of the "manager" user identity which will be used to authenticate to a (non-embedded) LDAP server. --If omitted, anonymous access will be used. -+`manager-dn`:: -+Username (DN) of the "`manager`" user identity, which is used to authenticate to a (non-embedded) LDAP server. -+If omitted, anonymous access is used. - - - [[nsa-ldap-server-manager-password]] --* **manager-password** -+`manager-password`:: - The password for the manager DN. --This is required if the manager-dn is specified. -+This is required if the `manager-dn` is specified. - - - [[nsa-ldap-server-port]] --* **port** -+`port`:: - Specifies an IP port number. --Used to configure an embedded LDAP server, for example. --The default value is 33389. -+You can use use it to configure an embedded LDAP server, for example. -+The default value is `33389`. - - - [[nsa-ldap-server-root]] --* **root** -+`root`:: - Optional root suffix for the embedded LDAP server. --Default is "dc=springframework,dc=org" -+Default: `dc=springframework,dc=org` - - - [[nsa-ldap-server-url]] --* **url** --Specifies the ldap server URL when not using the embedded LDAP server. -+url:: -+Specifies the LDAP server URL when not using the embedded LDAP server. - - - [[nsa-ldap-authentication-provider]] - ==== - This element is shorthand for the creation of an `LdapAuthenticationProvider` instance. --By default this will be configured with a `BindAuthenticator` instance and a `DefaultAuthoritiesPopulator`. -+By default, this is configured with a `BindAuthenticator` instance and a `DefaultAuthoritiesPopulator`. - As with all namespace authentication providers, it must be included as a child of the `authentication-provider` element. - - - [[nsa-ldap-authentication-provider-parents]] - ===== Parent Elements of - -- --* <> -- -+The parent element of the `` is the <`>> element. - - - [[nsa-ldap-authentication-provider-attributes]] - ===== Attributes - -+The `` element has the following attributes: - - [[nsa-ldap-authentication-provider-group-role-attribute]] --* **group-role-attribute** --The LDAP attribute name which contains the role name which will be used within Spring Security. --Maps to the ``DefaultLdapAuthoritiesPopulator``'s `groupRoleAttribute` property. --Defaults to "cn". -+`group-role-attribute`:: -+The LDAP attribute name, which contains the role name that is used within Spring Security. -+Maps to the `groupRoleAttribute` property of the `DefaultLdapAuthoritiesPopulator`. -+Default: `cn` - - - [[nsa-ldap-authentication-provider-group-search-base]] --* **group-search-base** -+`group-search-base`:: - Search base for group membership searches. --Maps to the ``DefaultLdapAuthoritiesPopulator``'s `groupSearchBase` constructor argument. --Defaults to "" (searching from the root). -+Maps to the `groupSearchBase` constructor argument of `DefaultLdapAuthoritiesPopulator`. -+Default: `""` (searching from the root) - - - [[nsa-ldap-authentication-provider-group-search-filter]] --* **group-search-filter** -+`group-search-filter`:: - Group search filter. --Maps to the ``DefaultLdapAuthoritiesPopulator``'s `groupSearchFilter` property. --Defaults to `+(uniqueMember={0})+`. -+Maps to the `groupSearchFilter` property of `DefaultLdapAuthoritiesPopulator`. - The substituted parameter is the DN of the user. -+Default: `+(uniqueMember={0})+` - - - [[nsa-ldap-authentication-provider-role-prefix]] --* **role-prefix** --A non-empty string prefix that will be added to role strings loaded from persistent. --Maps to the ``DefaultLdapAuthoritiesPopulator``'s `rolePrefix` property. --Defaults to "ROLE_". --Use the value "none" for no prefix in cases where the default is non-empty. -+`role-prefix`:: -+A non-empty string prefix that is added to role strings loaded from persistent storage. -+Maps to the `rolePrefix` property of `DefaultLdapAuthoritiesPopulator`. -+Use a value of `none` for no prefix in cases where the default is non-empty. -+Default: `ROLE_` - - - [[nsa-ldap-authentication-provider-server-ref]] --* **server-ref** -+`server-ref`:: - The optional server to use. --If omitted, and a default LDAP server is registered (using with no Id), that server will be used. -+If omitted, and a default LDAP server is registered (by using `` with no ID), that server is used. - - - [[nsa-ldap-authentication-provider-user-context-mapper-ref]] --* **user-context-mapper-ref** --Allows explicit customization of the loaded user object by specifying a UserDetailsContextMapper bean which will be called with the context information from the user's directory entry -+`user-context-mapper-ref`:: -+Allows explicit customization of the loaded user object by specifying a `UserDetailsContextMapper` bean, which is called with the context information from the user's directory entry. - - - [[nsa-ldap-authentication-provider-user-details-class]] --* **user-details-class** --Allows the objectClass of the user entry to be specified. --If set, the framework will attempt to load standard attributes for the defined class into the returned UserDetails object -+`user-details-class`:: -+Lets the `objectClass` of the user entry be specified. -+If set, the framework tries to load standard attributes for the defined class into the returned `UserDetails` object - - - [[nsa-ldap-authentication-provider-user-dn-pattern]] --* **user-dn-pattern** --If your users are at a fixed location in the directory (i.e. you can work out the DN directly from the username without doing a directory search), you can use this attribute to map directly to the DN. -+user-dn-pattern:: -+If your users are at a fixed location in the directory (that is, you can work out the DN directly from the username without doing a directory search), you can use this attribute to map directly to the DN. - It maps directly to the `userDnPatterns` property of `AbstractLdapAuthenticator`. --The value is a specific pattern used to build the user's DN, for example `+uid={0},ou=people+`. --The key `+{0}+` must be present and will be substituted with the username. -+The value is a specific pattern used to build the user's DN -- for example, `+uid={0},ou=people+`. -+The `+{0}+` key must be present and is substituted with the username. - - - [[nsa-ldap-authentication-provider-user-search-base]] --* **user-search-base** -+`user-search-base`:: - Search base for user searches. --Defaults to "". --Only used with a 'user-search-filter'. -- -+Only used with a `user-search-filter`. -+Default `""` - + -- --If you need to perform a search to locate the user in the directory, then you can set these attributes to control the search. --The `BindAuthenticator` will be configured with a `FilterBasedLdapUserSearch` and the attribute values map directly to the first two arguments of that bean's constructor. --If these attributes aren't set and no `user-dn-pattern` has been supplied as an alternative, then the default search values of `+user-search-filter="(uid={0})"+` and `user-search-base=""` will be used. -+If you need to perform a search to locate the user in the directory, you can set these attributes to control the search. -+The `BindAuthenticator` is configured with a `FilterBasedLdapUserSearch`, and the attribute values map directly to the first two arguments of that bean's constructor. -+If these attributes are not set and no `user-dn-pattern` has been supplied as an alternative, the default search values of `+user-search-filter="(uid={0})"+` and `user-search-base=""` are used. - - - [[nsa-ldap-authentication-provider-user-search-filter]] --* **user-search-filter** --The LDAP filter used to search for users (optional). --For example `+(uid={0})+`. -+`user-search-filter`:: -+The LDAP filter used to search for users (optional) -- for example, `+(uid={0})+`. - The substituted parameter is the user's login name. -- - + -- --If you need to perform a search to locate the user in the directory, then you can set these attributes to control the search. --The `BindAuthenticator` will be configured with a `FilterBasedLdapUserSearch` and the attribute values map directly to the first two arguments of that bean's constructor. --If these attributes aren't set and no `user-dn-pattern` has been supplied as an alternative, then the default search values of `+user-search-filter="(uid={0})"+` and `user-search-base=""` will be used. -+If you need to perform a search to locate the user in the directory, you can set these attributes to control the search. -+The `BindAuthenticator` is configured with a `FilterBasedLdapUserSearch`, and the attribute values map directly to the first two arguments of that bean's constructor. -+If these attributes are not set and no `user-dn-pattern` has been supplied as an alternative, the default search values of `+user-search-filter="(uid={0})"+` and `user-search-base=""` is used. - - - [[nsa-ldap-authentication-provider-children]] - ===== Child Elements of - -- --* <> -- -+The `` has a single child element: <`>>. - - - [[nsa-password-compare]] - ==== --This is used as child element to `` and switches the authentication strategy from `BindAuthenticator` to `PasswordComparisonAuthenticator`. -+The `` element is used as a child element to `` and switches the authentication strategy from `BindAuthenticator` to `PasswordComparisonAuthenticator`. - - - [[nsa-password-compare-parents]] - ===== Parent Elements of - -- --* <> -- -+The parent element of the `` element is the <`>> element. - - - [[nsa-password-compare-attributes]] - ===== Attributes - -+The `` has the following attributes: - - [[nsa-password-compare-hash]] --* **hash** -+`hash`:: - Defines the hashing algorithm used on user passwords. - We recommend strongly against using MD4, as it is a very weak hashing algorithm. - - - [[nsa-password-compare-password-attribute]] --* **password-attribute** --The attribute in the directory which contains the user password. --Defaults to "userPassword". -+`password-attribute`:: -+The attribute in the directory that contains the user password. -+Default: `userPassword` - - - [[nsa-password-compare-children]] - ===== Child Elements of - -- --* <> -- -+The `` element has a single child element: <`>>. - - - [[nsa-ldap-user-service]] - ==== --This element configures an LDAP `UserDetailsService`. --The class used is `LdapUserDetailsService` which is a combination of a `FilterBasedLdapUserSearch` and a `DefaultLdapAuthoritiesPopulator`. --The attributes it supports have the same usage as in ``. -+The `` element configures an LDAP `UserDetailsService`. -+It uses `LdapUserDetailsService`, which is a combination of a `FilterBasedLdapUserSearch` and a `DefaultLdapAuthoritiesPopulator`. -+The attributes it supports have the same usage as ``. - - - [[nsa-ldap-user-service-attributes]] - ===== Attributes - -+The `` element has the following attributes: -+ - - [[nsa-ldap-user-service-cache-ref]] --* **cache-ref** --Defines a reference to a cache for use with a UserDetailsService. -+`cache-ref`:: -+Defines a reference to a cache for use with a `UserDetailsService`. - - - [[nsa-ldap-user-service-group-role-attribute]] --* **group-role-attribute** --The LDAP attribute name which contains the role name which will be used within Spring Security. --Defaults to "cn". -+`group-role-attribute`:: -+The LDAP attribute name that contains the role name to be used within Spring Security. -+Default: `cn` - - - [[nsa-ldap-user-service-group-search-base]] --* **group-search-base** -+`group-search-base`:: - Search base for group membership searches. --Defaults to "" (searching from the root). -+Default: `""` (searching from the root) - - - [[nsa-ldap-user-service-group-search-filter]] --* **group-search-filter** -+`group-search-filter`:: - Group search filter. --Defaults to `+(uniqueMember={0})+`. - The substituted parameter is the DN of the user. -+Default: `+(uniqueMember={0})+` - - - [[nsa-ldap-user-service-id]] --* **id** -+`id`:: - A bean identifier, used for referring to the bean elsewhere in the context. - - - [[nsa-ldap-user-service-role-prefix]] --* **role-prefix** --A non-empty string prefix that will be added to role strings loaded from persistent storage (e.g. --"ROLE_"). --Use the value "none" for no prefix in cases where the default is non-empty. -+role-prefix:: -+A non-empty string prefix that is added to role strings loaded from persistent storage (for example, -+`ROLE_`). -+Use a value of `none` for no prefix in cases where the default is non-empty. - - - [[nsa-ldap-user-service-server-ref]] --* **server-ref** -+`server-ref`:: - The optional server to use. --If omitted, and a default LDAP server is registered (using with no Id), that server will be used. -+If omitted and a default LDAP server is registered (by using `` with no ID), that server is used. - - - [[nsa-ldap-user-service-user-context-mapper-ref]] --* **user-context-mapper-ref** --Allows explicit customization of the loaded user object by specifying a UserDetailsContextMapper bean which will be called with the context information from the user's directory entry -+`user-context-mapper-ref`:: -+Allows explicit customization of the loaded user object by specifying a `UserDetailsContextMapper` bean, which is called with the context information from the user's directory entry. - - - [[nsa-ldap-user-service-user-details-class]] --* **user-details-class** --Allows the objectClass of the user entry to be specified. --If set, the framework will attempt to load standard attributes for the defined class into the returned UserDetails object -+`user-details-class`:: -+Lets the `objectClass` of the user entry be specified. -+If set, the framework tries to load standard attributes for the defined class into the returned `UserDetails` object. - - - [[nsa-ldap-user-service-user-search-base]] --* **user-search-base** -+`user-search-base`:: - Search base for user searches. --Defaults to "". --Only used with a 'user-search-filter'. -+It is used only with a <`>> element. -+Default: `""` - - - [[nsa-ldap-user-service-user-search-filter]] --* **user-search-filter** --The LDAP filter used to search for users (optional). --For example `+(uid={0})+`. -+`user-search-filter`:: -+The LDAP filter used to search for users (optional) -- for example, `+(uid={0})+`. - The substituted parameter is the user's login name. -diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/architecture/delegating-filter-proxy.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/architecture/delegating-filter-proxy.adoc -index d7c3d45ed3..5743b93868 100644 ---- a/docs/manual/src/docs/asciidoc/_includes/servlet/architecture/delegating-filter-proxy.adoc -+++ b/docs/manual/src/docs/asciidoc/_includes/servlet/architecture/delegating-filter-proxy.adoc -@@ -2,17 +2,19 @@ - = DelegatingFilterProxy - - Spring provides a `Filter` implementation named {security-api-url}org/springframework/web/filter/DelegatingFilterProxy.html/[`DelegatingFilterProxy`] that allows bridging between the Servlet container's lifecycle and Spring's `ApplicationContext`. --The Servlet container allows registering ``Filter``s using its own standards, but it is not aware of Spring defined Beans. --`DelegatingFilterProxy` can be registered via standard Servlet container mechanisms, but delegate all the work to a Spring Bean that implements `Filter`. -+The Servlet container allows registering `Filter` instances by using its own standards, but it is not aware of Spring-defined Beans. -+You can register `DelegatingFilterProxy` through the standard Servlet container mechanisms but delegate all the work to a Spring Bean that implements `Filter`. - --Here is a picture of how `DelegatingFilterProxy` fits into the <>. -+Here is a picture of how `DelegatingFilterProxy` fits into the <>. - - .DelegatingFilterProxy - [[servlet-delegatingfilterproxy-figure]] - image::{figures}/delegatingfilterproxy.png[] - - `DelegatingFilterProxy` looks up __Bean Filter~0~__ from the `ApplicationContext` and then invokes __Bean Filter~0~__. --The pseudo code of `DelegatingFilterProxy` can be seen below. -+The following listing shows pseudo code of `DelegatingFilterProxy`: -+ -+// FIXME: Use real code from a real repository rather than pseudo code. - - .`DelegatingFilterProxy` Pseudo Code - ==== -@@ -41,6 +43,6 @@ fun doFilter(request: ServletRequest, response: ServletResponse, chain: FilterCh - ---- - ==== - --Another benefit of `DelegatingFilterProxy` is that it allows delaying looking `Filter` bean instances. --This is important because the container needs to register the `Filter` instances before the container can startup. --However, Spring typically uses a `ContextLoaderListener` to load the Spring Beans which will not be done until after the `Filter` instances need to be registered. -+Another benefit of `DelegatingFilterProxy` is that it allows delaying looking up `Filter` bean instances. -+This is important because the container needs to register the `Filter` instances before the container can start up. -+However, Spring typically uses a `ContextLoaderListener` to load the Spring Beans, which is not done until after the `Filter` instances need to be registered. -diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/architecture/exception-translation-filter.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/architecture/exception-translation-filter.adoc -index 67cad58ddf..f3c97ed7de 100644 ---- a/docs/manual/src/docs/asciidoc/_includes/servlet/architecture/exception-translation-filter.adoc -+++ b/docs/manual/src/docs/asciidoc/_includes/servlet/architecture/exception-translation-filter.adoc -@@ -8,29 +8,29 @@ The {security-api-url}org/springframework/security/web/access/ExceptionTranslati - - `ExceptionTranslationFilter` is inserted into the <> as one of the <>. - --image::{figures}/exceptiontranslationfilter.png[] -+The following image shows the relationship of `ExceptionTranslationFilter` to other components: - -+image::{figures}/exceptiontranslationfilter.png[] - - * image:{icondir}/number_1.png[] First, the `ExceptionTranslationFilter` invokes `FilterChain.doFilter(request, response)` to invoke the rest of the application. --* image:{icondir}/number_2.png[] If the user is not authenticated or it is an `AuthenticationException`, then __Start Authentication__. --** The <> is cleared out -+* image:{icondir}/number_2.png[] If the user is not authenticated or it is an `AuthenticationException`, __Start Authentication__. -+** The <> is cleared out. - ** The `HttpServletRequest` is saved in the {security-api-url}org/springframework/security/web/savedrequest/RequestCache.html[`RequestCache`]. - When the user successfully authenticates, the `RequestCache` is used to replay the original request. - // FIXME: add link to authentication success - ** The `AuthenticationEntryPoint` is used to request credentials from the client. - For example, it might redirect to a log in page or send a `WWW-Authenticate` header. - // FIXME: link to AuthenticationEntryPoint --* image:{icondir}/number_3.png[] Otherwise if it is an `AccessDeniedException`, then __Access Denied__. -+* image:{icondir}/number_3.png[] Otherwise, if it is an `AccessDeniedException`, then __Access Denied__. - The `AccessDeniedHandler` is invoked to handle access denied. - // FIXME: link to AccessDeniedHandler - --[NOTE] --==== --If the application does not throw an `AccessDeniedException` or an `AuthenticationException`, then `ExceptionTranslationFilter` does not do anything. --==== -+NOTE: If the application does not throw an `AccessDeniedException` or an `AuthenticationException`, `ExceptionTranslationFilter` does not do anything. - - The pseudocode for `ExceptionTranslationFilter` looks something like this: - -+// FIXME: Use real code from a real repository rather than pseudo code -+ - .ExceptionTranslationFilter pseudocode - [source,java] - ---- -@@ -44,7 +44,7 @@ try { - } - } - ---- --<1> You will recall from <> that invoking `FilterChain.doFilter(request, response)` is the equivalent of invoking the rest of the application. --This means that if another part of the application, (i.e. <> or method security) throws an `AuthenticationException` or `AccessDeniedException` it will be caught and handled here. --<2> If the user is not authenticated or it is an `AuthenticationException`, then __Start Authentication__. -+<1> As described in <>, invoking `FilterChain.doFilter(request, response)` is the equivalent of invoking the rest of the application. -+This means that if another part of the application, (<> or method security) throws an `AuthenticationException` or `AccessDeniedException` it is caught and handled here. -+<2> If the user is not authenticated or it is an `AuthenticationException`, __Start Authentication__. - <3> Otherwise, __Access Denied__ -diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/architecture/filter-chain-proxy.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/architecture/filter-chain-proxy.adoc -index 0b15efeec9..d69cbdb423 100644 ---- a/docs/manual/src/docs/asciidoc/_includes/servlet/architecture/filter-chain-proxy.adoc -+++ b/docs/manual/src/docs/asciidoc/_includes/servlet/architecture/filter-chain-proxy.adoc -@@ -5,6 +5,8 @@ Spring Security's Servlet support is contained within `FilterChainProxy`. - `FilterChainProxy` is a special `Filter` provided by Spring Security that allows delegating to many `Filter` instances through <>. - Since `FilterChainProxy` is a Bean, it is typically wrapped in a <>. - -+The following image shows the role of `FilterChainProxy`. -+ - .FilterChainProxy - [[servlet-filterchainproxy-figure]] - image::{figures}/filterchainproxy.png[] -diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/architecture/filters.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/architecture/filters.adoc -index 4b63aa4deb..54aaee9b4a 100644 ---- a/docs/manual/src/docs/asciidoc/_includes/servlet/architecture/filters.adoc -+++ b/docs/manual/src/docs/asciidoc/_includes/servlet/architecture/filters.adoc -@@ -1,21 +1,21 @@ - [[servlet-filters-review]] --= A Review of ``Filter``s -+= A Review of Filters - --Spring Security's Servlet support is based on Servlet ``Filter``s, so it is helpful to look at the role of ``Filter``s generally first. --The picture below shows the typical layering of the handlers for a single HTTP request. -+Spring Security's Servlet support is based on Servlet Filters, so it is helpful to look at the role of Filters generally first. -+The following image shows the typical layering of the handlers for a single HTTP request. - - .FilterChain - [[servlet-filterchain-figure]] - image::{figures}/filterchain.png[] - --The client sends a request to the application, and the container creates a `FilterChain` which contains the ``Filter``s and `Servlet` that should process the `HttpServletRequest` based on the path of the request URI. --In a Spring MVC application the `Servlet` is an instance of https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#mvc-servlet[`DispatcherServlet`]. --At most one `Servlet` can handle a single `HttpServletRequest` and `HttpServletResponse`. -+The client sends a request to the application, and the container creates a `FilterChain`, which contains the `Filter` instances and `Servlet` that should process the `HttpServletRequest`, based on the path of the request URI. -+In a Spring MVC application, the `Servlet` is an instance of https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#mvc-servlet[`DispatcherServlet`]. -+At most, one `Servlet` can handle a single `HttpServletRequest` and `HttpServletResponse`. - However, more than one `Filter` can be used to: - --* Prevent downstream ``Filter``s or the `Servlet` from being invoked. --In this instance the `Filter` will typically write the `HttpServletResponse`. --* Modify the `HttpServletRequest` or `HttpServletResponse` used by the downstream ``Filter``s and `Servlet` -+* Prevent downstream `Filter` instances or the `Servlet` from being invoked. -+In this case, the `Filter` typically writes the `HttpServletResponse`. -+* Modify the `HttpServletRequest` or `HttpServletResponse` used by the downstream `Filter` instances and the `Servlet`. - - The power of the `Filter` comes from the `FilterChain` that is passed into it. - -@@ -42,4 +42,4 @@ fun doFilter(request: ServletRequest, response: ServletResponse, chain: FilterCh - ---- - ==== - --Since a `Filter` only impacts downstream ``Filter``s and the `Servlet`, the order each `Filter` is invoked is extremely important. -+Since a `Filter` impacts only downstream `Filter` instances and the `Servlet`, the order in which each `Filter` is invoked is extremely important. -diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/architecture/index.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/architecture/index.adoc -index 38b639f9b2..610c495376 100644 ---- a/docs/manual/src/docs/asciidoc/_includes/servlet/architecture/index.adoc -+++ b/docs/manual/src/docs/asciidoc/_includes/servlet/architecture/index.adoc -@@ -2,8 +2,8 @@ - = Servlet Security: The Big Picture - :figures: images/servlet/architecture - --This section discusses Spring Security's high level architecture within Servlet based applications. --We build on this high level understanding within <>, <>, <> sections of the reference. -+This section discusses Spring Security's high-level architecture within Servlet based applications. -+We build on this high-level understanding within the <>, <>, and <> sections of the reference. - // FIXME: Add links to other sections of architecture - - include::filters.adoc[leveloffset=+1] -diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/architecture/security-filter-chain.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/architecture/security-filter-chain.adoc -index 508e9e3d21..a970902c1a 100644 ---- a/docs/manual/src/docs/asciidoc/_includes/servlet/architecture/security-filter-chain.adoc -+++ b/docs/manual/src/docs/asciidoc/_includes/servlet/architecture/security-filter-chain.adoc -@@ -1,7 +1,9 @@ - [[servlet-securityfilterchain]] - = SecurityFilterChain - --{security-api-url}org/springframework/security/web/SecurityFilterChain.html[`SecurityFilterChain`] is used by <> to determine which Spring Security ``Filter``s should be invoked for this request. -+{security-api-url}org/springframework/security/web/SecurityFilterChain.html[`SecurityFilterChain`] is used by <> to determine which Spring Security `Filter` instances should be invoked for the current request. -+ -+The following image shows the role of `SecurityFilterChain`. - - .SecurityFilterChain - [[servlet-securityfilterchain-figure]] -@@ -10,34 +12,36 @@ image::{figures}/securityfilterchain.png[] - The <> in `SecurityFilterChain` are typically Beans, but they are registered with `FilterChainProxy` instead of <>. - `FilterChainProxy` provides a number of advantages to registering directly with the Servlet container or <>. - First, it provides a starting point for all of Spring Security's Servlet support. --For that reason, if you are attempting to troubleshoot Spring Security's Servlet support, adding a debug point in `FilterChainProxy` is a great place to start. -+For that reason, if you try to troubleshoot Spring Security's Servlet support, adding a debug point in `FilterChainProxy` is a great place to start. - --Second, since `FilterChainProxy` is central to Spring Security usage it can perform tasks that are not viewed as optional. -+Second, since `FilterChainProxy` is central to Spring Security usage, it can perform tasks that are not viewed as optional. - // FIXME: Add a link to SecurityContext - For example, it clears out the `SecurityContext` to avoid memory leaks. - It also applies Spring Security's <> to protect applications against certain types of attacks. - - In addition, it provides more flexibility in determining when a `SecurityFilterChain` should be invoked. --In a Servlet container, ``Filter``s are invoked based upon the URL alone. -+In a Servlet container, `Filter` instances are invoked based upon the URL alone. - // FIXME: Link to RequestMatcher --However, `FilterChainProxy` can determine invocation based upon anything in the `HttpServletRequest` by leveraging the `RequestMatcher` interface. -+However, `FilterChainProxy` can determine invocation based upon anything in the `HttpServletRequest` by using the `RequestMatcher` interface. -+ -+In fact, you can use `FilterChainProxy` to determine which `SecurityFilterChain` should be used. -+This lets you provide a totally separate configuration for different _slices_ of your application. - --In fact, `FilterChainProxy` can be used to determine which `SecurityFilterChain` should be used. --This allows providing a totally separate configuration for different _slices_ of your application. -+The following image shows multiple `SecurityFilterChain` instances: - - .Multiple SecurityFilterChain - [[servlet-multi-securityfilterchain-figure]] - image::{figures}/multi-securityfilterchain.png[] - --In the <> Figure `FilterChainProxy` decides which `SecurityFilterChain` should be used. --Only the first `SecurityFilterChain` that matches will be invoked. --If a URL of `/api/messages/` is requested, it will first match on ``SecurityFilterChain~0~``'s pattern of `+/api/**+`, so only `SecurityFilterChain~0~` will be invoked even though it also matches on ``SecurityFilterChain~n~``. --If a URL of `/messages/` is requested, it will not match on ``SecurityFilterChain~0~``'s pattern of `+/api/**+`, so `FilterChainProxy` will continue trying each `SecurityFilterChain`. --Assuming that no other, `SecurityFilterChain` instances match `SecurityFilterChain~n~` will be invoked. --// FIXME add link to pattern matching -- --Notice that `SecurityFilterChain~0~` has only three security ``Filter``s instances configured. --However, `SecurityFilterChain~n~` has four security ``Filter``s configured. --It is important to note that each `SecurityFilterChain` can be unique and configured in isolation. --In fact, a `SecurityFilterChain` might have zero security ``Filter``s if the application wants Spring Security to ignore certain requests. -+In the <> figure, `FilterChainProxy` decides which `SecurityFilterChain` should be used. -+Only the first `SecurityFilterChain` that matches is invoked. -+If a URL of `/api/messages/` is requested, it first matches on the `SecurityFilterChain~0~` pattern of `+/api/**+`, so only `SecurityFilterChain~0~` is invoked, even though it also matches on ``SecurityFilterChain~n~``. -+If a URL of `/messages/` is requested, it does not match on the `SecurityFilterChain~0~` pattern of `+/api/**+`, so `FilterChainProxy` continues trying each `SecurityFilterChain`. -+Assuming that no other `SecurityFilterChain` instances match, `SecurityFilterChain~n~` is invoked. -+// FIXME: add link to pattern matching -+ -+Notice that `SecurityFilterChain~0~` has only three security `Filter` instances configured. -+However, `SecurityFilterChain~n~` has four security `Filter` instanes configured. -+It is important to note that each `SecurityFilterChain` can be unique and can be configured in isolation. -+In fact, a `SecurityFilterChain` might have zero security `Filter` instances if the application wants Spring Security to ignore certain requests. - // FIXME: add link to configuring multiple `SecurityFilterChain` instances -diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/architecture/security-filters.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/architecture/security-filters.adoc -index 408ec40637..9bc818d42f 100644 ---- a/docs/manual/src/docs/asciidoc/_includes/servlet/architecture/security-filters.adoc -+++ b/docs/manual/src/docs/asciidoc/_includes/servlet/architecture/security-filters.adoc -@@ -2,41 +2,41 @@ - = Security Filters - - The Security Filters are inserted into the <> with the <> API. --The <>s matters. --It is typically not necessary to know the ordering of Spring Security's ``Filter``s. --However, there are times that it is beneficial to know the ordering -+The <> instances matters. -+It is typically not necessary to know the ordering of Spring Security's `Filter` instances. -+However, there are times that it is beneficial to know the ordering. - --Below is a comprehensive list of Spring Security Filter ordering: -+The following is a comprehensive list of Spring Security Filter ordering: - --* ChannelProcessingFilter --* WebAsyncManagerIntegrationFilter --* SecurityContextPersistenceFilter --* HeaderWriterFilter --* CorsFilter --* CsrfFilter --* LogoutFilter --* OAuth2AuthorizationRequestRedirectFilter --* Saml2WebSsoAuthenticationRequestFilter --* X509AuthenticationFilter --* AbstractPreAuthenticatedProcessingFilter --* CasAuthenticationFilter --* OAuth2LoginAuthenticationFilter --* Saml2WebSsoAuthenticationFilter -+* `ChannelProcessingFilter` -+* `WebAsyncManagerIntegrationFilter` -+* `SecurityContextPersistenceFilter` -+* `HeaderWriterFilter` -+* `CorsFilter` -+* `CsrfFilter` -+* `LogoutFilter` -+* `OAuth2AuthorizationRequestRedirectFilter` -+* `Saml2WebSsoAuthenticationRequestFilter` -+* `X509AuthenticationFilter` -+* `AbstractPreAuthenticatedProcessingFilter` -+* `CasAuthenticationFilter` -+* `OAuth2LoginAuthenticationFilter` -+* `Saml2WebSsoAuthenticationFilter` - * <> --* OpenIDAuthenticationFilter --* DefaultLoginPageGeneratingFilter --* DefaultLogoutPageGeneratingFilter --* ConcurrentSessionFilter -+* `OpenIDAuthenticationFilter` -+* `DefaultLoginPageGeneratingFilter` -+* `DefaultLogoutPageGeneratingFilter` -+* `ConcurrentSessionFilter` - * <> --* BearerTokenAuthenticationFilter -+* `BearerTokenAuthenticationFilter` - * <> --* RequestCacheAwareFilter --* SecurityContextHolderAwareRequestFilter --* JaasApiIntegrationFilter --* RememberMeAuthenticationFilter --* AnonymousAuthenticationFilter --* OAuth2AuthorizationCodeGrantFilter --* SessionManagementFilter -+* `RequestCacheAwareFilter` -+* `SecurityContextHolderAwareRequestFilter` -+* `JaasApiIntegrationFilter` -+* `RememberMeAuthenticationFilter` -+* `AnonymousAuthenticationFilter` -+* `OAuth2AuthorizationCodeGrantFilter` -+* `SessionManagementFilter` - * <> - * <> --* SwitchUserFilter -+* `SwitchUserFilter` -diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/anonymous.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/anonymous.adoc -index 9f2508f7aa..16306a3402 100644 ---- a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/anonymous.adoc -+++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/anonymous.adoc -@@ -1,38 +1,35 @@ - [[anonymous]] - == Anonymous Authentication - -- - [[anonymous-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. -+It is generally considered good security practice to adopt a "`deny-by-default`" stance, 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). --In this case it is easiest to define access configuration attributes for these specific URLs rather than have for every secured resource. --Put differently, sometimes it is nice to say `ROLE_SOMETHING` is required by default and only allow certain exceptions to this rule, such as for login, logout and home pages of an application. -+In that case, it is easiest to define access configuration attributes for these specific URLs rather than for every secured resource. -+Put differently, sometimes it is nice to say `ROLE_SOMETHING` is required by default and allow only certain exceptions to this rule, such as for login, logout, and home pages of an application. - You could also omit these pages from the filter chain entirely, thus bypassing the access control checks, but this may be undesirable for other reasons, particularly if the pages behave differently for authenticated users. - - This is what we mean by anonymous authentication. --Note that there is no real conceptual difference between a user who is "anonymously authenticated" and an unauthenticated user. -+Note that there is no real conceptual difference between a user who is "`anonymously authenticated`" and an unauthenticated user. - Spring Security's anonymous authentication just gives you a more convenient way to configure your access-control attributes. --Calls to servlet API calls such as `getCallerPrincipal`, for example, will still return null even though there is actually an anonymous authentication object in the `SecurityContextHolder`. -+Calls to servlet API calls, such as `getCallerPrincipal`, still return null, even though there is actually an anonymous authentication object in the `SecurityContextHolder`. - - There are other situations where anonymous authentication is useful, such as when an auditing interceptor queries the `SecurityContextHolder` to identify which principal was responsible for a given operation. --Classes can be authored more robustly if they know the `SecurityContextHolder` always contains an `Authentication` object, and never `null`. -- -+Classes can be authored more robustly if they know the `SecurityContextHolder` always contains an `Authentication` object and never contains `null`. - - [[anonymous-config]] - === Configuration --Anonymous authentication support is provided automatically when using the HTTP configuration Spring Security 3.0 and can be customized (or disabled) using the `` element. --You don't need to configure the beans described here unless you are using traditional bean configuration. -- --Three classes that together provide the anonymous authentication feature. --`AnonymousAuthenticationToken` is an implementation of `Authentication`, and stores the `GrantedAuthority` s which apply to the anonymous principal. --There is a corresponding `AnonymousAuthenticationProvider`, which is chained into the `ProviderManager` so that `AnonymousAuthenticationToken` s are accepted. --Finally, there is an `AnonymousAuthenticationFilter`, which is chained after the normal authentication mechanisms and automatically adds an `AnonymousAuthenticationToken` to the `SecurityContextHolder` if there is no existing `Authentication` held there. --The definition of the filter and authentication provider appears as follows: -- -+Anonymous authentication support is provided automatically when you use the HTTP configuration (introduced inSpring Security 3.0). -+You can customize (or disable) it by using the `` element. -+You need not configure the beans described here unless you are using traditional bean configuration. - -+Three classes work together to provide the anonymous authentication feature. -+`AnonymousAuthenticationToken` is an implementation of `Authentication` and stores the `GrantedAuthority` instancesthat apply to the anonymous principal. -+There is a corresponding `AnonymousAuthenticationProvider`, which is chained into the `ProviderManager` so that `AnonymousAuthenticationToken` instances are accepted. -+Finally, an `AnonymousAuthenticationFilter` is chained after the normal authentication mechanisms and automatically adds an `AnonymousAuthenticationToken` to the `SecurityContextHolder` if there is no existing `Authentication` held there. -+The filter and authentication provider is defined as follows: - -+==== - [source,xml] - ---- - -@@ -47,27 +44,24 @@ The definition of the filter and authentication provider appears as follows: - - - ---- -+==== - -+The `key` is shared between the filter and authentication provider so that tokens created by the former are accepted by the latter - -- --The `key` is shared between the filter and authentication provider, so that tokens created by the former are accepted by the latter footnote:[ --The use of the `key` property should not be regarded as providing any real security here. -+NOTE: The use of the `key` property should not be regarded as providing any real security here. - It is merely a book-keeping exercise. --If you are sharing a `ProviderManager` which contains an `AnonymousAuthenticationProvider` in a scenario where it is possible for an authenticating client to construct the `Authentication` object (such as with RMI invocations), then a malicious client could submit an `AnonymousAuthenticationToken` which it had created itself (with chosen username and authority list). --If the `key` is guessable or can be found out, then the token would be accepted by the anonymous provider. --This isn't a problem with normal usage but if you are using RMI you would be best to use a customized `ProviderManager` which omits the anonymous provider rather than sharing the one you use for your HTTP authentication mechanisms. --]. --The `userAttribute` is expressed in the form of `usernameInTheAuthenticationToken,grantedAuthority[,grantedAuthority]`. --This is the same syntax as used after the equals sign for the `userMap` property of `InMemoryDaoImpl`. -- --As explained earlier, the benefit of anonymous authentication is that all URI patterns can have security applied to them. --For example: -+If you share a `ProviderManager` that contains an `AnonymousAuthenticationProvider` in a scenario where it is possible for an authenticating client to construct the `Authentication` object (such as with RMI invocations), then a malicious client could submit an `AnonymousAuthenticationToken` that it had created itself (with the chosen username and authority list). -+If the `key` is guessable or can be found out, the token would be accepted by the anonymous provider. -+This is not a problem with normal usage. However, if you use RMI, you should use a customized `ProviderManager` that omits the anonymous provider rather than sharing the one you use for your HTTP authentication mechanisms. - -+The `userAttribute` is expressed in the form of `usernameInTheAuthenticationToken,grantedAuthority[,grantedAuthority]`. -+The same syntax is used after the equals sign for the `userMap` property of `InMemoryDaoImpl`. - -+As explained earlier, the benefit of anonymous authentication is that all URI patterns can have security applied to them, as the following example shows: - -+==== - [source,xml] - ---- -- - - -@@ -83,20 +77,18 @@ For example: - - - ---- -- -- -- -+==== - - [[anonymous-auth-trust-resolver]] - === 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. --If an `AccessDeniedException` is thrown, and the authentication is of an anonymous type, instead of throwing a 403 (forbidden) response, the filter will instead commence the `AuthenticationEntryPoint` so the principal can authenticate properly. --This is a necessary distinction, otherwise principals would always be deemed "authenticated" and never be given an opportunity to login via form, basic, digest or some other normal authentication mechanism. -+The `ExceptionTranslationFilter` uses this interface in processing `AccessDeniedException` instances. -+If an `AccessDeniedException` is thrown and the authentication is of an anonymous type, instead of throwing a 403 (forbidden) response, the filter, instead, commences the `AuthenticationEntryPoint` so that the principal can authenticate properly. -+This is a necessary distinction. Otherwise, principals would always be deemed "`authenticated`" and never be given an opportunity to login through form, basic, digest, or some other normal authentication mechanism. - --You will often see the `ROLE_ANONYMOUS` attribute in the above interceptor configuration replaced with `IS_AUTHENTICATED_ANONYMOUSLY`, which is effectively the same thing when defining access controls. --This is an example of the use of the `AuthenticatedVoter` which we will see in the <>. -+We often see the `ROLE_ANONYMOUS` attribute in the earlier interceptor configuration replaced with `IS_AUTHENTICATED_ANONYMOUSLY`, which is effectively the same thing when defining access controls. -+This is an example of the use of the `AuthenticatedVoter`, which we cover in the <>. - It uses an `AuthenticationTrustResolver` to process this particular configuration attribute and grant access to anonymous users. --The `AuthenticatedVoter` approach is more powerful, since it allows you to differentiate between anonymous, remember-me and fully-authenticated users. --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`. -+The `AuthenticatedVoter` approach is more powerful, since it lets you differentiate between anonymous, remember-me, and fully authenticated users. -+If you do not need this functionality, though, you can stick with `ROLE_ANONYMOUS`, which is processed by Spring Security's standard `RoleVoter`. -diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/architecture/abstract-authentication-processing-filter.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/architecture/abstract-authentication-processing-filter.adoc -index a3a8a48d18..c0801ee192 100644 ---- a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/architecture/abstract-authentication-processing-filter.adoc -+++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/architecture/abstract-authentication-processing-filter.adoc -@@ -4,7 +4,7 @@ - :icondir: images/icons - - {security-api-url}org/springframework/security/web/authentication/AbstractAuthenticationProcessingFilter.html[`AbstractAuthenticationProcessingFilter`] is used as a base `Filter` for authenticating a user's credentials. --Before the credentials can be authenticated, Spring Security typically requests the credentials using <>. -+Before the credentials can be authenticated, Spring Security typically requests the credentials by using <>. - - Next, the `AbstractAuthenticationProcessingFilter` can authenticate any authentication requests that are submitted to it. - -@@ -16,26 +16,26 @@ For example, <> is passed into the <> to be authenticated. - --image:{icondir}/number_3.png[] If authentication fails, then __Failure__ -+image:{icondir}/number_3.png[] If authentication fails, then __Failure__. - - * The <> is cleared out. - * `RememberMeServices.loginFail` is invoked. - If remember me is not configured, this is a no-op. --// FIXME: link to rememberme -+See the {security-api-url}org/springframework/security/web/authentication/rememberme/package-frame.html[`rememberme`] package. - * `AuthenticationFailureHandler` is invoked. --// FIXME: link to AuthenticationFailureHandler -+See the {security-api-url}org/springframework/security/web/authentication/AuthenticationFailureHandler.html[`AuthenticationFailureHandler`] interface. - - image:{icondir}/number_4.png[] If authentication is successful, then __Success__. - --* `SessionAuthenticationStrategy` is notified of a new log in. --// FIXME: Add link to SessionAuthenticationStrategy -+* `SessionAuthenticationStrategy` is notified of a new login. -+See the {security-api-url}org/springframework/security/web/authentication/session/SessionAuthenticationStrategy.html[`SessionAuthenticationStrategy`] interface. - * The <> is set on the <>. --Later the `SecurityContextPersistenceFilter` saves the `SecurityContext` to the `HttpSession`. --// FIXME: link securitycontextpersistencefilter -+Later, the `SecurityContextPersistenceFilter` saves the `SecurityContext` to the `HttpSession`. -+See the {security-api-url}org/springframework/security/web/context/SecurityContextPersistenceFilter.html[`SecurityContextPersistenceFilter`] class. - * `RememberMeServices.loginSuccess` is invoked. - If remember me is not configured, this is a no-op. --// FIXME: link to rememberme -+See the {security-api-url}org/springframework/security/web/authentication/rememberme/package-frame.html[`rememberme`] package. - * `ApplicationEventPublisher` publishes an `InteractiveAuthenticationSuccessEvent`. - * `AuthenticationSuccessHandler` is invoked. - // FIXME: link to AuthenticationSuccessHandler -- -+See the {security-api-url}org/springframework/security/web/authentication/AuthenticationSuccessHandler.html[`AuthenticationSuccessHandler`] interface. -diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/architecture/authentication-entry-point.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/architecture/authentication-entry-point.adoc -index cdc00dddbc..0218b752bc 100644 ---- a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/architecture/authentication-entry-point.adoc -+++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/architecture/authentication-entry-point.adoc -@@ -4,11 +4,9 @@ - - {security-api-url}org/springframework/security/web/AuthenticationEntryPoint.html[`AuthenticationEntryPoint`] is used to send an HTTP response that requests credentials from a client. - --Sometimes a client will proactively include credentials such as a username/password to request a resource. --In these cases, Spring Security does not need to provide an HTTP response that requests credentials from the client since they are already included. -+Sometimes, a client proactively includes credentials (such as a username and password) to request a resource. -+In these cases, Spring Security does not need to provide an HTTP response that requests credentials from the client, since they are already included. - --In other cases, a client will make an unauthenticated request to a resource that they are not authorized to access. -+In other cases, a client makes an unauthenticated request to a resource that they are not authorized to access. - In this case, an implementation of `AuthenticationEntryPoint` is used to request credentials from the client. --The `AuthenticationEntryPoint` implementation might perform a <>, respond with an <> header, etc. -- -- -+The `AuthenticationEntryPoint` implementation might perform a <>, respond with an <> header, or take other action. -diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/architecture/authentication-manager.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/architecture/authentication-manager.adoc -index 5c85382b71..5993364378 100644 ---- a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/architecture/authentication-manager.adoc -+++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/architecture/authentication-manager.adoc -@@ -2,8 +2,8 @@ - = AuthenticationManager - - {security-api-url}org/springframework/security/authentication/AuthenticationManager.html[`AuthenticationManager`] is the API that defines how Spring Security's Filters perform <>. --The <> that is returned is then set on the <> by the controller (i.e. <>) that invoked the `AuthenticationManager`. --If you are not integrating with __Spring Security's ``Filters``s__ you can set the `SecurityContextHolder` directly and are not required to use an `AuthenticationManager`. -+The <> that is returned is then set on the <> by the controller (that is, by <>) that invoked the `AuthenticationManager`. -+If you are not integrating with Spring Security's `Filters` instances, you can set the `SecurityContextHolder` directly and are not required to use an `AuthenticationManager`. - - While the implementation of `AuthenticationManager` could be anything, the most common implementation is <>. - // FIXME: add configuration -diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/architecture/authentication-provider.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/architecture/authentication-provider.adoc -index c7cb0b7b6c..3932504e34 100644 ---- a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/architecture/authentication-provider.adoc -+++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/architecture/authentication-provider.adoc -@@ -1,6 +1,6 @@ - [[servlet-authentication-authenticationprovider]] - = AuthenticationProvider - --Multiple {security-api-url}org/springframework/security/authentication/AuthenticationProvider.html[``AuthenticationProvider``s] can be injected into <>. -+You can inject multiple {security-api-url}org/springframework/security/authentication/AuthenticationProvider.html[`AuthenticationProvider`] instances into <>. - Each `AuthenticationProvider` performs a specific type of authentication. --For example, <> supports username/password based authentication while `JwtAuthenticationProvider` supports authenticating a JWT token. -+For example, <> supports username/password-based authentication, while `JwtAuthenticationProvider` supports authenticating a JWT token. -diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/architecture/authentication.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/architecture/authentication.adoc -index 2e7319c4ae..170d180f06 100644 ---- a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/architecture/authentication.adoc -+++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/architecture/authentication.adoc -@@ -1,18 +1,18 @@ - [[servlet-authentication-authentication]] - = Authentication - --The {security-api-url}org/springframework/security/core/Authentication.html[`Authentication`] serves two main purposes within Spring Security: -+The {security-api-url}org/springframework/security/core/Authentication.html[`Authentication`] interface serves two main purposes within Spring Security: - - * An input to <> to provide the credentials a user has provided to authenticate. - When used in this scenario, `isAuthenticated()` returns `false`. --* Represents the currently authenticated user. --The current `Authentication` can be obtained from the <>. -+* Represent the currently authenticated user. -+You can obtain the current `Authentication` from the <>. - - The `Authentication` contains: - --* `principal` - identifies the user. -+* `principal`: Identifies the user. - When authenticating with a username/password this is often an instance of <>. --* `credentials` - Often a password. --In many cases this will be cleared after the user is authenticated to ensure it is not leaked. --* `authorities` - the <> are high level permissions the user is granted. --A few examples are roles or scopes. -+* `credentials`: Often a password. -+In many cases, this is cleared after the user is authenticated, to ensure that it is not leaked. -+* `authorities`: The <> instances are high-level permissions the user is granted. -+Two examples are roles and scopes. -diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/architecture/granted-authority.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/architecture/granted-authority.adoc -index 19b45cd049..98afa85f11 100644 ---- a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/architecture/granted-authority.adoc -+++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/architecture/granted-authority.adoc -@@ -1,16 +1,16 @@ - [[servlet-authentication-granted-authority]] - = GrantedAuthority --{security-api-url}org/springframework/security/core/GrantedAuthority.html[``GrantedAuthority``s] are high level permissions the user is granted. A few examples are roles or scopes. -+{security-api-url}org/springframework/security/core/GrantedAuthority.html[`GrantedAuthority`] instances are high-level permissions that the user is granted. Two examples are roles and scopes. - --``GrantedAuthority``s can be obtained from the <> method. -+You can obtain `GrantedAuthority` instances from the <> method. - This method provides a `Collection` of `GrantedAuthority` objects. - A `GrantedAuthority` is, not surprisingly, an authority that is granted to the principal. --Such authorities are usually "roles", such as `ROLE_ADMINISTRATOR` or `ROLE_HR_SUPERVISOR`. --These roles are later on configured for web authorization, method authorization and domain object authorization. --Other parts of Spring Security are capable of interpreting these authorities, and expect them to be present. --When using username/password based authentication ``GrantedAuthority``s are usually loaded by the <>. -+Such authorities are usually "`roles`", such as `ROLE_ADMINISTRATOR` or `ROLE_HR_SUPERVISOR`. -+These roles are later configured for web authorization, method authorization, and domain object authorization. -+Other parts of Spring Security interpret these authorities and expect them to be present. -+When using username/password based authentication `GrantedAuthority` instances are usually loaded by the <>. - --Usually the `GrantedAuthority` objects are application-wide permissions. -+Usually, the `GrantedAuthority` objects are application-wide permissions. - They are not specific to a given domain object. --Thus, you wouldn't likely have a `GrantedAuthority` to represent a permission to `Employee` object number 54, because if there are thousands of such authorities you would quickly run out of memory (or, at the very least, cause the application to take a long time to authenticate a user). --Of course, Spring Security is expressly designed to handle this common requirement, but you'd instead use the project's domain object security capabilities for this purpose. -+Thus, you would not likely have a `GrantedAuthority` to represent a permission to `Employee` object number 54, because if there are thousands of such authorities you would quickly run out of memory (or, at the very least, cause the application to take a long time to authenticate a user). -+Of course, Spring Security is expressly designed to handle this common requirement, but you should instead use the project's domain object security capabilities for this purpose. -diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/architecture/provider-manager.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/architecture/provider-manager.adoc -index 4ed8cb4615..5dc80d7f60 100644 ---- a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/architecture/provider-manager.adoc -+++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/architecture/provider-manager.adoc -@@ -3,18 +3,18 @@ - :figures: images/servlet/authentication/architecture - - {security-api-url}org/springframework/security/authentication/ProviderManager.html[`ProviderManager`] is the most commonly used implementation of <>. --`ProviderManager` delegates to a `List` of <>. --// FIXME: link to AuthenticationProvider -+`ProviderManager` delegates to a `List` of <> instances. -+(See the Javadoc for the {security-api-url}org/springframework/security/authentication/AuthenticationProvider.html[`AuthenticationProvider`]. - Each `AuthenticationProvider` has an opportunity to indicate that authentication should be successful, fail, or indicate it cannot make a decision and allow a downstream `AuthenticationProvider` to decide. --If none of the configured ``AuthenticationProvider``s can authenticate, then authentication will fail with a `ProviderNotFoundException` which is a special `AuthenticationException` that indicates the `ProviderManager` was not configured to support the type of `Authentication` that was passed into it. -+If none of the configured `AuthenticationProvider` instances can authenticate, authentication fails with a `ProviderNotFoundException`, which is a special `AuthenticationException` that indicates that the `ProviderManager` was not configured to support the type of `Authentication` that was passed into it. - - image::{figures}/providermanager.png[] - - In practice each `AuthenticationProvider` knows how to perform a specific type of authentication. -- For example, one `AuthenticationProvider` might be able to validate a username/password, while another might be able to authenticate a SAML assertion. --This allows each `AuthenticationProvider` to do a very specific type of authentication, while supporting multiple types of authentication and only exposing a single `AuthenticationManager` bean. -+For example, one `AuthenticationProvider` might be able to validate a username/password, while another might be able to authenticate a SAML assertion. -+This lets each `AuthenticationProvider` do a very specific type of authentication while supporting multiple types of authentication and expose only a single `AuthenticationManager` bean. - --`ProviderManager` also allows configuring an optional parent `AuthenticationManager` which is consulted in the event that no `AuthenticationProvider` can perform authentication. -+`ProviderManager` also allows configuring an optional parent `AuthenticationManager`, which is consulted in the event that no `AuthenticationProvider` can perform authentication. - The parent can be any type of `AuthenticationManager`, but it is often an instance of `ProviderManager`. - - image::{figures}/providermanager-parent.png[] -@@ -25,12 +25,12 @@ This is somewhat common in scenarios where there are multiple <>. - Spring Security does not care how the `SecurityContextHolder` is populated. --If it contains a value, then it is used as the currently authenticated user. -+If it contains a value, it is used as the currently authenticated user. - --The simplest way to indicate a user is authenticated is to set the `SecurityContextHolder` directly. -+The simplest way to indicate a user is authenticated is to set the `SecurityContextHolder` directly: - - .Setting `SecurityContextHolder` - ==== -@@ -36,18 +36,18 @@ context.authentication = authentication - - SecurityContextHolder.setContext(context) // <3> - ---- --==== - - <1> We start by creating an empty `SecurityContext`. --It is important to create a new `SecurityContext` instance instead of using `SecurityContextHolder.getContext().setAuthentication(authentication)` to avoid race conditions across multiple threads. --<2> Next we create a new <> object. -+You should create a new `SecurityContext` instance instead of using `SecurityContextHolder.getContext().setAuthentication(authentication)` to avoid race conditions across multiple threads. -+<2> Next, we create a new <> object. - Spring Security does not care what type of `Authentication` implementation is set on the `SecurityContext`. --Here we use `TestingAuthenticationToken` because it is very simple. -+Here, we use `TestingAuthenticationToken`, because it is very simple. - A more common production scenario is `UsernamePasswordAuthenticationToken(userDetails, password, authorities)`. - <3> Finally, we set the `SecurityContext` on the `SecurityContextHolder`. --Spring Security will use this information for <>. -+Spring Security uses this information for <>. -+==== - --If you wish to obtain information about the authenticated principal, you can do so by accessing the `SecurityContextHolder`. -+To obtain information about the authenticated principal, access the `SecurityContextHolder`. - - .Access Currently Authenticated User - ==== -@@ -72,18 +72,18 @@ val authorities = authentication.authorities - ---- - ==== - --// FIXME: add links to HttpServletRequest.getRemoteUser() and @CurrentSecurityContext @AuthenticationPrincipal -+// FIXME: Add links to and relevant description of HttpServletRequest.getRemoteUser() and @CurrentSecurityContext @AuthenticationPrincipal - --By default the `SecurityContextHolder` uses a `ThreadLocal` to store these details, which means that the `SecurityContext` is always available to methods in the same thread, even if the `SecurityContext` is not explicitly passed around as an argument to those methods. --Using a `ThreadLocal` in this way is quite safe if care is taken to clear the thread after the present principal's request is processed. -+By default, `SecurityContextHolder` uses a `ThreadLocal` to store these details, which means that the `SecurityContext` is always available to methods in the same thread, even if the `SecurityContext` is not explicitly passed around as an argument to those methods. -+Using a `ThreadLocal` in this way is quite safe if you take care to clear the thread after the present principal's request is processed. - Spring Security's <> ensures that the `SecurityContext` is always cleared. - --Some applications aren't entirely suitable for using a `ThreadLocal`, because of the specific way they work with threads. -+Some applications are not entirely suitable for using a `ThreadLocal`, because of the specific way they work with threads. - For example, a Swing client might want all threads in a Java Virtual Machine to use the same security context. --`SecurityContextHolder` can be configured with a strategy on startup to specify how you would like the context to be stored. --For a standalone application you would use the `SecurityContextHolder.MODE_GLOBAL` strategy. -+You can configure `SecurityContextHolder` with a strategy on startup to specify how you would like the context to be stored. -+For a standalone application, you would use the `SecurityContextHolder.MODE_GLOBAL` strategy. - Other applications might want to have threads spawned by the secure thread also assume the same security identity. --This is achieved by using `SecurityContextHolder.MODE_INHERITABLETHREADLOCAL`. -+You can achieve this by using `SecurityContextHolder.MODE_INHERITABLETHREADLOCAL`. - You can change the mode from the default `SecurityContextHolder.MODE_THREADLOCAL` in two ways. --The first is to set a system property, the second is to call a static method on `SecurityContextHolder`. --Most applications won't need to change from the default, but if you do, take a look at the JavaDoc for `SecurityContextHolder` to learn more. -+The first is to set a system property. The second is to call a static method on `SecurityContextHolder`. -+Most applications need not change from the default. However, if you do, take a look at the JavaDoc for `SecurityContextHolder` to learn more. -diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/cas.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/cas.adoc -index 31436ad1f2..310044eca6 100644 ---- a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/cas.adoc -+++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/cas.adoc -@@ -2,106 +2,108 @@ - == CAS Authentication - - [[cas-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. -+Unlike other initiatives, JA-SIG's Central Authentication Service is open source, widely used, simple to understand, and platform-independent. It also supports proxy capabilities. -+Spring Security fully supports CAS and provides an easy migration path from single-application deployments of Spring Security to multiple-application deployments secured by an enterprise-wide CAS server. - - 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. -+You also need to visit this site to download the CAS Server files. - - [[cas-how-it-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. -+While 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 (and later) supports CAS 3 (and later). -+At the time of writing, the CAS server is at version 6.3.3. - --Somewhere in your enterprise you will need to setup a CAS server. --The CAS server is simply a standard WAR file, so there isn't anything difficult about setting up your server. --Inside the WAR file you will customise the login and other single sign on pages displayed to users. -+NOTE: This section was written about CAS version 3.4, but the material is still current. - --When deploying a CAS 3.4 server, you will also need to specify an `AuthenticationHandler` in the `deployerConfigContext.xml` included with CAS. --The `AuthenticationHandler` has a simple method that returns a boolean as to whether a given set of Credentials is valid. --Your `AuthenticationHandler` implementation will need to link into some type of backend authentication repository, such as an LDAP server or database. --CAS itself includes numerous `AuthenticationHandler` s out of the box to assist with this. --When you download and deploy the server war file, it is set up to successfully authenticate users who enter a password matching their username, which is useful for testing. -+Somewhere in your enterprise, you need to setup a CAS server. -+The CAS server runs from a standard WAR file. -+Inside the WAR file, you need to customize the login and other single-sign-on pages displayed to users. - --Apart from the CAS server itself, the other key players are of course the secure web applications deployed throughout your enterprise. --These web applications are known as "services". --There are three types of services. --Those that authenticate service tickets, those that can obtain proxy tickets, and those that authenticate proxy tickets. --Authenticating a proxy ticket differs because the list of proxies must be validated and often times a proxy ticket can be reused. -+When deploying a CAS 3.4 server, you also need to specify an `AuthenticationHandler` in the `deployerConfigContext.xml` included with CAS. -+The `AuthenticationHandler` has a simple method that returns a boolean as to whether a given set of credentials is valid. -+Your `AuthenticationHandler` implementation needs to link into some type of backend authentication repository, such as an LDAP server or database. -+CAS itself includes numerous `AuthenticationHandler` implementations to assist with this. -+When you download and deploy the server war file, it is set up to successfully authenticate users who enter a password that matches their username, which is useful for testing. - -+Apart from the CAS server itself, the other key players are the secure web applications deployed throughout your enterprise. -+These web applications are known as "`services`". -+There are three types of services: -+ -+* Services that authenticate service tickets -+* Services that can obtain proxy tickets -+* Services that authenticate proxy tickets. -+ -+Authenticating a proxy ticket differs because the list of proxies must be validated and because, oftentimes, a proxy ticket can be reused. - - [[cas-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 basic interaction between a web browser, a CAS server, and a Spring Security-secured service is as follows: - --* The web user is browsing the service's public pages. -+. The web user browses the service's public pages. - CAS or Spring Security is not involved. --* The user eventually requests a page that is either secure or one of the beans it uses is secure. --Spring Security's `ExceptionTranslationFilter` will detect the `AccessDeniedException` or `AuthenticationException`. --* Because the user's `Authentication` object (or lack thereof) caused an `AuthenticationException`, the `ExceptionTranslationFilter` will call the configured `AuthenticationEntryPoint`. --If using CAS, this will be the `CasAuthenticationEntryPoint` class. --* The `CasAuthenticationEntryPoint` will redirect the user's browser to the CAS server. --It will also indicate a `service` parameter, which is the callback URL for the Spring Security service (your application). -+. The user eventually requests a page that is either secure or that uses a secure bean. -+Spring Security's `ExceptionTranslationFilter` detects the `AccessDeniedException` or `AuthenticationException`. -+. Because the user's `Authentication` object (or lack thereof) caused an `AuthenticationException`, the `ExceptionTranslationFilter` calls the configured `AuthenticationEntryPoint`. -+If using CAS, this is the `CasAuthenticationEntryPoint` class. -+. The `CasAuthenticationEntryPoint` redirects the user's browser to the CAS server. -+It also indicates a `service` parameter, which is the callback URL for the Spring Security service (your application). - For example, the URL to which the browser is redirected might be https://my.company.com/cas/login?service=https%3A%2F%2Fserver3.company.com%2Fwebapp%2Flogin/cas. --* After the user's browser redirects to CAS, they will be prompted for their username and password. --If the user presents a session cookie which indicates they've previously logged on, they will not be prompted to login again (there is an exception to this procedure, which we'll cover later). --CAS will use the `PasswordHandler` (or `AuthenticationHandler` if using CAS 3.0) discussed above to decide whether the username and password is valid. --* Upon successful login, CAS will redirect the user's browser back to the original service. --It will also include a `ticket` parameter, which is an opaque string representing the "service ticket". --Continuing our earlier example, the URL the browser is redirected to might be https://server3.company.com/webapp/login/cas?ticket=ST-0-ER94xMJmn6pha35CQRoZ. --* Back in the service web application, the `CasAuthenticationFilter` is always listening for requests to `/login/cas` (this is configurable, but we'll use the defaults in this introduction). --The processing filter will construct a `UsernamePasswordAuthenticationToken` representing the service ticket. --The principal will be equal to `CasAuthenticationFilter.CAS_STATEFUL_IDENTIFIER`, whilst the credentials will be the service ticket opaque value. --This authentication request will then be handed to the configured `AuthenticationManager`. --* The `AuthenticationManager` implementation will be the `ProviderManager`, which is in turn configured with the `CasAuthenticationProvider`. --The `CasAuthenticationProvider` only responds to `UsernamePasswordAuthenticationToken` s containing the CAS-specific principal (such as `CasAuthenticationFilter.CAS_STATEFUL_IDENTIFIER`) and `CasAuthenticationToken` s (discussed later). --* `CasAuthenticationProvider` will validate the service ticket using a `TicketValidator` implementation. --This will typically be a `Cas20ServiceTicketValidator` which is one of the classes included in the CAS client library. --In the event the application needs to validate proxy tickets, the `Cas20ProxyTicketValidator` is used. --The `TicketValidator` makes an HTTPS request to the CAS server in order to validate the service ticket. --It may also include a proxy callback URL, which is included in this example: https://my.company.com/cas/proxyValidate?service=https%3A%2F%2Fserver3.company.com%2Fwebapp%2Flogin/cas&ticket=ST-0-ER94xMJmn6pha35CQRoZ&pgtUrl=https://server3.company.com/webapp/login/cas/proxyreceptor. --* Back on the CAS server, the validation request will be received. --If the presented service ticket matches the service URL the ticket was issued to, CAS will provide an affirmative response in XML indicating the username. --If any proxy was involved in the authentication (discussed below), the list of proxies is also included in the XML response. --* [OPTIONAL] If the request to the CAS validation service included the proxy callback URL (in the `pgtUrl` parameter), CAS will include a `pgtIou` string in the XML response. -+. After the user's browser redirects to CAS, they are prompted for their username and password. -+If the user presents a session cookie that indicates that they have previously logged on, they are not prompted to login again (there is an exception to this procedure, which we cover later). -+CAS uses the `PasswordHandler` (or `AuthenticationHandler` if using CAS 3.0) discussed earler to decide whether the username and password are valid. -+. Upon successful login, CAS redirects the user's browser back to the original service. -+It also includes a `ticket` parameter, which is an opaque string that represents the "`service ticket`". -+Continuing our earlier example, the URL to which the browser is redirected might be https://server3.company.com/webapp/login/cas?ticket=ST-0-ER94xMJmn6pha35CQRoZ. -+. Back in the service web application, the `CasAuthenticationFilter` is always listening for requests to `/login/cas` (this is configurable, but we use the defaults in this introduction). -+The processing filter constructs a `UsernamePasswordAuthenticationToken` that represents the service ticket. -+The principal is equal to `CasAuthenticationFilter.CAS_STATEFUL_IDENTIFIER`, while the credentials are the service ticket opaque value. -+This authentication request is then handed to the configured `AuthenticationManager`. -+. The `AuthenticationManager` implementation is the `ProviderManager`, which is in turn configured with the `CasAuthenticationProvider`. -+The `CasAuthenticationProvider` only responds to `UsernamePasswordAuthenticationToken` instances that contain the CAS-specific principal (such as `CasAuthenticationFilter.CAS_STATEFUL_IDENTIFIER`) and `CasAuthenticationToken` instances (discussed later). -+. `CasAuthenticationProvider` will validate the service ticket using a `TicketValidator` implementation. -+This is typically a `Cas20ServiceTicketValidator`, which is one of the classes included in the CAS client library. -+If the application needs to validate proxy tickets, the `Cas20ProxyTicketValidator` is used. -+The `TicketValidator` makes an HTTPS request to the CAS server to validate the service ticket. -+It can also include a proxy callback URL, which is included in this example: https://my.company.com/cas/proxyValidate?service=https%3A%2F%2Fserver3.company.com%2Fwebapp%2Flogin/cas&ticket=ST-0-ER94xMJmn6pha35CQRoZ&pgtUrl=https://server3.company.com/webapp/login/cas/proxyreceptor. -+. Back on the CAS server, the validation request is received. -+If the presented service ticket matches the service URL to which the ticket was issued, CAS provides an affirmative response in XML that indicates the username. -+If any proxy was involved in the authentication (discussed later), the list of proxies is also included in the XML response. -+. [OPTIONAL] If the request to the CAS validation service included the proxy callback URL (in the `pgtUrl` parameter), CAS includes a `pgtIou` string in the XML response. - This `pgtIou` represents a proxy-granting ticket IOU. --The CAS server will then create its own HTTPS connection back to the `pgtUrl`. -+The CAS server thens create its own HTTPS connection back to the `pgtUrl`. - This is to mutually authenticate the CAS server and the claimed service URL. --The HTTPS connection will be used to send a proxy granting ticket to the original web application. --For example, https://server3.company.com/webapp/login/cas/proxyreceptor?pgtIou=PGTIOU-0-R0zlgrl4pdAQwBvJWO3vnNpevwqStbSGcq3vKB2SqSFFRnjPHt&pgtId=PGT-1-si9YkkHLrtACBo64rmsi3v2nf7cpCResXg5MpESZFArbaZiOKH. --* The `Cas20TicketValidator` will parse the XML received from the CAS server. --It will return to the `CasAuthenticationProvider` a `TicketResponse`, which includes the username (mandatory), proxy list (if any were involved), and proxy-granting ticket IOU (if the proxy callback was requested). --* Next `CasAuthenticationProvider` will call a configured `CasProxyDecider`. -+The HTTPS connection is used to send a proxy granting ticket to the original web application -- -+for example, https://server3.company.com/webapp/login/cas/proxyreceptor?pgtIou=PGTIOU-0-R0zlgrl4pdAQwBvJWO3vnNpevwqStbSGcq3vKB2SqSFFRnjPHt&pgtId=PGT-1-si9YkkHLrtACBo64rmsi3v2nf7cpCResXg5MpESZFArbaZiOKH. -+. The `Cas20TicketValidator` parses the XML received from the CAS server. -+It returns to the `CasAuthenticationProvider` a `TicketResponse`, which includes the username (mandatory), proxy list (if any were involved), and proxy-granting ticket IOU (if the proxy callback was requested). -+. Next `CasAuthenticationProvider` calls a configured `CasProxyDecider`. - The `CasProxyDecider` indicates whether the proxy list in the `TicketResponse` is acceptable to the service. --Several implementations are provided with Spring Security: `RejectProxyTickets`, `AcceptAnyCasProxy` and `NamedCasProxyDecider`. --These names are largely self-explanatory, except `NamedCasProxyDecider` which allows a `List` of trusted proxies to be provided. --* `CasAuthenticationProvider` will next request a `AuthenticationUserDetailsService` to load the `GrantedAuthority` objects that apply to the user contained in the `Assertion`. --* If there were no problems, `CasAuthenticationProvider` constructs a `CasAuthenticationToken` including the details contained in the `TicketResponse` and the ``GrantedAuthority``s. --* Control then returns to `CasAuthenticationFilter`, which places the created `CasAuthenticationToken` in the security context. --* The user's browser is redirected to the original page that caused the `AuthenticationException` (or a custom destination depending on the configuration). -+Spring Security provides three implementations: `RejectProxyTickets`, `AcceptAnyCasProxy`, and `NamedCasProxyDecider`. -+These names are largely self-explanatory, except `NamedCasProxyDecider`, which allows a `List` of trusted proxies to be provided. -+. `CasAuthenticationProvider` next requests a `AuthenticationUserDetailsService` to load the `GrantedAuthority` objects that apply to the user contained in the `Assertion`. -+. If there were no problems, `CasAuthenticationProvider` constructs a `CasAuthenticationToken`, including the details contained in the `TicketResponse` and the `GrantedAuthority` instances. -+. Control then returns to `CasAuthenticationFilter`, which places the created `CasAuthenticationToken` in the security context. -+. The user's browser is redirected to the original page that caused the `AuthenticationException` (or a custom destination depending on the configuration). - --It's good that you're still here! --Let's now look at how this is configured -+Next, we discuss how to configure the components that are involved in that long interaction. - - [[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. -+Spring Security makes the web application side of CAS easy. -+We assume you already know the basics of using Spring Security, so these are not covered again later. -+We also assume a namespace-based configuration is being used and add in the CAS beans as required. - Each section builds upon the previous section. --A full CAS sample application can be found in the Spring Security <>. -- -+You can find a full CAS sample application in the Spring Security <>. - - [[cas-st]] - ==== 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. --This represents your CAS service: -+This section describes how to set up Spring Security to authenticate Service Tickets. -+Oftentimes, this is all a web application requires. -+You need to add a `ServiceProperties` bean to your application context to represent your CAS service: - -+==== - [source,xml] - ---- - - - ---- -+==== - --The `service` must equal a URL that will be monitored by the `CasAuthenticationFilter`. --The `sendRenew` defaults to false, but should be set to true if your application is particularly sensitive. --What this parameter does is tell the CAS login service that a single sign on login is unacceptable. --Instead, the user will need to re-enter their username and password in order to gain access to the service. -+The `service` must equal a URL that is monitored by the `CasAuthenticationFilter`. -+`sendRenew` defaults to `false` but should be set to `true` if your application is particularly sensitive. -+This parameter tells the CAS login service that a single-sign-on login is unacceptable. -+Instead, the user needs to re-enter their username and password to gain access to the service. - --The following beans should be configured to commence the CAS authentication process (assuming you're using a namespace configuration): -+The following beans should be configured to commence the CAS authentication process (assuming you use a namespace configuration): - -+==== - [source,xml] - ---- - -@@ -137,17 +141,19 @@ The following beans should be configured to commence the CAS authentication proc - - - ---- -+==== - - For CAS to operate, the `ExceptionTranslationFilter` must have its `authenticationEntryPoint` property set to the `CasAuthenticationEntryPoint` bean. --This can easily be done using <> as is done in the example above. --The `CasAuthenticationEntryPoint` must refer to the `ServiceProperties` bean (discussed above), which provides the URL to the enterprise's CAS login server. --This is where the user's browser will be redirected. -+You can do so by using <>, as in the preceding example. -+The `CasAuthenticationEntryPoint` must refer to the `ServiceProperties` bean (discussed earlier), which provides the URL to the enterprise's CAS login server. -+This is where the user's browser is redirected. - - The `CasAuthenticationFilter` has very similar properties to the `UsernamePasswordAuthenticationFilter` (used for form-based logins). - You can use these properties to customize things like behavior for authentication success and failure. - --Next you need to add a `CasAuthenticationProvider` and its collaborators: -+Next, you need to add a `CasAuthenticationProvider` and its collaborators: - -+==== - [source,xml,attrs="-attributes"] - ---- - -@@ -180,24 +186,25 @@ Normally passwords should be hashed using BCrypt --> - ... - - ---- -+==== - - The `CasAuthenticationProvider` uses a `UserDetailsService` instance to load the authorities for a user, once they have been authenticated by CAS. --We've shown a simple in-memory setup here. -+We have shown a simple in-memory setup here. - Note that the `CasAuthenticationProvider` does not actually use the password for authentication, but it does use the authorities. - - The beans are all reasonably self-explanatory if you refer back to the <> section. - - This completes the most basic configuration for CAS. --If you haven't made any mistakes, your web application should happily work within the framework of CAS single sign on. --No other parts of Spring Security need to be concerned about the fact CAS handled authentication. --In the following sections we will discuss some (optional) more advanced configurations. -- -+If you have not made any mistakes, your web application should happily work within the framework of CAS single sign on. -+No other parts of Spring Security need to be concerned about the fact that CAS handled authentication. -+In the following sections, we discuss some (optional) more advanced configurations. - - [[cas-singlelogout]] - ==== 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 -+The following updates to the Spring Security configuration handle Single Logout: - -+==== - [source,xml] - ---- - -@@ -221,26 +228,26 @@ Below are updates to the Spring Security configuration that handle Single Logout - - - ---- -+==== - --The `logout` element logs the user out of the local application, but does not end the session with the CAS server or any other applications that have been logged into. --The `requestSingleLogoutFilter` filter will allow the URL of `/spring_security_cas_logout` to be requested to redirect the application to the configured CAS Server logout URL. --Then the CAS Server will send a Single Logout request to all the services that were signed into. -+The `logout` element logs the user out of the local application but does not end the session with the CAS server or any other applications that have been logged into. -+The `requestSingleLogoutFilter` filter lets the URL of `/spring_security_cas_logout` be requested to redirect the application to the configured CAS Server logout URL. -+Then the CAS Server sends a Single Logout request to all the services that were signed into. - The `singleLogoutFilter` handles the Single Logout request by looking up the `HttpSession` in a static `Map` and then invalidating it. - - It might be confusing why both the `logout` element and the `singleLogoutFilter` are needed. --It is considered best practice to logout locally first since the `SingleSignOutFilter` just stores the `HttpSession` in a static `Map` in order to call invalidate on it. -+It is considered best practice to logout locally first, since the `SingleSignOutFilter` just stores the `HttpSession` in a static `Map` in order to invalidate it. - With the configuration above, the flow of logout would be: - --* The user requests `/logout` which would log the user out of the local application and send the user to the logout success page. --* The logout success page, `/cas-logout.jsp`, should instruct the user to click a link pointing to `/logout/cas` in order to logout out of all applications. -+* The user requests `/logout`, which would log the user out of the local application and send the user to the logout success page. -+* The logout success page, `/cas-logout.jsp`, should instruct the user to click a link that points to `/logout/cas`, to logout out of all applications. - * When the user clicks the link, the user is redirected to the CAS single logout URL (https://localhost:9443/cas/logout). - * On the CAS Server side, the CAS single logout URL then submits single logout requests to all the CAS Services. - On the CAS Service side, JASIG's `SingleSignOutFilter` processes the logout request by invalidating the original session. - -+The next step is to add the following to your `web.xml` file: - -- --The next step is to add the following to your web.xml -- -+==== - [source,xml] - ---- - -@@ -263,45 +270,49 @@ The next step is to add the following to your web.xml - - - ---- -+==== - --When using the SingleSignOutFilter you might encounter some encoding issues. --Therefore it is recommended to add the `CharacterEncodingFilter` to ensure that the character encoding is correct when using the `SingleSignOutFilter`. --Again, refer to JASIG's documentation for details. -+When using the `SingleSignOutFilter`, you might encounter some encoding issues. -+Therefore, we recommend adding the `CharacterEncodingFilter` to ensure that the character encoding is correct when using the `SingleSignOutFilter`. -+Again, see JASIG's documentation for details. - The `SingleSignOutHttpSessionListener` ensures that when an `HttpSession` expires, the mapping used for single logout is removed. - - - [[cas-pt-client]] - ==== 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. -+This section describes how to authenticate to a service by using CAS. -+In other words, this section discusses how to set up 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 --In order to authenticate to a stateless service, the application needs to obtain a proxy granting ticket (PGT). -+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. - - The first step is to include a `ProxyGrantingTicketStorage` in your Spring Security configuration. --This is used to store PGT's that are obtained by the `CasAuthenticationFilter` so that they can be used to obtain proxy tickets. --An example configuration is shown below -+This is used to store PGTs that are obtained by the `CasAuthenticationFilter` so that they can be used to obtain proxy tickets. -+The following example shows a typical configuration: - -+==== - [source,xml] - ---- - - - ---- -+==== - - The next step is to update the `CasAuthenticationProvider` to be able to obtain proxy tickets. --To do this replace the `Cas20ServiceTicketValidator` with a `Cas20ProxyTicketValidator`. --The `proxyCallbackUrl` should be set to a URL that the application will receive PGT's at. --Last, the configuration should also reference the `ProxyGrantingTicketStorage` so it can use a PGT to obtain proxy tickets. --You can find an example of the configuration changes that should be made below. -+To do so, replace the `Cas20ServiceTicketValidator` with a `Cas20ProxyTicketValidator`. -+The `proxyCallbackUrl` should be set to a URL that at which the application receives PGTs. -+Finally, the configuration should also reference the `ProxyGrantingTicketStorage` so that it can use a PGT to obtain proxy tickets. -+The following example shows the configuration changes that should be made: - -+==== - [source,xml] - ---- - - - ---- -+==== - --The last step is to update the `CasAuthenticationFilter` to accept PGT and to store them in the `ProxyGrantingTicketStorage`. --It is important the `proxyReceptorUrl` matches the `proxyCallbackUrl` of the `Cas20ProxyTicketValidator`. --An example configuration is shown below. -+The last step is to update the `CasAuthenticationFilter` to accept PGTs and to store them in the `ProxyGrantingTicketStorage`. -+The `proxyReceptorUrl` should match the `proxyCallbackUrl` of the `Cas20ProxyTicketValidator`. -+The following example shows a typical configuration: - -+==== - [source,xml] - ---- -- - - ... - - - -- - ---- -+==== - - [[cas-pt-client-sample]] --===== 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. -+===== Calling a Stateless Service by 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 <> contains a working example in the `ProxyTicketSampleServlet`. --Example code can be found below: -+The following listing shows an example: - -+==== - [source,java] - ---- - protected void doGet(HttpServletRequest request, HttpServletResponse response) -@@ -357,27 +370,29 @@ String proxyResponse = CommonUtils.getResponseFromServer(serviceUrl, "UTF-8"); - ... - } - ---- -+==== - - [[cas-pt]] - ==== 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`. -+A stateful client is considered to be any client that submits to the `filterProcessUrl` of the `CasAuthenticationFilter`. -+A stateless client is any client that presents an authentication request to `CasAuthenticationFilter` on a URL other than the `filterProcessUrl`. - --Because remoting protocols have no way of presenting themselves within the context of an `HttpSession`, it isn't possible to rely on the default practice of storing the security context in the session between requests. --Furthermore, because the CAS server invalidates a ticket after it has been validated by the `TicketValidator`, presenting the same proxy ticket on subsequent requests will not work. -+Because remoting protocols have no way of presenting themselves within the context of an `HttpSession`, it is not possible to rely on the default practice of storing the security context in the session between requests. -+Furthermore, because the CAS server invalidates a ticket after it has been validated by the `TicketValidator`, presenting the same proxy ticket on subsequent requests does not work. - - One obvious option is to not use CAS at all for remoting protocol clients. - However, this would eliminate many of the desirable features of CAS. - As a middle-ground, the `CasAuthenticationProvider` uses a `StatelessTicketCache`. --This is used solely for stateless clients which use a principal equal to `CasAuthenticationFilter.CAS_STATELESS_IDENTIFIER`. --What happens is the `CasAuthenticationProvider` will store the resulting `CasAuthenticationToken` in the `StatelessTicketCache`, keyed on the proxy ticket. --Accordingly, remoting protocol clients can present the same proxy ticket and the `CasAuthenticationProvider` will not need to contact the CAS server for validation (aside from the first request). --Once authenticated, the proxy ticket could be used for URLs other than the original target service. -+This is used solely for stateless clients that use a principal equal to `CasAuthenticationFilter.CAS_STATELESS_IDENTIFIER`. -+The `CasAuthenticationProvider` stores the resulting `CasAuthenticationToken` in the `StatelessTicketCache`, keyed on the proxy ticket. -+Accordingly, remoting protocol clients can present the same proxy ticket, and the `CasAuthenticationProvider` does not need to contact the CAS server for validation (aside from the first request). -+Once authenticated, the proxy ticket can be used for URLs other than the original target service. - - This section builds upon the previous sections to accommodate proxy ticket authentication. --The first step is to specify to authenticate all artifacts as shown below. -+The first step is to specify to authenticate all artifacts: - -+==== - [source,xml] - ---- - - - ---- -+==== - - The next step is to specify `serviceProperties` and the `authenticationDetailsSource` for the `CasAuthenticationFilter`. --The `serviceProperties` property instructs the `CasAuthenticationFilter` to attempt to authenticate all artifacts instead of only ones present on the `filterProcessUrl`. -+The `serviceProperties` property instructs the `CasAuthenticationFilter` to try to authenticate all artifacts instead of only ones present on the `filterProcessUrl`. - The `ServiceAuthenticationDetailsSource` creates a `ServiceAuthenticationDetails` that ensures the current URL, based upon the `HttpServletRequest`, is used as the service URL when validating the ticket. --The method for generating the service URL can be customized by injecting a custom `AuthenticationDetailsSource` that returns a custom `ServiceAuthenticationDetails`. -+You can customize the method for generating the service URL by injecting a custom `AuthenticationDetailsSource` that returns a custom `ServiceAuthenticationDetails`. - -+==== - [source,xml] - ---- - - - ---- -+==== - --You will also need to update the `CasAuthenticationProvider` to handle proxy tickets. --To do this replace the `Cas20ServiceTicketValidator` with a `Cas20ProxyTicketValidator`. --You will need to configure the `statelessTicketCache` and which proxies you want to accept. --You can find an example of the updates required to accept all proxies below. -+You also need to update the `CasAuthenticationProvider` to handle proxy tickets. -+To do so, replace the `Cas20ServiceTicketValidator` with a `Cas20ProxyTicketValidator`. -+You need to configure the `statelessTicketCache` and which proxies you want to accept. -+The following example shows the updates required to accept all proxies: - -+==== - [source,xml] - ---- - -@@ -441,3 +460,4 @@ You can find an example of the updates required to accept all proxies below. - - - ---- -+==== -diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/events.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/events.adoc -index 254df9a669..a97b2b17af 100644 ---- a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/events.adoc -+++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/events.adoc -@@ -1,10 +1,10 @@ - [[servlet-events]] - == Authentication Events - --For each authentication that succeeds or fails, a `AuthenticationSuccessEvent` or `AuthenticationFailureEvent` is fired, respectively. -+For each authentication that succeeds or fails, a `AuthenticationSuccessEvent` or `AuthenticationFailureEvent`, respectively, is fired. - - To listen for these events, you must first publish an `AuthenticationEventPublisher`. --Spring Security's `DefaultAuthenticationEventPublisher` will probably do fine: -+Spring Security's `DefaultAuthenticationEventPublisher` works fine for this purpose: - - ==== - .Java -@@ -28,7 +28,7 @@ fun authenticationEventPublisher - ---- - ==== - --Then, you can use Spring's `@EventListener` support: -+Then you can use Spring's `@EventListener` support: - - ==== - .Java -@@ -70,7 +70,7 @@ While similar to `AuthenticationSuccessHandler` and `AuthenticationFailureHandle - - === Adding Exception Mappings - --`DefaultAuthenticationEventPublisher` by default will publish an `AuthenticationFailureEvent` for the following events: -+By default, `DefaultAuthenticationEventPublisher` publishes an `AuthenticationFailureEvent` for the following events: - - |============ - | Exception | Event -@@ -85,9 +85,9 @@ While similar to `AuthenticationSuccessHandler` and `AuthenticationFailureHandle - | `InvalidBearerTokenException` | `AuthenticationFailureBadCredentialsEvent` - |============ - --The publisher does an exact `Exception` match, which means that sub-classes of these exceptions won't also produce events. -+The publisher does an exact `Exception` match, which means that sub-classes of these exceptions do not also produce events. - --To that end, you may want to supply additional mappings to the publisher via the `setAdditionalExceptionMappings` method: -+To that end, you may want to supply additional mappings to the publisher through the `setAdditionalExceptionMappings` method: - - ==== - .Java -@@ -123,7 +123,7 @@ fun authenticationEventPublisher - - === Default Event - --And, you can supply a catch-all event to fire in the case of any `AuthenticationException`: -+You can also supply a catch-all event to fire in the case of any `AuthenticationException`: - - ==== - .Java -diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/index.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/index.adoc -index 9536e950e6..0d0507f8cb 100644 ---- a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/index.adoc -+++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/index.adoc -@@ -7,34 +7,34 @@ This section discusses: - [[servlet-authentication-architecture]] - *Architecture Components* - --This section describes the main architectural components of Spring Security's used in Servlet authentication. --If you need concrete flows that explain how these pieces fit together, look at the <> specific sections. -- --* <> - The `SecurityContextHolder` is where Spring Security stores the details of who is <>. --* <> - is obtained from the `SecurityContextHolder` and contains the `Authentication` of the currently authenticated user. --* <> - Can be the input to `AuthenticationManager` to provide the credentials a user has provided to authenticate or the current user from the `SecurityContext`. --* <> - An authority that is granted to the principal on the `Authentication` (i.e. roles, scopes, etc.) --* <> - the API that defines how Spring Security's Filters perform <>. --* <> - the most common implementation of `AuthenticationManager`. --* <> - used by `ProviderManager` to perform a specific type of authentication. --* <> - used for requesting credentials from a client (i.e. redirecting to a log in page, sending a `WWW-Authenticate` response, etc.) --* <> - a base `Filter` used for authentication. --This also gives a good idea of the high level flow of authentication and how pieces work together. -+This section describes the main architectural components of Spring Security that are used in Servlet authentication. -+If you need concrete flows that explain how these pieces fit together, see the <> specific sections. -+ -+* <>: The `SecurityContextHolder` is where Spring Security stores the details of who is <>. -+* <>: Is obtained from the `SecurityContextHolder` and contains the `Authentication` of the currently authenticated user. -+* <>: Can be the input to `AuthenticationManager` to provide the credentials a user has provided to authenticate or the current user from the `SecurityContext`. -+* <>: An authority that is granted to the principal on the `Authentication` (roles, scopes, and so on) -+* <>: The API that defines how Spring Security's Filters perform <>. -+* <>: The most common implementation of `AuthenticationManager`. -+* <>: Used by `ProviderManager` to perform a specific type of authentication. -+* <>: Used for requesting credentials from a client (redirecting to a log in page, sending a `WWW-Authenticate` response, and so on) -+* <>: A base `Filter` used for authentication. -+This also gives a good idea of the high-level flow of authentication and how the pieces work together. - - [[servlet-authentication-mechanisms]] - *Authentication Mechanisms* - - // FIXME: brief description - --* <> - how to authenticate with a username/password --* <> - OAuth 2.0 Log In with OpenID Connect and non-standard OAuth 2.0 Login (i.e. GitHub) --* <> - SAML 2.0 Log In --* <> - Central Authentication Server (CAS) Support --* <> - How to remember a user past session expiration --* <> - Authenticate with JAAS --* <> - OpenID Authentication (not to be confused with OpenID Connect) --* <> - Authenticate with an external mechanism such as https://www.siteminder.com/[SiteMinder] or Java EE security but still use Spring Security for authorization and protection against common exploits. --* <> - X509 Authentication -+* <>: How to authenticate with a username and password. -+* <>: OAuth 2.0 Log In with OpenID Connect and non-standard OAuth 2.0 Login (i.e. GitHub). -+* <>: SAML 2.0 Log In. -+* <>: Central Authentication Server (CAS) support. -+* <>: How to remember the past session expiration of a user. -+* <>: Authenticate with JAAS. -+* <>: OpenID Authentication (not to be confused with OpenID Connect). -+* <>: Authenticate with an external mechanism such as https://www.siteminder.com/[SiteMinder] or Java EE security but still use Spring Security for authorization and protection against common exploits. -+* <>: X509 Authentication. - - // FIXME: Add other mechanisms - -diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/jaas.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/jaas.adoc -index 3a1864ca89..98020d9406 100644 ---- a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/jaas.adoc -+++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/jaas.adoc -@@ -1,80 +1,71 @@ - [[servlet-jaas]] - == Java Authentication and Authorization Service (JAAS) Provider - -- --=== 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. -- -+Spring Security provides a package to delegate authentication requests to the Java Authentication and Authorization Service (JAAS). -+This section discusses that package. - - [[jaas-abstractjaasauthenticationprovider]] - === AbstractJaasAuthenticationProvider --The `AbstractJaasAuthenticationProvider` is the basis for the provided JAAS `AuthenticationProvider` implementations. -+The `AbstractJaasAuthenticationProvider` class 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. -- -+The `AbstractJaasAuthenticationProvider` has a number of dependencies that can be injected into it, as discussed in the remainder of this section. - - [[jaas-callbackhandler]] - ==== JAAS CallbackHandler --Most JAAS `LoginModule` s require a callback of some sort. -+Most JAAS `LoginModule` instances require a callback of some sort. - These callbacks are usually used to obtain the username and password from the user. - --In a Spring Security deployment, Spring Security is responsible for this user interaction (via the authentication mechanism). --Thus, by the time the authentication request is delegated through to JAAS, Spring Security's authentication mechanism will already have fully-populated an `Authentication` object containing all the information required by the JAAS `LoginModule`. -- --Therefore, the JAAS package for Spring Security provides two default callback handlers, `JaasNameCallbackHandler` and `JaasPasswordCallbackHandler`. --Each of these callback handlers implement `JaasAuthenticationCallbackHandler`. --In most cases these callback handlers can simply be used without understanding the internal mechanics. -+In a Spring Security deployment, Spring Security is responsible for this user interaction (through the authentication mechanism). -+Thus, by the time the authentication request is delegated through to JAAS, Spring Security's authentication mechanism has already fully populated an `Authentication` object that contains all the information required by the JAAS `LoginModule`. - --For those needing full control over the callback behavior, internally `AbstractJaasAuthenticationProvider` wraps these `JaasAuthenticationCallbackHandler` s with an `InternalCallbackHandler`. --The `InternalCallbackHandler` is the class that actually implements JAAS normal `CallbackHandler` interface. --Any time that the JAAS `LoginModule` is used, it is passed a list of application context configured `InternalCallbackHandler` s. --If the `LoginModule` requests a callback against the `InternalCallbackHandler` s, the callback is in-turn passed to the `JaasAuthenticationCallbackHandler` s being wrapped. -+Therefore, the JAAS package for Spring Security provides two default callback handlers: `JaasNameCallbackHandler` and `JaasPasswordCallbackHandler`. -+Each of these callback handlers implements `JaasAuthenticationCallbackHandler`. -+In most cases, these callback handlers can be used without understanding the internal mechanics. - -+For those needing full control over the callback behavior, `AbstractJaasAuthenticationProvider` internally wraps these `JaasAuthenticationCallbackHandler` instances with an `InternalCallbackHandler`. -+The `InternalCallbackHandler` is the class that actually implements the JAAS normal `CallbackHandler` interface. -+Any time that the JAAS `LoginModule` is used, it is passed a list of application contexts configured `InternalCallbackHandler` instances. -+If the `LoginModule` requests a callback against the `InternalCallbackHandler` instances, the callback is, in turn, passed to the `JaasAuthenticationCallbackHandler` instances being wrapped. - - [[jaas-authoritygranter]] - ==== JAAS AuthorityGranter - JAAS works with principals. --Even "roles" are represented as principals in JAAS. -+Even "`roles`" are represented as principals in JAAS. - Spring Security, on the other hand, works with `Authentication` objects. --Each `Authentication` object contains a single principal, and multiple `GrantedAuthority` s. -+Each `Authentication` object contains a single principal and multiple `GrantedAuthority` instances. - To facilitate mapping between these different concepts, Spring Security's JAAS package includes an `AuthorityGranter` interface. - --An `AuthorityGranter` is responsible for inspecting a JAAS principal and returning a set of `String` s, representing the authorities assigned to the principal. --For each returned authority string, the `AbstractJaasAuthenticationProvider` creates a `JaasGrantedAuthority` (which implements Spring Security's `GrantedAuthority` interface) containing the authority string and the JAAS principal that the `AuthorityGranter` was passed. --The `AbstractJaasAuthenticationProvider` obtains the JAAS principals by firstly successfully authenticating the user's credentials using the JAAS `LoginModule`, and then accessing the `LoginContext` it returns. -+An `AuthorityGranter` is responsible for inspecting a JAAS principal and returning a set of `String` objects that represent the authorities assigned to the principal. -+For each returned authority string, the `AbstractJaasAuthenticationProvider` creates a `JaasGrantedAuthority` (which implements Spring Security's `GrantedAuthority` interface) that contains the authority string and the JAAS principal that the `AuthorityGranter` was passed. -+The `AbstractJaasAuthenticationProvider` obtains the JAAS principals by first successfully authenticating the user's credentials by using the JAAS `LoginModule` and then accessing the `LoginContext` it returns. - A call to `LoginContext.getSubject().getPrincipals()` is made, with each resulting principal passed to each `AuthorityGranter` defined against the `AbstractJaasAuthenticationProvider.setAuthorityGranters(List)` property. - --Spring Security does not include any production `AuthorityGranter` s given that every JAAS principal has an implementation-specific meaning. -+Spring Security does not include any production `AuthorityGranter` instances, given that every JAAS principal has an implementation-specific meaning. - However, there is a `TestAuthorityGranter` in the unit tests that demonstrates a simple `AuthorityGranter` implementation. - -- - [[jaas-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. -- -+The `DefaultJaasAuthenticationProvider` lets a JAAS `Configuration` object be injected into it as a dependency. -+It then creates a `LoginContext` by using the injected JAAS `Configuration`. -+This means that `DefaultJaasAuthenticationProvider` is not bound to any particular implementation of `Configuration`, as `JaasAuthenticationProvider` is. - - [[jaas-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`. --For details, refer to the class level javadoc of `InMemoryConfiguration`. -- -+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` instances. -+`InMemoryConfiguration` also supports a default `Array` of `AppConfigurationEntry` objects that is used if no mapping is found within the provided `Map`. -+For details, see the {security-api-url}org/springframework/security/authentication/jaas/memory/InMemoryConfiguration.html[Javadoc of `InMemoryConfiguration`]. - - [[jaas-djap-config]] - ==== 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. -+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 dependent on the default `Configuration` implementation. - --An example configuration of `DefaultJaasAuthenticationProvider` using `InMemoryConfiguration` is provided below. -+The next example provides a configuration of `DefaultJaasAuthenticationProvider` that uses `InMemoryConfiguration`. - Note that custom implementations of `Configuration` can easily be injected into `DefaultJaasAuthenticationProvider` as well. - -- -+==== - [source,xml] - ---- -- - - -@@ -110,32 +101,32 @@ class="org.springframework.security.authentication.jaas.DefaultJaasAuthenticatio - - - -- - ---- -- -- -+==== - - [[jaas-jaasauthenticationprovider]] - === JaasAuthenticationProvider --The `JaasAuthenticationProvider` assumes the default `Configuration` is an instance of https://download.oracle.com/javase/1.4.2/docs/guide/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` assumes that the default `Configuration` is an instance of https://download.oracle.com/javase/1.4.2/docs/guide/security/jaas/spec/com/sun/security/auth/login/ConfigFile.html[`ConfigFile`]. -+This assumption is made in order to try to update the `Configuration`. - The `JaasAuthenticationProvider` then uses the default `Configuration` to create the `LoginContext`. - --Let's assume we have a JAAS login configuration file, `/WEB-INF/login.conf`, with the following contents: -+Assume that we have a JAAS login configuration file, `/WEB-INF/login.conf`, with the following contents: - -+==== - [source,txt] - ---- - JAASTest { - sample.SampleLoginModule required; - }; - ---- -+==== - --Like all Spring Security beans, the `JaasAuthenticationProvider` is configured via the application context. -+Like all Spring Security beans, the `JaasAuthenticationProvider` is configured through the application context. - The following definitions would correspond to the above JAAS login configuration file: - -+==== - [source,xml] - ---- -- - - -@@ -155,16 +146,19 @@ class="org.springframework.security.authentication.jaas.JaasAuthenticationProvid - - - ---- -+==== - - [[jaas-apiprovision]] - === Running as a Subject --If configured, the `JaasApiIntegrationFilter` will attempt to run as the `Subject` on the `JaasAuthenticationToken`. -+If configured, the `JaasApiIntegrationFilter` tries to run as the `Subject` on the `JaasAuthenticationToken`. - This means that the `Subject` can be accessed using: - -+==== - [source,java] - ---- - Subject subject = Subject.getSubject(AccessController.getContext()); - ---- -+==== - --This integration can easily be configured using the <> attribute. -+You can configure this integration by using the <> attribute. - This feature is useful when integrating with legacy or external API's that rely on the JAAS Subject being populated. -diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/logout.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/logout.adoc -index c824ffe0ad..1b5a3f1893 100644 ---- a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/logout.adoc -+++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/logout.adoc -@@ -1,16 +1,18 @@ - [[jc-logout]] - == Handling Logouts - -+This section covers how to customize the handling of logouts. -+ - [[logout-java-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: -+The default is that accessing the URL `/logout` logs the user out by: - - - Invalidating the HTTP Session - - Cleaning up any RememberMe authentication that was configured - - Clearing the `SecurityContextHolder` --- Redirect to `/login?logout` -+- Redirecting to `/login?logout` - - Similar to configuring login capabilities, however, you also have various options to further customize your logout requirements: - -@@ -53,33 +55,30 @@ override fun configure(http: HttpSecurity) { - - <1> Provides logout support. - This is automatically applied when using `WebSecurityConfigurerAdapter`. --<2> The URL that triggers log out to occur (default is `/logout`). --If CSRF protection is enabled (default), then the request must also be a POST. --For more information, please consult the {security-api-url}org/springframework/security/config/annotation/web/configurers/LogoutConfigurer.html#logoutUrl-java.lang.String-[JavaDoc]. --<3> The URL to redirect to after logout has occurred. -+<2> The URL that triggers log out to occur (the default is `/logout`). -+If CSRF protection is enabled (the default), the request must also be a POST. -+For more information, see {security-api-url}org/springframework/security/config/annotation/web/configurers/LogoutConfigurer.html#logoutUrl-java.lang.String-[`logoutUrl(java.lang.String logoutUrl)`]. -+<3> The URL to which to redirect after logout has occurred. - The default is `/login?logout`. --For more information, please consult the {security-api-url}org/springframework/security/config/annotation/web/configurers/LogoutConfigurer.html#logoutSuccessUrl-java.lang.String-[JavaDoc]. -+For more information, see {security-api-url}org/springframework/security/config/annotation/web/configurers/LogoutConfigurer.html#logoutSuccessUrl-java.lang.String-[`logoutSuccessUrl(java.lang.String logoutSuccessUrl)`]. - <4> Let's you specify a custom `LogoutSuccessHandler`. - If this is specified, `logoutSuccessUrl()` is ignored. --For more information, please consult the {security-api-url}org/springframework/security/config/annotation/web/configurers/LogoutConfigurer.html#logoutSuccessHandler-org.springframework.security.web.authentication.logout.LogoutSuccessHandler-[JavaDoc]. -+For more information, see {security-api-url}org/springframework/security/config/annotation/web/configurers/LogoutConfigurer.html#logoutSuccessHandler-org.springframework.security.web.authentication.logout.LogoutSuccessHandler-[`LogoutSuccessHandler`]. - <5> Specify whether to invalidate the `HttpSession` at the time of logout. - This is *true* by default. - Configures the `SecurityContextLogoutHandler` under the covers. --For more information, please consult the {security-api-url}org/springframework/security/config/annotation/web/configurers/LogoutConfigurer.html#invalidateHttpSession-boolean-[JavaDoc]. -+For more information, see {security-api-url}org/springframework/security/config/annotation/web/configurers/LogoutConfigurer.html#invalidateHttpSession-boolean-[`invalidateHttpSession(boolean invalidateHttpSession)`]. - <6> Adds a `LogoutHandler`. --`SecurityContextLogoutHandler` is added as the last `LogoutHandler` by default. --<7> Allows specifying the names of cookies to be removed on logout success. -+By default, `SecurityContextLogoutHandler` is added as the last `LogoutHandler`. -+<7> Lets specifying the names of cookies be removed on logout success. - This is a shortcut for adding a `CookieClearingLogoutHandler` explicitly. - --[NOTE] --==== --Logouts can of course also be configured using the XML Namespace notation. --Please see the documentation for the <> in the Spring Security XML Namespace section for further details. --==== -+NOTE: Logouts can also be configured by using the XML Namespace notation. -+See the documentation for the <> in the Spring Security XML Namespace section for further details. - --Generally, in order to customize logout functionality, you can add -+Generally, to customize logout functionality, you can add - `{security-api-url}org/springframework/security/web/authentication/logout/LogoutHandler.html[LogoutHandler]` --and/or -+or - `{security-api-url}org/springframework/security/web/authentication/logout/LogoutSuccessHandler.html[LogoutSuccessHandler]` - implementations. - For many common scenarios, these handlers are applied under the -@@ -88,8 +87,8 @@ covers when using the fluent API. - [[ns-logout]] - === 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. -+The default logout URL is `/logout`, but you can set it to something else by setting the `logout-url` attribute. -+You can find more information on other available attributes in the namespace appendix. - - [[jc-logout-handler]] - === LogoutHandler -@@ -97,9 +96,9 @@ More information on other available attributes may be found in the namespace app - Generally, `{security-api-url}org/springframework/security/web/authentication/logout/LogoutHandler.html[LogoutHandler]` - implementations indicate classes that are able to participate in logout handling. - They are expected to be invoked to perform necessary clean-up. --As such they should -+As a result, they should - not throw exceptions. --Various implementations are provided: -+Spring Security provides various implementations: - - - {security-api-url}org/springframework/security/web/authentication/rememberme/PersistentTokenBasedRememberMeServices.html[PersistentTokenBasedRememberMeServices] - - {security-api-url}org/springframework/security/web/authentication/rememberme/TokenBasedRememberMeServices.html[TokenBasedRememberMeServices] -@@ -108,41 +107,41 @@ Various implementations are provided: - - {security-api-url}org/springframework/security/web/authentication/logout/SecurityContextLogoutHandler.html[SecurityContextLogoutHandler] - - {security-api-url}org/springframework/security/web/authentication/logout/HeaderWriterLogoutHandler.html[HeaderWriterLogoutHandler] - --Please see <> for details. -+See <> for details. - - Instead of providing `LogoutHandler` implementations directly, the fluent API also provides shortcuts that provide the respective `LogoutHandler` implementations under the covers. --E.g. `deleteCookies()` allows specifying the names of one or more cookies to be removed on logout success. -+For example, `deleteCookies()` lets you specify the names of one or more cookies to be removed on logout success. - This is a shortcut compared to adding a `CookieClearingLogoutHandler`. - - [[jc-logout-success-handler]] - === LogoutSuccessHandler - --The `LogoutSuccessHandler` is called after a successful logout by the `LogoutFilter`, to handle e.g. -+The `LogoutSuccessHandler` is called after a successful logout by the `LogoutFilter`, to handle (for example) - redirection or forwarding to the appropriate destination. - Note that the interface is almost the same as the `LogoutHandler` but may raise an exception. - --The following implementations are provided: -+Spring Security provides the following implementations: - - - {security-api-url}org/springframework/security/web/authentication/logout/SimpleUrlLogoutSuccessHandler.html[SimpleUrlLogoutSuccessHandler] - - HttpStatusReturningLogoutSuccessHandler - --As mentioned above, you don't need to specify the `SimpleUrlLogoutSuccessHandler` directly. -+As mentioned earlier, you need not specify the `SimpleUrlLogoutSuccessHandler` directly. - Instead, the fluent API provides a shortcut by setting the `logoutSuccessUrl()`. --This will setup the `SimpleUrlLogoutSuccessHandler` under the covers. --The provided URL will be redirected to after a logout has occurred. -+This sets up the `SimpleUrlLogoutSuccessHandler` under the covers. -+The provided URL is redirected to after a logout has occurred. - The default is `/login?logout`. - - The `HttpStatusReturningLogoutSuccessHandler` can be interesting in REST API type scenarios. --Instead of redirecting to a URL upon the successful logout, this `LogoutSuccessHandler` allows you to provide a plain HTTP status code to be returned. --If not configured a status code 200 will be returned by default. -+Instead of redirecting to a URL upon the successful logout, this `LogoutSuccessHandler` lets you provide a plain HTTP status code to be returned. -+If not configured, a status code 200 is returned by default. - - [[jc-logout-references]] - === Further Logout-Related References - - - <> - - <> --- <> -+- <> - - <> - - <> in section CSRF Caveats --- Section <> (CAS protocol) -+- <> (CAS protocol) - - Documentation for the <> in the Spring Security XML Namespace section -diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/openid.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/openid.adoc -index 01362127ff..c615550bcf 100644 ---- a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/openid.adoc -+++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/openid.adoc -@@ -1,11 +1,11 @@ - [[servlet-openid]] - == 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. -+NOTE: The OpenID 1.0 and 2.0 protocols have been deprecated. You should migrate to OpenID Connect, which is supported by `spring-security-oauth2`. - --The namespace supports https://openid.net/[OpenID] login either instead of, or in addition to normal form-based login, with a simple change: -+The namespace supports https://openid.net/[OpenID] login either instead of or in addition to normal form-based login, with a simple change: - -+==== - [source,xml] - ---- - -@@ -13,24 +13,27 @@ The namespace supports https://openid.net/[OpenID] login either instead of, or i - - - ---- -+==== - - You should then register yourself with an OpenID provider (such as myopenid.com), and add the user information to your in-memory ``: - -+==== - [source,xml] - ---- - - ---- -+==== - --You should be able to login using the `myopenid.com` site to authenticate. --It is also possible to select a specific `UserDetailsService` bean for use OpenID by setting the `user-service-ref` attribute on the `openid-login` element. --Note that we have omitted the password attribute from the above user configuration, since this set of user data is only being used to load the authorities for the user. --A random password will be generated internally, preventing you from accidentally using this user data as an authentication source elsewhere in your configuration. -- -+You should be able to login by using the `myopenid.com` site to authenticate. -+You can also select a specific `UserDetailsService` bean for use with OpenID by setting the `user-service-ref` attribute on the `openid-login` element. -+Note that we have omitted the password attribute from the above user configuration, since this set of user data is being used only to load the authorities for the user. -+A random password is generated internally, preventing you from accidentally using this user data as an authentication source elsewhere in your configuration. - - === 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: -+Spring Security includes support for OpenID https://openid.net/specs/openid-attribute-exchange-1_0.html[attribute exchange]. -+As an example, the following configuration tries to retrieve the email and full name from the OpenID provider for use by the application: - -+==== - [source,xml] - ---- - -@@ -40,21 +43,24 @@ As an example, the following configuration would attempt to retrieve the email a - - - ---- -+==== - --The "type" of each OpenID attribute is a URI, determined by a particular schema, in this case https://axschema.org/[https://axschema.org/]. --If an attribute must be retrieved for successful authentication, the `required` attribute can be set. --The exact schema and attributes supported will depend on your OpenID provider. --The attribute values are returned as part of the authentication process and can be accessed afterwards using the following code: -+The "`type`" of each OpenID attribute is a URI, determined by a particular schema -- in this case, https://axschema.org/[https://axschema.org/]. -+If an attribute must be retrieved for successful authentication, you can set the `required` attribute. -+The exact schema and attributes supported depend on your OpenID provider. -+The attribute values are returned as part of the authentication process and can be accessed afterwards by using the following code: - -+==== - [source,java] - ---- - OpenIDAuthenticationToken token = - (OpenIDAuthenticationToken)SecurityContextHolder.getContext().getAuthentication(); - List attributes = token.getAttributes(); - ---- -+==== - - We can obtain the `OpenIDAuthenticationToken` from the <>. - The `OpenIDAttribute` contains the attribute type and the retrieved value (or values in the case of multi-valued attributes). --You can supply multiple `attribute-exchange` elements, using an `identifier-matcher` attribute on each. --This contains a regular expression which will be matched against the OpenID identifier supplied by the user. --See the OpenID sample application in the codebase for an example configuration, providing different attribute lists for the Google, Yahoo and MyOpenID providers. -+You can supply multiple `attribute-exchange` elements by using an `identifier-matcher` attribute on each element. -+This contains a regular expression that is matched against the OpenID identifier supplied by the user. -+See the {gh-samples-url}/boot/oauth2login[OpenID sample application] in the codebase for an example configuration, providing different attribute lists for the Google, Yahoo and MyOpenID providers. -diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/preauth.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/preauth.adoc -index c50de6379f..ae6a079912 100644 ---- a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/preauth.adoc -+++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/preauth.adoc -@@ -1,33 +1,29 @@ - [[servlet-preauth]] - == 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. --When using pre-authentication, Spring Security has to -+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 runs. -+When using pre-authentication, Spring Security has to: - - * Identify the user making the request. -- - * Obtain the authorities for the user. - -- --The details will depend on the external authentication mechanism. -+The details depend on the external authentication mechanism. - A user might be identified by their certificate information in the case of X.509, or by an HTTP request header in the case of Siteminder. --If relying on container authentication, the user will be identified by calling the `getUserPrincipal()` method on the incoming HTTP request. --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`. -- -+If relying on container authentication, the user is identified by calling the `getUserPrincipal()` method on the incoming HTTP request. -+In some cases, the external mechanism may supply role and authority information for the user. However, in other cases, you must obtain the authorities from a separate source, such as a `UserDetailsService`. - - === 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 <>, as it already has a namespace configuration option which is simpler to use and get started with. --If you need to use explicit bean configuration or are planning on writing your own implementation then an understanding of how the provided implementations work will be useful. --You will find classes under the `org.springframework.security.web.authentication.preauth`. --We just provide an outline here so you should consult the Javadoc and source where appropriate. -- -+Because most pre-authentication mechanisms follow the same pattern, Spring Security has a set of classes that provide an internal framework for implementing pre-authenticated authentication providers. -+This removes duplication and lets new implementations be added in a structured fashion, without having to write everything from scratch. -+You need not know about these classes if you want to use something like <>, as it already has a namespace configuration option which is simpler to use and get started with. -+If you need to use explicit bean configuration or are planning on writing your own implementation, you need an understanding of how the provided implementations work. -+You can find the classes under the `org.springframework.security.web.authentication.preauth`. -+We provide only an outline here, so you should consult the Javadoc and source where appropriate. - - ==== 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: -+This class checks the current contents of the security context and, if it is empty, tries to extract user information from the HTTP request and submit it to the `AuthenticationManager`. -+Subclasses override the following methods to obtain this information. - - .Override AbstractPreAuthenticatedProcessingFilter - ==== -@@ -49,24 +45,24 @@ protected abstract fun getPreAuthenticatedCredentials(request: HttpServletReques - ==== - - --After calling these, the filter will create a `PreAuthenticatedAuthenticationToken` containing the returned data and submit it for authentication. --By "authentication" here, we really just mean further processing to perhaps load the user's authorities, but the standard Spring Security authentication architecture is followed. -+After calling these, the filter creates a `PreAuthenticatedAuthenticationToken` that contains the returned data and submits it for authentication. -+By "`authentication`" here, we really just mean further processing to perhaps load the user's authorities, but the standard Spring Security authentication architecture is followed. - --Like other Spring Security authentication filters, the pre-authentication filter has an `authenticationDetailsSource` property which by default will create a `WebAuthenticationDetails` object to store additional information such as the session-identifier and originating IP address in the `details` property of the `Authentication` object. -+As other Spring Security authentication filters, the pre-authentication filter has an `authenticationDetailsSource` property, which, by default, creates a `WebAuthenticationDetails` object to store additional information, such as the session identifier and the originating IP address in the `details` property of the `Authentication` object. - In cases where user role information can be obtained from the pre-authentication mechanism, the data is also stored in this property, with the details implementing the `GrantedAuthoritiesContainer` interface. - This enables the authentication provider to read the authorities which were externally allocated to the user. --We'll look at a concrete example next. -+We look at a concrete example next. - - - [[j2ee-preauth-details]] - ===== 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". -+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 `` information in a `web.xml` file. - The pre-authentication sample application uses the latter approach. - --There is an additional stage where the roles (or attributes) are mapped to Spring Security `GrantedAuthority` objects using a configured `Attributes2GrantedAuthoritiesMapper`. --The default will just add the usual `ROLE_` prefix to the names, but it gives you full control over the behaviour. -+There is an additional stage where the roles (or attributes) are mapped to Spring Security `GrantedAuthority` objects by using a configured `Attributes2GrantedAuthoritiesMapper`. -+The default just adds the usual `ROLE_` prefix to the names, but it gives you full control over the behavior. - - - ==== PreAuthenticatedAuthenticationProvider -@@ -74,45 +70,43 @@ The pre-authenticated provider has little more to do than load the `UserDetails` - 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: - -+==== - [source,java] - ---- - public interface AuthenticationUserDetailsService { - UserDetails loadUserDetails(Authentication token) throws UsernameNotFoundException; - } - ---- -+==== - --This interface may have also other uses but with pre-authentication it allows access to the authorities which were packaged in the `Authentication` object, as we saw in the previous section. -+This interface may also have other uses, but, with pre-authentication, it allows access to the authorities that were packaged in the `Authentication` object, as we saw in the previous section. - The `PreAuthenticatedGrantedAuthoritiesUserDetailsService` class does this. --Alternatively, it may delegate to a standard `UserDetailsService` via the `UserDetailsByNameServiceWrapper` implementation. -+Alternatively, it may delegate to a standard `UserDetailsService` through the `UserDetailsByNameServiceWrapper` implementation. - - ==== Http403ForbiddenEntryPoint --The <> 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. -+The <> is responsible for kick-starting the authentication process for an unauthenticated user (when they try to access a protected resource). However, in the pre-authenticated case, this does not apply. -+You would only configure the `ExceptionTranslationFilter` with an instance of this class if you do not use pre-authentication in combination with other authentication mechanisms. -+It is 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 - X.509 authentication is covered in its <>. --Here we'll look at some classes which provide support for other pre-authenticated scenarios. -- -+Here, we look at some classes which provide support for other pre-authenticated scenarios. - - ==== 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. --It defaults to using the name `SM_USER` as the header name. -+This mechanism is supported by the `RequestHeaderAuthenticationFilter` class, which only extracts the username from the header. -+It defaults to using a name of `SM_USER` as the header name. - See the Javadoc for more details. - --[TIP] --==== --Note that when using a system like this, the framework performs no authentication checks at all and it is __extremely__ important that the external system is configured properly and protects all access to the application. --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. --==== -+TIP: When using a system like this, the framework performs no authentication checks at all, and it is _extremely_ important that the external system is configured properly and protects all access to the application. -+If an attacker is able to forge the headers in their original request without this being detected, they could potentially choose any username they wished. - - ===== Siteminder Example Configuration --A typical configuration using this filter would look like this: -+The following example shows a typical configuration that uses this filter: - -+==== - [source,xml] - ---- - -@@ -138,14 +132,14 @@ A typical configuration using this filter would look like this: - - - ---- -+==== - --We've assumed here that the <> is being used for configuration. --It's also assumed that you have added a `UserDetailsService` (called "userDetailsService") to your configuration to load the user's roles. -- -+We have assumed here that the <> is being used for configuration. -+It is also assumed that you have added a `UserDetailsService` (called `userDetailsService`) to your configuration to load the user's roles. - - ==== 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 <>. -+The `J2eePreAuthenticatedProcessingFilter` class extracts 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 earlier in <>. - --There is a sample application in the codebase which uses this approach, so get hold of the code from github and have a look at the application context file if you are interested. -+There is a sample application that uses this approach in the codebase, so get hold of the code from Github and have a look at the application context file if you are interested. - The code is in the `samples/xml/preauth` directory. -diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/rememberme.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/rememberme.adoc -index 25f6fd791d..541d86535f 100644 ---- a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/rememberme.adoc -+++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/rememberme.adoc -@@ -1,23 +1,22 @@ - [[servlet-rememberme]] - == Remember-Me Authentication - -- - [[remember-me-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. -+Spring Security provides the necessary hooks for these operations to take place and has two concrete remember-me implementations. - One uses hashing to preserve the security of cookie-based tokens and the other uses a database or other persistent storage mechanism to store the generated tokens. - - Note that both implementations require a `UserDetailsService`. --If you are using an authentication provider which doesn't use a `UserDetailsService` (for example, the LDAP provider) then it won't work unless you also have a `UserDetailsService` bean in your application context. -+If you use an authentication provider that does not use a `UserDetailsService` (for example, the LDAP provider), it does not work unless you also have a `UserDetailsService` bean in your application context. - - - [[remember-me-hash-token]] - === 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: -+In essence, a cookie is sent to the browser upon successful interactive authentication, with the cookie being composed as follows: - -+==== - [source,txt] - ---- - base64(username + ":" + expirationTime + ":" + -@@ -28,16 +27,18 @@ password: That matches the one in the retrieved UserDetails - expirationTime: The date and time when the remember-me token expires, expressed in milliseconds - key: A private key to prevent modification of the remember-me token - ---- -+==== - --As such the remember-me token is valid only for the period specified, and provided that the username, password and key does not change. --Notably, this has a potential security issue in that a captured remember-me token will be usable from any user agent until such time as the token expires. --This is the same issue as with digest authentication. --If a principal is aware a token has been captured, they can easily change their password and immediately invalidate all remember-me tokens on issue. --If more significant security is needed you should use the approach described in the next section. --Alternatively remember-me services should simply not be used at all. -+The remember-me token is valid only for the period specified and only if the username, password, and key do not change. -+Notably, this has a potential security issue, in that a captured remember-me token is usable from any user agent until such time as the token expires. -+This is the same issue as with <>. -+If a principal is aware that a token has been captured, they can easily change their password and immediately invalidate all remember-me tokens on issue. -+If more significant security is needed, you should use the approach described in the next section. -+Alternatively, remember-me services should not be used at all. - --If you are familiar with the topics discussed in the chapter on <>, you can enable remember-me authentication just by adding the `` element: -+If you are familiar with the topics discussed in the chapter on <>, you can enable remember-me authentication by adding the `` element: - -+==== - [source,xml] - ---- - -@@ -45,16 +46,18 @@ If you are familiar with the topics discussed in the chapter on < - - ---- -+==== - --The `UserDetailsService` will normally be selected automatically. -+The `UserDetailsService` is normally 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 --This approach is based on the article 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: -+This approach is based on the article titled http://jaspan.com/improved_persistent_login_cookie_best_practice[http://jaspan.com/improved_persistent_login_cookie_best_practice], with some minor modifications. (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, supply a datasource reference: - -+==== - [source,xml] - ---- - -@@ -62,9 +65,11 @@ To use the this approach with namespace configuration, you would supply a dataso - - - ---- -+==== - --The database should contain a `persistent_logins` table, created using the following SQL (or equivalent): -+The database should contain a `persistent_logins` table, created by using the following SQL (or equivalent): - -+==== - [source,ddl] - ---- - create table persistent_logins (username varchar(64) not null, -@@ -72,14 +77,16 @@ create table persistent_logins (username varchar(64) not null, - token varchar(64) not null, - last_used timestamp not null) - ---- -+==== - - [[remember-me-impls]] - === Remember-Me Interfaces and Implementations --Remember-me is used with `UsernamePasswordAuthenticationFilter`, and is implemented via hooks in the `AbstractAuthenticationProcessingFilter` superclass. -+Remember-me is used with `UsernamePasswordAuthenticationFilter` and is implemented through hooks in the `AbstractAuthenticationProcessingFilter` superclass. - It is also used within `BasicAuthenticationFilter`. --The hooks will invoke a concrete `RememberMeServices` at the appropriate times. --The interface looks like this: -+The hooks invoke a concrete `RememberMeServices` at the appropriate times. -+The following listing shows the interface: - -+==== - [source,java] - ---- - Authentication autoLogin(HttpServletRequest request, HttpServletResponse response); -@@ -89,24 +96,27 @@ void loginFail(HttpServletRequest request, HttpServletResponse response); - void loginSuccess(HttpServletRequest request, HttpServletResponse response, - Authentication successfulAuthentication); - ---- -+==== - --Please refer to the Javadoc for a fuller discussion on what the methods do, although note at this stage that `AbstractAuthenticationProcessingFilter` only calls the `loginFail()` and `loginSuccess()` methods. -+See the Javadoc for {security-api-url}org/springframework/security/web/authentication/RememberMeServices.html[`RememberMeServices`] for a fuller discussion on what the methods do, although note that, at this stage, `AbstractAuthenticationProcessingFilter` calls only the `loginFail()` and `loginSuccess()` methods. - The `autoLogin()` method is called by `RememberMeAuthenticationFilter` whenever the `SecurityContextHolder` does not contain an `Authentication`. --This interface therefore provides the underlying remember-me implementation with sufficient notification of authentication-related events, and delegates to the implementation whenever a candidate web request might contain a cookie and wish to be remembered. -+This interface, therefore, provides the underlying remember-me implementation with sufficient notification of authentication-related events and delegates to the implementation whenever a candidate web request might contain a cookie and wish to be remembered. - 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. -+ -+We have seen earlier that Spring Security provides two implementations. -+We look at each of these in turn. - - ==== TokenBasedRememberMeServices - This implementation supports the simpler approach described in <>. - `TokenBasedRememberMeServices` generates a `RememberMeAuthenticationToken`, which is processed by `RememberMeAuthenticationProvider`. - A `key` is shared between this authentication provider and the `TokenBasedRememberMeServices`. --In addition, `TokenBasedRememberMeServices` requires A UserDetailsService from which it can retrieve the username and password for signature comparison purposes, and generate the `RememberMeAuthenticationToken` to contain the correct `GrantedAuthority` s. -+In addition, `TokenBasedRememberMeServices` requires a `UserDetailsService`, from which it can retrieve the username and password for signature comparison purposes and generate the `RememberMeAuthenticationToken` to contain the correct `GrantedAuthority` instances. - Some sort of logout command should be provided by the application that invalidates the cookie if the user requests this. --`TokenBasedRememberMeServices` also implements Spring Security's `LogoutHandler` interface so can be used with `LogoutFilter` to have the cookie cleared automatically. -+`TokenBasedRememberMeServices` also implements Spring Security's `LogoutHandler` interface so that it can be used with `LogoutFilter` to have the cookie cleared automatically. - --The beans required in an application context to enable remember-me services are as follows: -+The following beans are required in an application context to enable remember-me services: - -+==== - [source,xml] - ---- - - - ---- -+==== - --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`). -+Remember 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 --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. -+You can use this class 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. - --* `InMemoryTokenRepositoryImpl` which is intended for testing only. --* `JdbcTokenRepositoryImpl` which stores the tokens in a database. -+* `InMemoryTokenRepositoryImpl`, which is intended for testing only. -+* `JdbcTokenRepositoryImpl`, which stores the tokens in a database. - --The database schema is described above in <>. -+See <> for the database schema. -diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/runas.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/runas.adoc -index 8eb5de89ec..4cc1495782 100644 ---- a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/runas.adoc -+++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/runas.adoc -@@ -2,19 +2,19 @@ - == Run-As Authentication Replacement - - [[runas-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`. -+The `RunAsManager` indicates the replacement `Authentication` object, if any, that should be used during the `SecurityInterceptorCallback`. - --By temporarily replacing the `Authentication` object during the secure object callback phase, the secured invocation will be able to call other objects which require different authentication and authorization credentials. --It will also be able to perform any internal security checks for specific `GrantedAuthority` objects. -+By temporarily replacing the `Authentication` object during the secure object callback phase, the secured invocation can call other objects that require different authentication and authorization credentials. -+It can also perform any internal security checks for specific `GrantedAuthority` objects. - 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 --A `RunAsManager` interface is provided by Spring Security: -+Spring Security provices a `RunAsManager` interface: - -+==== - [source,java] - ---- - Authentication buildRunAs(Authentication authentication, Object object, -@@ -24,31 +24,30 @@ boolean supports(ConfigAttribute attribute); - - boolean supports(Class clazz); - ---- -- -- -+==== - - The first method returns the `Authentication` object that should replace the existing `Authentication` object for the duration of the method invocation. - If the method returns `null`, it indicates no replacement should be made. - The second method is used by the `AbstractSecurityInterceptor` as part of its startup validation of configuration attributes. --The `supports(Class)` method is called by a security interceptor implementation to ensure the configured `RunAsManager` supports the type of secure object that the security interceptor will present. -+The `supports(Class)` method is called by a security interceptor implementation to ensure that the configured `RunAsManager` supports the type of secure object that the security interceptor presents. - --One concrete implementation of a `RunAsManager` is provided with Spring Security. -+Spring Security provides one concrete implementation of `RunAsManager`. - The `RunAsManagerImpl` class returns a replacement `RunAsUserToken` if any `ConfigAttribute` starts with `RUN_AS_`. --If any such `ConfigAttribute` is found, the replacement `RunAsUserToken` will contain the same principal, credentials and granted authorities as the original `Authentication` object, along with a new `SimpleGrantedAuthority` for each `RUN_AS_` `ConfigAttribute`. --Each new `SimpleGrantedAuthority` will be prefixed with `ROLE_`, followed by the `RUN_AS` `ConfigAttribute`. --For example, a `RUN_AS_SERVER` will result in the replacement `RunAsUserToken` containing a `ROLE_RUN_AS_SERVER` granted authority. -+If any such `ConfigAttribute` is found, the replacement `RunAsUserToken` contains the same principal, credentials, and granted authorities as the original `Authentication` object, along with a new `SimpleGrantedAuthority` for each `RUN_AS_` `ConfigAttribute`. -+Each new `SimpleGrantedAuthority` is prefixed with `ROLE_`, followed by the `RUN_AS` `ConfigAttribute`. -+For example, a `RUN_AS_SERVER` results in the replacement `RunAsUserToken` containing a `ROLE_RUN_AS_SERVER` granted authority. - --The replacement `RunAsUserToken` is just like any other `Authentication` object. --It needs to be authenticated by the `AuthenticationManager`, probably via delegation to a suitable `AuthenticationProvider`. -+The replacement `RunAsUserToken` is like any other `Authentication` object. -+It needs to be authenticated by the `AuthenticationManager`, probably through delegation to a suitable `AuthenticationProvider`. - The `RunAsImplAuthenticationProvider` performs such authentication. --It simply accepts as valid any `RunAsUserToken` presented. -+It accepts as valid any `RunAsUserToken` presented. - - To ensure malicious code does not create a `RunAsUserToken` and present it for guaranteed acceptance by the `RunAsImplAuthenticationProvider`, the hash of a key is stored in all generated tokens. - The `RunAsManagerImpl` and `RunAsImplAuthenticationProvider` is created in the bean context with the same key: - -+==== - [source,xml] - ---- -- - - -@@ -59,8 +58,7 @@ The `RunAsManagerImpl` and `RunAsImplAuthenticationProvider` is created in the b - - - ---- -+==== - -- -- --By using the same key, each `RunAsUserToken` can be validated it was created by an approved `RunAsManagerImpl`. --The `RunAsUserToken` is immutable after creation for security reasons -+By using the same key, each `RunAsUserToken` can be validated because it was created by an approved `RunAsManagerImpl`. -+The `RunAsUserToken` is immutable after creation, for security reasons. -diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/session-management.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/session-management.adoc -index 2250445a73..0916bd138f 100644 ---- a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/session-management.adoc -+++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/session-management.adoc -@@ -1,12 +1,13 @@ - [[session-mgmt]] - == 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. -+HTTP session-related functionality is handled by a combination of the {security-api-url}org/springframework/security/authentication/AuthenticationProvider.html[`SessionManagementFilter`] and the {security-api-url}org/springframework/security/web/authentication/session/SessionAuthenticationStrategy.html[`SessionAuthenticationStrategy`] interface, to which the filter delegates. -+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 - 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: -+To do so, configure the `session-management` element: - -+==== - [source,xml] - ---- - -@@ -14,25 +15,29 @@ This is achieved through the `session-management` element: - - - ---- -+==== - --Note that if you use this mechanism to detect session timeouts, it may falsely report an error if the user logs out and then logs back in without closing the browser. --This is because the session cookie is not cleared when you invalidate the session and will be resubmitted even if the user has logged out. --You may be able to explicitly delete the JSESSIONID cookie on logging out, for example by using the following syntax in the logout handler: -+Note that, if you use this mechanism to detect session timeouts, it may falsely report an error if the user logs out and then logs back in without closing the browser. -+This is because the session cookie is not cleared when you invalidate the session and is resubmitted even if the user has logged out. -+You may be able to explicitly delete the `JSESSIONID` cookie on logging out -- for example, by using the following syntax in the logout handler: - -+==== - [source,xml] - ---- - - - - ---- -+==== - --Unfortunately this can't be guaranteed to work with every servlet container, so you will need to test it in your environment -+Unfortunately, this cannot be guaranteed to work with every servlet container, so you need to test it in your environment. - - [NOTE] --==== --If you are running your application behind a proxy, you may also be able to remove the session cookie by configuring the proxy server. --For example, using Apache HTTPD's mod_headers, the following directive would delete the `JSESSIONID` cookie by expiring it in the response to a logout request (assuming the application is deployed under the path `/tutorial`): -+===== -+If you run your application behind a proxy, you may also be able to remove the session cookie by configuring the proxy server. -+For example, by using Apache HTTPD's `mod_headers`, the following directive deletes the `JSESSIONID` cookie by expiring it in the response to a logout request (assuming the application is deployed under the `/tutorial` path): - -+==== - [source,xml] - ---- - -@@ -40,13 +45,15 @@ Header always set Set-Cookie "JSESSIONID=;Path=/tutorial;Expires=Thu, 01 Jan 197 - - ---- - ==== -+===== - - - [[ns-concurrent-sessions]] - === 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 `web.xml` file to keep Spring Security updated about session lifecycle events: -+If you wish to place constraints on a single user's ability to log in to your application, Spring Security supports this with the following simple additions. -+First, you need to add the following listener to your `web.xml` file to keep Spring Security updated about session lifecycle events: - -+==== - [source,xml] - ---- - -@@ -55,9 +62,11 @@ First you need to add the following listener to your `web.xml` file to keep Spri - - - ---- -+==== - - Then add the following lines to your application context: - -+==== - [source,xml] - ---- - -@@ -67,10 +76,12 @@ Then add the following lines to your application context: - - - ---- -+==== - --This will prevent a user from logging in multiple times - a second login will cause the first to be invalidated. --Often you would prefer to prevent a second login, in which case you can use -+These changes prevent a user from logging in multiple times. A second login causes the first to be invalidated. -+Often, you would prefer to prevent a second login. In that case, you can use: - -+==== - [source,xml] - ---- - -@@ -80,61 +91,61 @@ Often you would prefer to prevent a second login, in which case you can use - - - ---- -+==== - --The second login will then be rejected. --By "rejected", we mean that the user will be sent to the `authentication-failure-url` if form-based login is being used. --If the second authentication takes place through another non-interactive mechanism, such as "remember-me", an "unauthorized" (401) error will be sent to the client. --If instead you want to use an error page, you can add the attribute `session-authentication-error-url` to the `session-management` element. -+The second login is then rejected. -+By "`rejected`", we mean that the user is sent to the `authentication-failure-url` if form-based login is being used. -+If the second authentication takes place through another non-interactive mechanism, such as "`remember-me`", an "`unauthorized`" (401) error is sent to the client. -+If, instead, you want to use an error page, you can add the `session-authentication-error-url` attribute to the `session-management` element. - --If you are using a customized authentication filter for form-based login, then you have to configure concurrent session control support explicitly. --More details can be found in the <>. -+If you use a customized authentication filter for form-based login, you have to configure concurrent session control support explicitly. -+You can find more details in the <>. - - [[ns-session-fixation]] - === 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 ``, which has four options -+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 and 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 automatically protects against this by creating a new session or otherwise changing the session ID when a user logs in. -+If you do not require this protection or it conflicts with some other requirement, you can control the behavior setting the `session-fixation-protection` attribute on ``, which has four options - --* `none` - Don't do anything. --The original session will be retained. -+* `none`: Do nothing. -+The original session is retained. - --* `newSession` - Create a new "clean" session, without copying the existing session data (Spring Security-related attributes will still be copied). -+* `newSession`: Create a new, "`clean`" session, without copying the existing session data (Spring Security-related attributes are still copied). - --* `migrateSession` - Create a new session and copy all existing session attributes to the new session. -+* `migrateSession`: Create a new session and copy all existing session attributes to the new session. - This is the default in Servlet 3.0 or older containers. - --* `changeSessionId` - Do not create a new session. -+* `changeSessionId`: Do not create a new session. - Instead, use the session fixation protection provided by the Servlet container (`HttpServletRequest#changeSessionId()`). --This option is only available in Servlet 3.1 (Java EE 7) and newer containers. --Specifying it in older containers will result in an exception. --This is the default in Servlet 3.1 and newer containers. -- -+This option is available only in Servlet 3.1 (Java EE 7) and newer containers, where it is the default. -+Specifying it in older containers results in an exception. - - When session fixation protection occurs, it results in a `SessionFixationProtectionEvent` being published in the application context. --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. -+If you use `changeSessionId`, this protection will _also_ result in any `javax.servlet.http.HttpSessionIdListener` instances being notified, so use caution if your code listens for both events. - See the <> chapter for additional information. - - === 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. -+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 -+ -+NOTE: Authentication by mechanisms that perform a redirect after authenticating (such as form-login) are not detected by `SessionManagementFilter`, as the filter is not invoked during the authenticating request. - Session-management functionality has to be handled separately in these cases. --]. -+ - If the repository contains a security context, the filter does nothing. --If it doesn't, and the thread-local `SecurityContext` contains a (non-anonymous) `Authentication` object, the filter assumes they have been authenticated by a previous filter in the stack. --It will then invoke the configured `SessionAuthenticationStrategy`. -+If it does not and the thread-local `SecurityContext` contains a (non-anonymous) `Authentication` object, the filter assumes they have been authenticated by a previous filter in the stack. -+It then invokes the configured `SessionAuthenticationStrategy`. - --If the user is not currently authenticated, the filter will check whether an invalid session ID has been requested (because of a timeout, for example) and will invoke the configured `InvalidSessionStrategy`, if one is set. --The most common behaviour is just to redirect to a fixed URL and this is encapsulated in the standard implementation `SimpleRedirectInvalidSessionStrategy`. --The latter is also used when configuring an invalid session URL through the namespace,<>. -+If the user is not currently authenticated, the filter checks whether an invalid session ID has been requested (because of a timeout, for example) and invokes the configured `InvalidSessionStrategy`, if one is set. -+The most common behavior is to redirect to a fixed URL, and this is encapsulated in the standard implementation (`SimpleRedirectInvalidSessionStrategy`). -+The latter is also used when configuring an invalid session URL through the namespace, <>. - - - === 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: -+`SessionAuthenticationStrategy` is used by both `SessionManagementFilter` and `AbstractAuthenticationProcessingFilter`, so, if you are using a customized form-login class, for example, you need to inject it into both of these. -+In this case, a typical configuration that combines the namespace and custom beans might look like this: - -+==== - [source,xml] - ---- -- - - - -@@ -148,56 +159,53 @@ In this case, a typical configuration, combining the namespace and custom beans - - -- - ---- -+==== - --Note that the use of the default, `SessionFixationProtectionStrategy` may cause issues if you are storing beans in the session which implement `HttpSessionBindingListener`, including Spring session-scoped beans. --See the Javadoc for this class for more information. -+Note that the use of the default, `SessionFixationProtectionStrategy`, may cause issues if you are storing beans in the session that implement `HttpSessionBindingListener`, including Spring session-scoped beans. -+See the Javadoc for this Java class for more information. - - [[concurrent-sessions]] - === 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. -+Spring Security can 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, while 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. - You can either expire their previous login or you can report an error when they try to log in again, preventing the second login. --Note that if you are using the second approach, a user who has not explicitly logged out (but who has just closed their browser, for example) will not be able to log in again until their original session expires. -+Note that, if you use the second approach, a user who has not explicitly logged out (but who has just closed their browser, for example) cannot log in again until their original session expires. - -+//FIXME: Add a link to the namespace chapter. - Concurrency control is supported by the namespace, so please check the earlier namespace chapter for the simplest configuration. --Sometimes you need to customize things though. -+Sometimes, though, you need to customize things. - - The implementation uses a specialized version of `SessionAuthenticationStrategy`, called `ConcurrentSessionControlAuthenticationStrategy`. --[NOTE] --==== - --Previously the concurrent authentication check was made by the `ProviderManager`, which could be injected with a `ConcurrentSessionController`. -+NOTE: Previously, the concurrent authentication check was made by the `ProviderManager`, which could be injected with a `ConcurrentSessionController`. - The latter would check if the user was attempting to exceed the number of permitted sessions. - However, this approach required that an HTTP session be created in advance, which is undesirable. --In Spring Security 3, the user is first authenticated by the `AuthenticationManager` and once they are successfully authenticated, a session is created and the check is made whether they are allowed to have another session open. -- --==== -+In Spring Security 3 and later, the user is first authenticated by the `AuthenticationManager` and once they are successfully authenticated, a session is created and the check is made whether they are allowed to have another session open. - -+To use concurrent session support, you need to add the following to `web.xml`: - --To use concurrent session support, you'll need to add the following to `web.xml`: -- -+==== - [source,xml] - ---- -- - - - org.springframework.security.web.session.HttpSessionEventPublisher - - - ---- -+==== - -+In addition, you need to add the `ConcurrentSessionFilter` to your `FilterChainProxy`. -+The `ConcurrentSessionFilter` requires two constructor arguments: -+* `sessionRegistry`, which generally points to an instance of `SessionRegistryImpl` -+* `sessionInformationExpiredStrategy`, which defines the strategy to apply when a session has expired -+The following sample configuration uses the namespace to create the `FilterChainProxy` and other default beans: - -- --In addition, you will need to add the `ConcurrentSessionFilter` to your `FilterChainProxy`. --The `ConcurrentSessionFilter` requires two constructor arguments, `sessionRegistry`, which generally points to an instance of `SessionRegistryImpl`, and `sessionInformationExpiredStrategy`, which defines the strategy to apply when a session has expired. --A configuration using the namespace to create the `FilterChainProxy` and other default beans might look like this: -- -+==== - [source,xml] - ---- -- - - - -@@ -241,25 +249,22 @@ class="org.springframework.security.web.session.ConcurrentSessionFilter"> - - -- - ---- -- -- -+==== - - Adding the listener to `web.xml` causes an `ApplicationEvent` to be published to the Spring `ApplicationContext` every time a `HttpSession` commences or ends. --This is critical, as it allows the `SessionRegistryImpl` to be notified when a session ends. --Without it, a user will never be able to log back in again once they have exceeded their session allowance, even if they log out of another session or it times out. -- -+This is critical, as it lets the `SessionRegistryImpl` be notified when a session ends. -+Without it, a user can never log back in again once they have exceeded their session allowance, even if they log out of another session or it times out. - - [[list-authenticated-principals]] - ==== 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. -+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` that you can use directly within your application. So, even if you do not 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 use the namespace, you can set an alias for the internally-created `SessionRegistry` by using the `session-registry-alias` attribute, providing a reference that you can inject into your own beans. - - The `getAllPrincipals()` method supplies you with a list of the currently authenticated users. - You can list a user's sessions by calling the `getAllSessions(Object principal, boolean includeExpiredSessions)` method, which returns a list of `SessionInformation` objects. - You can also expire a user's session by calling `expireNow()` on a `SessionInformation` instance. --When the user returns to the application, they will be prevented from proceeding. -+When the user returns to the application, they are prevented from proceeding. - You may find these methods useful in an administration application, for example. --Have a look at the Javadoc for more information. -+See the Javadoc for more information about the {security-api-url}org/springframework/security/core/session/SessionRegistry.html[`SessionRegistry`] interface. -diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/basic.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/basic.adoc -index aa2ff02f29..02a746d3b4 100644 ---- a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/basic.adoc -+++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/basic.adoc -@@ -1,60 +1,61 @@ - [[servlet-authentication-basic]] - = Basic Authentication - --This section provides details on how Spring Security provides support for https://tools.ietf.org/html/rfc7617[Basic HTTP Authentication] for servlet based applications. -+This section provides details on how Spring Security provides support for https://tools.ietf.org/html/rfc7617[Basic HTTP Authentication] for servlet-based applications. - // FIXME: describe authenticationentrypoint, authenticationfailurehandler, authenticationsuccesshandler - --Let's take a look at how HTTP Basic Authentication works within Spring Security. --First, we see the https://tools.ietf.org/html/rfc7235#section-4.1[WWW-Authenticate] header is sent back to an unauthenticated client. -+This section describes how HTTP Basic Authentication works within Spring Security. -+First, we see the https://tools.ietf.org/html/rfc7235#section-4.1[WWW-Authenticate] header is sent back to an unauthenticated client: - - .Sending WWW-Authenticate Header - image::{figures}/basicauthenticationentrypoint.png[] - --The figure builds off our <> diagram. -+The preceding figure builds off our <> diagram. - - 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 <> indicates that the unauthenticated request is __Denied__ by throwing an `AccessDeniedException`. - - image:{icondir}/number_3.png[] Since the user is not authenticated, <> initiates __Start Authentication__. --The configured <> is an instance of {security-api-url}org/springframework/security/web/authentication/www/BasicAuthenticationEntryPoint.html[`BasicAuthenticationEntryPoint`] which sends a WWW-Authenticate header. -+The configured <> is an instance of {security-api-url}org/springframework/security/web/authentication/www/BasicAuthenticationEntryPoint.html[`BasicAuthenticationEntryPoint`], which sends a WWW-Authenticate header. - The `RequestCache` is typically a `NullRequestCache` that does not save the request since the client is capable of replaying the requests it originally requested. - --When a client receives the WWW-Authenticate header it knows it should retry with a username and password. --Below is the flow for the username and password being processed. -+When a client receives the `WWW-Authenticate` header, it knows it should retry with a username and password. -+The following image shows the flow for the username and password being processed: - - [[servlet-authentication-basicauthenticationfilter]] - .Authenticating Username and Password - image::{figures}/basicauthenticationfilter.png[] - --The figure builds off our <> diagram. -+The preceding figure builds off our <> diagram. - -- --image:{icondir}/number_1.png[] When the user submits their username and password, the `BasicAuthenticationFilter` creates a `UsernamePasswordAuthenticationToken` which is a type of <> by extracting the username and password from the `HttpServletRequest`. -+image:{icondir}/number_1.png[] When the user submits their username and password, the `BasicAuthenticationFilter` creates a `UsernamePasswordAuthenticationToken`, which is a type of <> by extracting the username and password from the `HttpServletRequest`. - - image:{icondir}/number_2.png[] Next, the `UsernamePasswordAuthenticationToken` is passed into the `AuthenticationManager` to be authenticated. - The details of what `AuthenticationManager` look like depend on how the <>. - --image:{icondir}/number_3.png[] If authentication fails, then __Failure__ -+image:{icondir}/number_3.png[] If authentication fails, then __Failure__. - --* The <> is cleared out. --* `RememberMeServices.loginFail` is invoked. -+. The <> is cleared out. -+. `RememberMeServices.loginFail` is invoked. - If remember me is not configured, this is a no-op. --// FIXME: link to rememberme --* `AuthenticationEntryPoint` is invoked to trigger the WWW-Authenticate to be sent again. -+See the {security-api-url}org/springframework/security/web/authentication/RememberMeServices.html[`RememberMeServices`] interface in the Javadoc. -+. `AuthenticationEntryPoint` is invoked to trigger the WWW-Authenticate to be sent again. -+See the {security-api-url}org/springframework/security/web/AuthenticationEntryPoint.html[`AuthenticationEntryPoint`] interface in the Javadoc. - - image:{icondir}/number_4.png[] If authentication is successful, then __Success__. - --* The <> is set on the <>. --* `RememberMeServices.loginSuccess` is invoked. -+. The <> is set on the <>. -+. `RememberMeServices.loginSuccess` is invoked. - If remember me is not configured, this is a no-op. --// FIXME: link to rememberme --* The `BasicAuthenticationFilter` invokes `FilterChain.doFilter(request,response)` to continue with the rest of the application logic. -+See the {security-api-url}org/springframework/security/web/authentication/RememberMeServices.html[`RememberMeServices`] interface in the Javadoc. -+. The `BasicAuthenticationFilter` invokes `FilterChain.doFilter(request,response)` to continue with the rest of the application logic. -+See the {security-api-url}org/springframework/security/web/authentication/www/BasicAuthenticationFilter.html[`BasicAuthenticationFilter`] Class in the Javadoc - --Spring Security's HTTP Basic Authentication support in is enabled by default. -+By default, Spring Security's HTTP Basic Authentication support is enabled. - However, as soon as any servlet based configuration is provided, HTTP Basic must be explicitly provided. - --A minimal, explicit configuration can be found below: -+The following example shows a minimal, explicit configuration: - - .Explicit HTTP Basic Configuration - ==== -diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/dao-authentication-provider.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/dao-authentication-provider.adoc -index 3818a019ac..3daf2cb6ac 100644 ---- a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/dao-authentication-provider.adoc -+++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/dao-authentication-provider.adoc -@@ -1,21 +1,21 @@ - [[servlet-authentication-daoauthenticationprovider]] - = DaoAuthenticationProvider - --{security-api-url}org/springframework/security/authentication/dao/DaoAuthenticationProvider.html[`DaoAuthenticationProvider`] is an <> implementation that leverages a <> and <> to authenticate a username and password. -+{security-api-url}org/springframework/security/authentication/dao/DaoAuthenticationProvider.html[`DaoAuthenticationProvider`] is an <> implementation that uses a <> and <> to authenticate a username and password. - --Let's take a look at how `DaoAuthenticationProvider` works within Spring Security. --The figure explains details of how the <> in figures from <> works. -+This section examines how `DaoAuthenticationProvider` works within Spring Security. -+The following figure explains the workings of the <> in figures from the <> section. - - .`DaoAuthenticationProvider` Usage - image::{figures}/daoauthenticationprovider.png[] - --image:{icondir}/number_1.png[] The authentication `Filter` from <> passes a `UsernamePasswordAuthenticationToken` to the `AuthenticationManager` which is implemented by <>. -+image:{icondir}/number_1.png[] The authentication `Filter` from the <> section passes a `UsernamePasswordAuthenticationToken` to the `AuthenticationManager`, which is implemented by <>. - - image:{icondir}/number_2.png[] The `ProviderManager` is configured to use an <> of type `DaoAuthenticationProvider`. - - image:{icondir}/number_3.png[] `DaoAuthenticationProvider` looks up the `UserDetails` from the `UserDetailsService`. - --image:{icondir}/number_4.png[] `DaoAuthenticationProvider` then uses the <> to validate the password on the `UserDetails` returned in the previous step. -+image:{icondir}/number_4.png[] `DaoAuthenticationProvider` uses the <> to validate the password on the `UserDetails` returned in the previous step. - - image:{icondir}/number_5.png[] When authentication is successful, the <> that is returned is of type `UsernamePasswordAuthenticationToken` and has a principal that is the `UserDetails` returned by the configured `UserDetailsService`. --Ultimately, the returned `UsernamePasswordAuthenticationToken` will be set on the <> by the authentication `Filter`. -+Ultimately, the returned `UsernamePasswordAuthenticationToken` is set on the <> by the authentication `Filter`. -diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/digest.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/digest.adoc -index 603db7d93d..565503a29f 100644 ---- a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/digest.adoc -+++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/digest.adoc -@@ -1,26 +1,23 @@ - [[servlet-authentication-digest]] - = Digest Authentication - --This section provides details on how Spring Security provides support for https://tools.ietf.org/html/rfc2617[Digest Authentication] which is provided `DigestAuthenticationFilter`. -+This section provides details on how Spring Security provides support for https://tools.ietf.org/html/rfc2617[Digest Authentication], which is provided `DigestAuthenticationFilter`. - --[WARNING] --==== --You should not use Digest Authentication in modern applications because it is not considered secure. --The most obvious problem is that you must store your passwords in plaintext, encrypted, or an MD5 format. -+WARNING: You should not use Digest Authentication in modern applications, because it is not considered to be secure. -+The most obvious problem is that you must store your passwords in plaintext or an encrypted or MD5 format. - All of these storage formats are considered insecure. --Instead, you should store credentials using a one way adaptive password hash (i.e. bCrypt, PBKDF2, SCrypt, etc) which is not supported by Digest Authentication. --==== -+Instead, you should store credentials by using a one way adaptive password hash (bCrypt, PBKDF2, SCrypt, and others), which is not supported by Digest Authentication. - --Digest Authentication attempts to solve many of the weaknesses of <>, specifically by ensuring credentials are never sent in clear text across the wire. -+Digest Authentication tries to solve many of the weaknesses of <>, specifically by ensuring credentials are never sent in clear text across the wire. - Many https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Digest#Browser_compatibility[browsers support Digest Authentication]. - - The standard governing HTTP Digest Authentication is defined by https://tools.ietf.org/html/rfc2617[RFC 2617], which updates an earlier version of the Digest Authentication standard prescribed by https://tools.ietf.org/html/rfc2069[RFC 2069]. - Most user agents implement RFC 2617. - Spring Security's Digest Authentication support is compatible with the "`auth`" quality of protection (`qop`) prescribed by RFC 2617, which also provides backward compatibility with RFC 2069. --Digest Authentication was seen as a more attractive option if you need to use unencrypted HTTP (i.e. no TLS/HTTPS) and wish to maximise security of the authentication process. -+Digest Authentication was seen as a more attractive option if you need to use unencrypted HTTP (no TLS or HTTPS) and wish to maximize security of the authentication process. - However, everyone should use <>. - --Central to Digest Authentication is a "nonce". -+Central to Digest Authentication is a "`nonce`". - This is a value the server generates. - Spring Security's nonce adopts the following format: - -@@ -34,7 +31,8 @@ key: A private key to prevent modification of the nonce token - ---- - ==== - --You will need to ensure you <> insecure plain text <> using NoOpPasswordEncoder`. -+You need to ensure that you <> insecure plain text <> by using `NoOpPasswordEncoder`. -+(See the {security-api-url}org/springframework/security/crypto/password/NoOpPasswordEncoder.html[`NoOpPasswordEncoder`] class in the Javadoc.) - The following provides an example of configuring Digest Authentication with Java Configuration: - - .Digest Authentication -diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/form.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/form.adoc -index 27343234e5..85f7601fcd 100644 ---- a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/form.adoc -+++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/form.adoc -@@ -1,71 +1,70 @@ - [[servlet-authentication-form]] - = Form Login - --Spring Security provides support for username and password being provided through an html form. -+Spring Security provides support for username and password being provided through an HTML form. - This section provides details on how form based authentication works within Spring Security. - // FIXME: describe authenticationentrypoint, authenticationfailurehandler, authenticationsuccesshandler - --Let's take a look at how form based log in works within Spring Security. --First, we see how the user is redirected to the log in form. -+This section examines how form-based login works within Spring Security. -+First, we see how the user is redirected to the log in form: - - .Redirecting to the Log In Page - image::{figures}/loginurlauthenticationentrypoint.png[] - --The figure builds off our <> diagram. -+The preceding figure builds off our <> diagram. - --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_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 <> indicates that the unauthenticated request is __Denied__ by throwing an `AccessDeniedException`. - --image:{icondir}/number_3.png[] Since the user is not authenticated, <> initiates __Start Authentication__ and sends a redirect to the log in page with the configured <>. --In most cases the `AuthenticationEntryPoint` is an instance of {security-api-url}org/springframework/security/web/authentication/LoginUrlAuthenticationEntryPoint.html[`LoginUrlAuthenticationEntryPoint`]. -+image:{icondir}/number_3.png[] Since the user is not authenticated, <> initiates __Start Authentication__ and sends a redirect to the login page with the configured <>. -+In most cases, the `AuthenticationEntryPoint` is an instance of {security-api-url}org/springframework/security/web/authentication/LoginUrlAuthenticationEntryPoint.html[`LoginUrlAuthenticationEntryPoint`]. - --image:{icondir}/number_4.png[] The browser will then request the log in page that it was redirected to. -+image:{icondir}/number_4.png[] The browser requests the login page to which it was redirected. - --image:{icondir}/number_5.png[] Something within the application, must <>. -+image:{icondir}/number_5.png[] Something within the application must <>. - - [[servlet-authentication-usernamepasswordauthenticationfilter]] - When the username and password are submitted, the `UsernamePasswordAuthenticationFilter` authenticates the username and password. --The `UsernamePasswordAuthenticationFilter` extends <>, so this diagram should look pretty similar. -+The `UsernamePasswordAuthenticationFilter` extends <>, so the following diagram should look pretty similar: - - .Authenticating Username and Password - image::{figures}/usernamepasswordauthenticationfilter.png[] - - The figure builds off our <> diagram. - -+image:{icondir}/number_1.png[] When the user submits their username and password, the `UsernamePasswordAuthenticationFilter` creates a `UsernamePasswordAuthenticationToken`, which is a type of <>, by extracting the username and password from the `HttpServletRequest` instance. - --image:{icondir}/number_1.png[] When the user submits their username and password, the `UsernamePasswordAuthenticationFilter` creates a `UsernamePasswordAuthenticationToken` which is a type of <> by extracting the username and password from the `HttpServletRequest`. -- --image:{icondir}/number_2.png[] Next, the `UsernamePasswordAuthenticationToken` is passed into the `AuthenticationManager` to be authenticated. -+image:{icondir}/number_2.png[] Next, the `UsernamePasswordAuthenticationToken` is passed into the `AuthenticationManager` instance to be authenticated. - The details of what `AuthenticationManager` look like depend on how the <>. - --image:{icondir}/number_3.png[] If authentication fails, then __Failure__ -+image:{icondir}/number_3.png[] If authentication fails, then __Failure__. - --* The <> is cleared out. --* `RememberMeServices.loginFail` is invoked. -+. The <> is cleared out. -+. `RememberMeServices.loginFail` is invoked. - If remember me is not configured, this is a no-op. --// FIXME: link to rememberme --* `AuthenticationFailureHandler` is invoked. --// FIXME: link to AuthenticationFailureHandler -+See the {security-api-url}org/springframework/security/web/authentication/RememberMeServices.html[`RememberMeServices`] interface in the Javadoc. -+. `AuthenticationFailureHandler` is invoked. -+See the {security-api-url}springframework/security/web/authentication/AuthenticationFailureHandler.html[`AuthenticationFailureHandler`] class in the Javadoc - - image:{icondir}/number_4.png[] If authentication is successful, then __Success__. - --* `SessionAuthenticationStrategy` is notified of a new log in. --// FIXME: Add link to SessionAuthenticationStrategy --* The <> is set on the <>. --// FIXME: link securitycontextpersistencefilter --* `RememberMeServices.loginSuccess` is invoked. -+. `SessionAuthenticationStrategy` is notified of a new log in. -+See the {security-api-url}springframework/security/web/authentication/session/SessionAuthenticationStrategy.html[`SessionAuthenticationStrategy`] interface in the Javadoc. -+. The <> is set on the <>. -+See the {security-api-url}springframework/security/web/context/SecurityContextPersistenceFilter.html[`SecurityContextPersistenceFilter`] class in the Javadoc. -+. `RememberMeServices.loginSuccess` is invoked. - If remember me is not configured, this is a no-op. --// FIXME: link to rememberme --* `ApplicationEventPublisher` publishes an `InteractiveAuthenticationSuccessEvent`. --* The `AuthenticationSuccessHandler` is invoked. Typically this is a `SimpleUrlAuthenticationSuccessHandler` which will redirect to a request saved by <> when we redirect to the log in page. -+See the {security-api-url}springframework/security/web/authentication/RememberMeServices.html[`RememberMeServices`] interface in the Javadoc. -+. `ApplicationEventPublisher` publishes an `InteractiveAuthenticationSuccessEvent`. -+. The `AuthenticationSuccessHandler` is invoked. Typically, this is a `SimpleUrlAuthenticationSuccessHandler`, which redirects to a request saved by <> when we redirect to the login page. - - [[servlet-authentication-form-min]] --Spring Security form log in is enabled by default. --However, as soon as any servlet based configuration is provided, form based log in must be explicitly provided. --A minimal, explicit Java configuration can be found below: -+By default, Spring Security form login is enabled. -+However, as soon as any servlet-based configuration is provided, form based login must be explicitly provided. -+The following example shows a minimal, explicit Java configuration: - --.Form Log In -+.Form LogIn - ==== - .Java - [source,java,role="primary"] -@@ -98,11 +97,11 @@ fun configure(http: HttpSecurity) { - ---- - ==== - --In this configuration Spring Security will render a default log in page. --Most production applications will require a custom log in form. -+In the preceding configuration, Spring Security renders a default login page. -+Most production applications require a custom login form. - - [[servlet-authentication-form-custom]] --The configuration below demonstrates how to provide a custom log in form. -+The following configuration demonstrates how to provide a custom login form. - - .Custom Log In Form Configuration - ==== -@@ -147,9 +146,9 @@ fun configure(http: HttpSecurity) { - [[servlet-authentication-form-custom-html]] - When the login page is specified in the Spring Security configuration, you are responsible for rendering the page. - // FIXME: default login page rendered by Spring Security --Below is a https://www.thymeleaf.org/[Thymeleaf] template that produces an HTML login form that complies with a login page of `/login`.: -+The following https://www.thymeleaf.org/[Thymeleaf] template produces an HTML login form that complies with a login page of `/login`.: - --.Log In Form -+.Login Form - ==== - .src/main/resources/templates/login.html - [source,xml] -@@ -181,19 +180,19 @@ Below is a https://www.thymeleaf.org/[Thymeleaf] template that produces an HTML - - There are a few key points about the default HTML form: - --* The form should perform a `post` to `/login` --* The form will need to include a <> which is <> by Thymeleaf. --* The form should specify the username in a parameter named `username` --* The form should specify the password in a parameter named `password` --* If the HTTP parameter error is found, it indicates the user failed to provide a valid username / password --* If the HTTP parameter logout is found, it indicates the user has logged out successfully -+* The form should perform a `post` to `/login`. -+* The form needs to include a <>, which is <> by Thymeleaf. -+* The form should specify the username in a parameter named `username`. -+* The form should specify the password in a parameter named `password`. -+* If the HTTP parameter named `error` is found, it indicates the user failed to provide a valid username or password. -+* If the HTTP parameter named `logout` is found, it indicates the user has logged out successfully. - --Many users will not need much more than to customize the log in page. --However, if needed everything above can be customized with additional configuration. -+Many users do not need much more than to customize the log in page. -+However, if needed, you can customize everything shown earlier with additional configuration. - - [[servlet-authentication-form-custom-controller]] --If you are using Spring MVC, you will need a controller that maps `GET /login` to the login template we created. --A minimal sample `LoginController` can be see below: -+If you use Spring MVC, you need a controller that maps `GET /login` to the login template we created. -+The following example shows a minimal `LoginController`: - - .LoginController - ==== -diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/in-memory.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/in-memory.adoc -index a364cee0e1..5b2a37a49f 100644 ---- a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/in-memory.adoc -+++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/in-memory.adoc -@@ -3,9 +3,9 @@ - - Spring Security's `InMemoryUserDetailsManager` implements <> to provide support for username/password based authentication that is retrieved in memory. - `InMemoryUserDetailsManager` provides management of `UserDetails` by implementing the `UserDetailsManager` interface. --`UserDetails` based authentication is used by Spring Security when it is configured to <> for authentication. -+`UserDetails`-based authentication is used by Spring Security when it is configured to <> for authentication. - --In this sample we use <> to encode the password of `password` and get the encoded password of `+{bcrypt}$2a$10$GRLdNijSQMUvl/au9ofL.eDwmoohzzS7.rmNSJZ.0FxO/BTk76klW+`. -+In the following sample, we use <> to encode a password value of `password` and get the encoded password of `+{bcrypt}$2a$10$GRLdNijSQMUvl/au9ofL.eDwmoohzzS7.rmNSJZ.0FxO/BTk76klW+`: - - .InMemoryUserDetailsManager Java Configuration - ==== -@@ -61,12 +61,11 @@ fun users(): UserDetailsService { - ---- - ==== - --The samples above store the passwords in a secure format, but leave a lot to be desired in terms of getting started experience. -+The preceding samples store the passwords in a secure format but leave a lot to be desired in terms of a getting started experience. - -- --In the sample below we leverage <> to ensure that the password stored in memory is protected. -+In the following sample, we use <> to ensure that the password stored in memory is protected. - However, it does not protect against obtaining the password by decompiling the source code. --For this reason, `User.withDefaultPasswordEncoder` should only be used for "getting started" and is not intended for production. -+For this reason, `User.withDefaultPasswordEncoder` should only be used for "`getting started`" and is not intended for production. - - .InMemoryUserDetailsManager with User.withDefaultPasswordEncoder - ==== -@@ -113,8 +112,8 @@ fun users(): UserDetailsService { - ---- - ==== - --There is no simple way to use `User.withDefaultPasswordEncoder` with XML based configuration. --For demos or just getting started, you can choose to prefix the password with `+{noop}+` to indicate <>. -+There is no simple way to use `User.withDefaultPasswordEncoder` with XML-based configuration. -+For demos or just getting started, you can choose to prefix the password with `+{noop}+` to indicate <>: - - . `+{noop}+` XML Configuration - ==== -diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/index.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/index.adoc -index 415d828118..13fc12aed9 100644 ---- a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/index.adoc -+++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/index.adoc -@@ -4,21 +4,21 @@ - :icondir: images/icons - - One of the most common ways to authenticate a user is by validating a username and password. --As such, Spring Security provides comprehensive support for authenticating with a username and password. -+Spring Security provides comprehensive support for authenticating with a username and password. - - [[servlet-authentication-unpwd-input]] --*Reading the Username & Password* -+== Reading the Username & Password - --Spring Security provides the following built in mechanisms for reading a username and password from the `HttpServletRequest`: -+Spring Security provides the following built-in mechanisms for reading a username and password from `HttpServletRequest`: - - * <> - * <> - * <> - - [[servlet-authentication-unpwd-storage]] --*Storage Mechanisms* -+== Storage Mechanisms - --Each of the supported mechanisms for reading a username and password can leverage any of the supported storage mechanisms: -+Each of the supported mechanisms for reading a username and password can use any of the supported storage mechanisms: - - * Simple Storage with <> - * Relational Databases with <> -diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/jdbc.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/jdbc.adoc -index 009e551512..740c8b4de7 100644 ---- a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/jdbc.adoc -+++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/jdbc.adoc -@@ -1,11 +1,11 @@ - [[servlet-authentication-jdbc]] - = JDBC Authentication - --Spring Security's `JdbcDaoImpl` implements <> to provide support for username/password based authentication that is retrieved using JDBC. -+Spring Security's `JdbcDaoImpl` implements <> to provide support for username-and-password-based authentication that is retrieved by using JDBC. - `JdbcUserDetailsManager` extends `JdbcDaoImpl` to provide management of `UserDetails` through the `UserDetailsManager` interface. --`UserDetails` based authentication is used by Spring Security when it is configured to <> for authentication. -+`UserDetails`-based authentication is used by Spring Security when it is configured to <> for authentication. - --In the following sections we will discuss: -+In the following sections, we discuss: - - * The <> used by Spring Security JDBC Authentication - * <> -@@ -14,20 +14,16 @@ In the following sections we will discuss: - [[servlet-authentication-jdbc-schema]] - == Default Schema - --Spring Security provides default queries for JDBC based authentication. -+Spring Security provides default queries for JDBC-based authentication. - This section provides the corresponding default schemas used with the default queries. --You will need to adjust the schema to match any customizations to the queries and the database dialect you are using. -+You need to adjust the schema to match any customizations to the queries and the database dialect you use. - - [[servlet-authentication-jdbc-schema-user]] - === User Schema - - `JdbcDaoImpl` requires tables to load the password, account status (enabled or disabled) and a list of authorities (roles) for the user. --The default schema required can be found below. - --[NOTE] --==== --The default schema is also exposed as a classpath resource named `org/springframework/security/core/userdetails/jdbc/users.ddl`. --==== -+NOTE: The default schema is also exposed as a classpath resource named `org/springframework/security/core/userdetails/jdbc/users.ddl`. - - .Default User Schema - ==== -@@ -48,8 +44,7 @@ create unique index ix_auth_username on authorities (username,authority); - ---- - ==== - --Oracle is a popular database choice, but requires a slightly different schema. --You can find the default Oracle Schema for users below. -+Oracle is a popular database choice but requires a slightly different schema: - - .Default User Schema for Oracle Databases - ==== -@@ -74,8 +69,7 @@ ALTER TABLE AUTHORITIES ADD CONSTRAINT AUTHORITIES_FK1 FOREIGN KEY (USERNAME) RE - [[servlet-authentication-jdbc-schema-group]] - === Group Schema - --If your application is leveraging groups, you will need to provide the groups schema. --The default schema for groups can be found below. -+If your application uses groups, you need to provide the groups schema: - - .Default Group Schema - ==== -@@ -105,7 +99,7 @@ create table group_members ( - == Setting up a DataSource - - Before we configure `JdbcUserDetailsManager`, we must create a `DataSource`. --In our example, we will setup an https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/data-access.html#jdbc-embedded-database-support[embedded DataSource] that is initialized with the <>. -+In our example, we set up an https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/data-access.html#jdbc-embedded-database-support[embedded DataSource] that is initialized with the <>. - - .Embedded Data Source - ==== -@@ -142,12 +136,12 @@ fun dataSource(): DataSource { - ---- - ==== - --In a production environment, you will want to ensure you setup a connection to an external database. -+In a production environment, you want to ensure that you set up a connection to an external database. - - [[servlet-authentication-jdbc-bean]] - == JdbcUserDetailsManager Bean - --In this sample we use <> to encode the password of `password` and get the encoded password of `+{bcrypt}$2a$10$GRLdNijSQMUvl/au9ofL.eDwmoohzzS7.rmNSJZ.0FxO/BTk76klW+`. -+In this sample, we use <> to encode a password value of `password` and get the encoded password of `+{bcrypt}$2a$10$GRLdNijSQMUvl/au9ofL.eDwmoohzzS7.rmNSJZ.0FxO/BTk76klW+`. - See the <> section for more details about how to store passwords. - - .JdbcUserDetailsManager -@@ -171,7 +165,7 @@ UserDetailsManager users(DataSource dataSource) { - JdbcUserDetailsManager users = new JdbcUserDetailsManager(dataSource); - users.createUser(user); - users.createUser(admin); -- return users; -+ return users; - } - ---- - -diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/ldap.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/ldap.adoc -index 57f456deb8..f1c32667e2 100644 ---- a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/ldap.adoc -+++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/ldap.adoc -@@ -1,25 +1,25 @@ - [[servlet-authentication-ldap]] - = LDAP Authentication - --LDAP is often used by organizations as a central repository for user information and as an authentication service. -+LDAP (Lightweight Directory Access Protocol) is often used by organizations as a central repository for user information and as an authentication service. - It can also be used to store the role information for application users. - --Spring Security's LDAP based authentication is used by Spring Security when it is configured to <> for authentication. --However, despite leveraging a username/password for authentication it does not integrate using `UserDetailsService` because in <> the LDAP server does not return the password so the application cannot perform validation of the password. -+Spring Security's LDAP-based authentication is used by Spring Security when it is configured to <> for authentication. -+However, despite using a username and password for authentication, it does not use `UserDetailsService`, because, in <>, the LDAP server does not return the password, so the application cannot perform validation of the password. - --There are many different scenarios for how an LDAP server may be configured so Spring Security's LDAP provider is fully configurable. --It uses separate strategy interfaces for authentication and role retrieval and provides default implementations which can be configured to handle a wide range of situations. -+There are many different scenarios for how an LDAP server can be configured, so Spring Security's LDAP provider is fully configurable. -+It uses separate strategy interfaces for authentication and role retrieval and provides default implementations, which can be configured to handle a wide range of situations. - - [[servlet-authentication-ldap-prerequisites]] - == Prerequisites - - You should be familiar with LDAP before trying to use it with Spring Security. --The following link provides a good introduction to the concepts involved and a guide to setting up a directory using the free LDAP server OpenLDAP: https://www.zytrax.com/books/ldap/. --Some familiarity with the JNDI APIs used to access LDAP from Java may also be useful. --We don't use any third-party LDAP libraries (Mozilla, JLDAP etc.) in the LDAP provider, but extensive use is made of Spring LDAP, so some familiarity with that project may be useful if you plan on adding your own customizations. -+The following link provides a good introduction to the concepts involved and a guide to setting up a directory using the free LDAP server, OpenLDAP: https://www.zytrax.com/books/ldap/. -+Some familiarity with the JNDI APIs used to access LDAP from Java can also be useful. -+We do not use any third-party LDAP libraries (Mozilla, JLDAP, or others) in the LDAP provider, but extensive use is made of Spring LDAP, so some familiarity with that project may be useful if you plan on adding your own customizations. - --When using LDAP authentication, it is important to ensure that you configure LDAP connection pooling properly. --If you are unfamiliar with how to do this, you can refer to the https://docs.oracle.com/javase/jndi/tutorial/ldap/connect/config.html[Java LDAP documentation]. -+When using LDAP authentication, you should ensure that you properly configure LDAP connection pooling. -+If you are unfamiliar with how to do so, see the https://docs.oracle.com/javase/jndi/tutorial/ldap/connect/config.html[Java LDAP documentation]. - - - // FIXME: -@@ -35,16 +35,17 @@ If you are unfamiliar with how to do this, you can refer to the https://docs.ora - [[servlet-authentication-ldap-embedded]] - == Setting up an Embedded LDAP Server - --The first thing you will need to do is to ensure that you have an LDAP Server to point your configuration to. --For simplicity, it often best to start with an embedded LDAP Server. -+The first thing you need to do is to ensure that you have an LDAP Server to which to point your configuration. -+For simplicity, it is often best to start with an embedded LDAP Server. - Spring Security supports using either: - - * <> - * <> - --In the samples below, we expose the following as `users.ldif` as a classpath resource to initialize the embedded LDAP server with the users `user` and `admin` both of which have a password of `password`. -+In the following samples, we expose `users.ldif` as a classpath resource to initialize the embedded LDAP server with two users, `user` and `admin`, both of which have a password of `password`: - - .users.ldif -+==== - [source,ldif] - ---- - dn: ou=groups,dc=springframework,dc=org -@@ -90,11 +91,12 @@ objectclass: groupOfNames - cn: admin - uniqueMember: uid=admin,ou=people,dc=springframework,dc=org - ---- -+==== - - [[servlet-authentication-ldap-unboundid]] - === Embedded UnboundID Server - --If you wish to use https://ldap.com/unboundid-ldap-sdk-for-java/[UnboundID], then specify the following dependencies: -+If you wish to use https://ldap.com/unboundid-ldap-sdk-for-java/[UnboundID], specify the following dependencies: - - .UnboundID Dependencies - ==== -@@ -118,7 +120,7 @@ depenendencies { - ---- - ==== - --You can then configure the Embedded LDAP Server -+You can then configure the Embedded LDAP Server: - - .Embedded LDAP Server Configuration - ==== -@@ -153,14 +155,11 @@ fun ldapContainer(): UnboundIdContainer { - [[servlet-authentication-ldap-apacheds]] - === Embedded ApacheDS Server - --[NOTE] --==== --Spring Security uses ApacheDS 1.x which is no longer maintained. -+NOTE: Spring Security uses ApacheDS 1.x, which is no longer maintained. - Unfortunately, ApacheDS 2.x has only released milestone versions with no stable release. - Once a stable release of ApacheDS 2.x is available, we will consider updating. --==== - --If you wish to use https://directory.apache.org/apacheds/[Apache DS], then specify the following dependencies: -+If you wish to use https://directory.apache.org/apacheds/[Apache DS], specify the following dependencies: - - .ApacheDS Dependencies - ==== -@@ -191,7 +190,7 @@ depenendencies { - ---- - ==== - --You can then configure the Embedded LDAP Server -+You can then configure the Embedded LDAP Server: - - .Embedded LDAP Server Configuration - ==== -@@ -226,8 +225,8 @@ fun ldapContainer(): ApacheDSContainer { - [[servlet-authentication-ldap-contextsource]] - == LDAP ContextSource - --Once you have an LDAP Server to point your configuration to, you need configure Spring Security to point to an LDAP server that should be used to authenticate users. --This is done by creating an LDAP `ContextSource`, which is the equivalent of a JDBC `DataSource`. -+Once you have an LDAP Server to which to point your configuration, you need to configure Spring Security to point to an LDAP server that should be used to authenticate users. -+To do so, create an LDAP `ContextSource` (which is the equivalent of a JDBC `DataSource`): - - .LDAP Context Source - ==== -@@ -258,15 +257,15 @@ fun contextSource(container: UnboundIdContainer): ContextSource { - [[servlet-authentication-ldap-authentication]] - == Authentication - --Spring Security's LDAP support does not use the <> because LDAP bind authentication does not allow clients to read the password or even a hashed version of the password. --This means there is no way a password to be read and then authenticated by Spring Security. -+Spring Security's LDAP support does not use the <> because LDAP bind authentication does not let clients read the password or even a hashed version of the password. -+This means there is no way for a password to be read and then authenticated by Spring Security. - --For this reason, LDAP support is implemented using the `LdapAuthenticator` interface. --The `LdapAuthenticator` is also responsible for retrieving any required user attributes. -+For this reason, LDAP support is implemented through the `LdapAuthenticator` interface. -+The `LdapAuthenticator` interface is also responsible for retrieving any required user attributes. - This is because the permissions on the attributes may depend on the type of authentication being used. --For example, if binding as the user, it may be necessary to read them with the user's own permissions. -+For example, if binding as the user, it may be necessary to read the attributes with the user's own permissions. - --There are two `LdapAuthenticator` implementations supplied with Spring Security: -+Spring Security supplies two `LdapAuthenticator` implementations: - - * <> - * <> -@@ -275,11 +274,10 @@ There are two `LdapAuthenticator` implementations supplied with Spring Security: - == Using Bind Authentication - - https://ldap.com/the-ldap-bind-operation/[Bind Authentication] is the most common mechanism for authenticating users with LDAP. --In bind authentication the users credentials (i.e. username/password) are submitted to the LDAP server which authenticates them. --The advantage to using bind authentication is that the user's secrets (i.e. password) do not need to be exposed to clients which helps to protect them from leaking. -+In bind authentication, the user's credentials (username and password) are submitted to the LDAP server, which authenticates them. -+The advantage to using bind authentication is that the user's secrets (the password) do not need to be exposed to clients, which helps to protect them from leaking. - -- --An example of bind authentication configuration can be found below. -+The following example shows bind authentication configuration: - - .Bind Authentication - ==== -@@ -323,9 +321,9 @@ fun authenticationProvider(authenticator: LdapAuthenticator): LdapAuthentication - ---- - ==== - --This simple example would obtain the DN for the user by substituting the user login name in the supplied pattern and attempting to bind as that user with the login password. -+The preceding simple example would obtain the DN for the user by substituting the user login name in the supplied pattern and attempting to bind as that user with the login password. - This is OK if all your users are stored under a single node in the directory. --If instead you wished to configure an LDAP search filter to locate the user, you could use the following: -+If, instead, you wish to configure an LDAP search filter to locate the user, you could use the following: - - .Bind Authentication with Search Filter - ==== -@@ -377,15 +375,15 @@ fun authenticationProvider(authenticator: LdapAuthenticator): LdapAuthentication - ---- - ==== - --If used with the `ContextSource` <>, this would perform a search under the DN `ou=people,dc=springframework,dc=org` using `+(uid={0})+` as a filter. --Again the user login name is substituted for the parameter in the filter name, so it will search for an entry with the `uid` attribute equal to the user name. --If a user search base isn't supplied, the search will be performed from the root. -+If used with the `ContextSource` <>, this would perform a search under the DN `ou=people,dc=springframework,dc=org` by using `+(uid={0})+` as a filter. -+Again, the user login name is substituted for the parameter in the filter name, so it searchs for an entry with the `uid` attribute equal to the user name. -+If a user search base is not supplied, the search is performed from the root. - - [[servlet-authentication-ldap-pwd]] - == Using Password Authentication - - Password comparison is when the password supplied by the user is compared with the one stored in the repository. --This can either be done by retrieving the value of the password attribute and checking it locally or by performing an LDAP "compare" operation, where the supplied password is passed to the server for comparison and the real password value is never retrieved. -+This can either be done by retrieving the value of the password attribute and checking it locally or by performing an LDAP "`compare`" operation, where the supplied password is passed to the server for comparison and the real password value is never retrieved. - An LDAP compare cannot be done when the password is properly hashed with a random salt. - - .Minimal Password Compare Configuration -@@ -428,7 +426,7 @@ fun authenticationProvider(authenticator: LdapAuthenticator): LdapAuthentication - ---- - ==== - --A more advanced configuration with some customizations can be found below. -+The following example shows a more advanced configuration with some customizations: - - .Password Compare Configuration - ==== -@@ -481,13 +479,14 @@ fun authenticationProvider(authenticator: LdapAuthenticator): LdapAuthentication - ---- - ==== - --<1> Specify the password attribute as `pwd` --<2> Use `BCryptPasswordEncoder` -+<1> Specify the password attribute as `pwd`. -+<2> Use `BCryptPasswordEncoder`. - - - == LdapAuthoritiesPopulator - --Spring Security's `LdapAuthoritiesPopulator` is used to determine what authorites are returned for the user. -+Spring Security's `LdapAuthoritiesPopulator` is used to determine what authorities are returned for the user. -+The following example shows how configure `LdapAuthoritiesPopulator`: - - .LdapAuthoritiesPopulator Configuration - ==== -@@ -537,14 +536,17 @@ fun authenticationProvider(authenticator: LdapAuthenticator, authorities: LdapAu - - == Active Directory - --Active Directory supports its own non-standard authentication options, and the normal usage pattern doesn't fit too cleanly with the standard `LdapAuthenticationProvider`. --Typically authentication is performed using the domain username (in the form `user@domain`), rather than using an LDAP distinguished name. --To make this easier, Spring Security has an authentication provider which is customized for a typical Active Directory setup. -+Active Directory supports its own non-standard authentication options, and the normal usage pattern does not fit too cleanly with the standard `LdapAuthenticationProvider`. -+Typically, authentication is performed by using the domain username (in the form of `user@domain`), rather than using an LDAP distinguished name. -+To make this easier, Spring Security has an authentication provider, which is customized for a typical Active Directory setup. - - Configuring `ActiveDirectoryLdapAuthenticationProvider` is quite straightforward. --You just need to supply the domain name and an LDAP URL supplying the address of the server footnote:[It is also possible to obtain the server's IP address using a DNS lookup. --This is not currently supported, but hopefully will be in a future version.]. --An example configuration can be seen below: -+You need only supply the domain name and an LDAP URL that supplies the address of the server. -+ -+NOTE: It is also possible to obtain the server's IP address byusing a DNS lookup. -+This is not currently supported, but hopefully will be in a future version. -+ -+The following example configures Active Directory: - - .Example Active Directory Configuration - ==== -diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/password-encoder.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/password-encoder.adoc -index 73f9e1f2e1..70b7e79252 100644 ---- a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/password-encoder.adoc -+++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/password-encoder.adoc -@@ -1,5 +1,5 @@ - [[servlet-authentication-password-storage]] - = PasswordEncoder - --Spring Security's servlet support storing passwords securely by integrating with <>. --Customizing the `PasswordEncoder` implementation used by Spring Security can be done by <>. -+Spring Security's servlet support includes storing passwords securely by integrating with <>. -+You can customize the `PasswordEncoder` implementation used by Spring Security by <>. -diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/user-details-service.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/user-details-service.adoc -index 9147cedbd2..f630021ee5 100644 ---- a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/user-details-service.adoc -+++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/user-details-service.adoc -@@ -1,11 +1,11 @@ - [[servlet-authentication-userdetailsservice]] - = UserDetailsService - --{security-api-url}org/springframework/security/core/userdetails/UserDetailsService.html[`UserDetailsService`] is used by <> for retrieving a username, password, and other attributes for authenticating with a username and password. -+{security-api-url}org/springframework/security/core/userdetails/UserDetailsService.html[`UserDetailsService`] is used by <> for retrieving a username, a password, and other attributes for authenticating with a username and password. - Spring Security provides <> and <> implementations of `UserDetailsService`. - - You can define custom authentication by exposing a custom `UserDetailsService` as a bean. --For example, the following will customize authentication assuming that `CustomUserDetailsService` implements `UserDetailsService`: -+For example, the following listing customizes authentication, assuming that `CustomUserDetailsService` implements `UserDetailsService`: - - NOTE: This is only used if the `AuthenticationManagerBuilder` has not been populated and no `AuthenticationProviderBean` is defined. - -diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/x509.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/x509.adoc -index d84ae8560c..a3fbb9017e 100644 ---- a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/x509.adoc -+++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/x509.adoc -@@ -1,28 +1,27 @@ - [[servlet-x509]] - == X.509 Authentication - -- - [[x509-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. -+The browser automatically checks that the certificate presented by a server has been issued (digitally signed) by one of a list of trusted certificate authorities that it maintains. - --You can also use SSL with "mutual authentication"; the server will then request a valid certificate from the client as part of the SSL handshake. --The server will authenticate the client by checking that its certificate is signed by an acceptable authority. -+You can also use SSL with "`mutual authentication`". The server then requests a valid certificate from the client as part of the SSL handshake. -+The server authenticates the client by checking that its certificate is signed by an acceptable authority. - If a valid certificate has been provided, it can be obtained through the servlet API in an application. --Spring Security X.509 module extracts the certificate using a filter. -+The Spring Security X.509 module extracts the certificate by using a filter. - It maps the certificate to an application user and loads that user's set of granted authorities for use with the standard Spring Security infrastructure. - - You should be familiar with using certificates and setting up client authentication for your servlet container before attempting to use it with Spring Security. - Most of the work is in creating and installing suitable certificates and keys. --For example, if you're using Tomcat then read the instructions here https://tomcat.apache.org/tomcat-9.0-doc/ssl-howto.html[https://tomcat.apache.org/tomcat-9.0-doc/ssl-howto.html]. --It's important that you get this working before trying it out with Spring Security -+For example, if you use Tomcat, you should read the https://tomcat.apache.org/tomcat-9.0-doc/ssl-howto.html[Tomcat SSL instructions]. -+You should get this working before trying it out with Spring Security. - - - === Adding X.509 Authentication to Your Web Application - Enabling X.509 client authentication is very straightforward. --Just add the `` element to your http security namespace configuration. -+To do so, add the `` element to your http security namespace configuration: - -+==== - [source,xml] - ---- - -@@ -30,39 +29,40 @@ Just add the `` element to your http security namespace configuration. - ; - - ---- -+==== - - The element has two optional attributes: - - * `subject-principal-regex`. - The regular expression used to extract a username from the certificate's subject name. --The default value is shown above. --This is the username which will be passed to the `UserDetailsService` to load the authorities for the user. -+The default value is shown in the preceding listing. -+This is the username that is passed to the `UserDetailsService` to load the authorities for the user. - * `user-service-ref`. --This is the bean Id of the `UserDetailsService` to be used with X.509. --It isn't needed if there is only one defined in your application context. -+This is the bean ID of the `UserDetailsService` to be used with X.509. -+It is not needed if there is only one defined in your application context. - - The `subject-principal-regex` should contain a single group. --For example the default expression "CN=(.*?)," matches the common name field. --So if the subject name in the certificate is "CN=Jimi Hendrix, OU=...", this will give a user name of "Jimi Hendrix". -+For example, the default expression (`CN=(.*?)`) matches the common name field. -+So, if the subject name in the certificate is "CN=Jimi Hendrix, OU=...", this gives a user name of "Jimi Hendrix". - The matches are case insensitive. --So "emailAddress=(+.*?+)," will match "EMAILADDRESS=jimi@hendrix.org,CN=..." giving a user name "jimi@hendrix.org". --If the client presents a certificate and a valid username is successfully extracted, then there should be a valid `Authentication` object in the security context. --If no certificate is found, or no corresponding user could be found then the security context will remain empty. --This means that you can easily use X.509 authentication with other options such as a form-based login. -+So "emailAddress=(+.*?+)," matches "EMAILADDRESS=jimi@hendrix.org,CN=...", giving a user name "jimi@hendrix.org". -+If the client presents a certificate and a valid username is successfully extracted, there should be a valid `Authentication` object in the security context. -+If no certificate is found or no corresponding user could be found, the security context remains empty. -+This means that you can use X.509 authentication with other options, such as a form-based login. - - [[x509-ssl-config]] - === Setting up SSL in Tomcat - There are some pre-generated certificates in the `samples/certificate` directory in the Spring Security project. --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. -+You can use these to enable SSL for testing if you do not want to generate your own. -+The `server.jks` file contains the server certificate, the private key, and the issuing authority certificate. - There are also some client certificate files for the users from the sample applications. - You can install these in your browser to enable SSL client authentication. - --To run tomcat with SSL support, drop the `server.jks` file into the tomcat `conf` directory and add the following connector to the `server.xml` file -+To run tomcat with SSL support, drop the `server.jks` file into the tomcat `conf` directory and add the following connector to the `server.xml` file: - -+==== - [source,xml] - ---- -- - -- - ---- -+==== - --`clientAuth` can also be set to `want` if you still want SSL connections to succeed even if the client doesn't provide a certificate. --Clients which don't present a certificate won't be able to access any objects secured by Spring Security unless you use a non-X.509 authentication mechanism, such as form authentication. -- -+`clientAuth` can also be set to `want` if you still want SSL connections to succeed even if the client does not provide a certificate. -+Clients that do not present a certificate cannot access any objects secured by Spring Security unless you use a non-X.509 authentication mechanism, such as form authentication. -diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authorization/acls.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authorization/acls.adoc -index f87e83d4ee..f55f59ec1b 100644 ---- a/docs/manual/src/docs/asciidoc/_includes/servlet/authorization/acls.adoc -+++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authorization/acls.adoc -@@ -1,153 +1,146 @@ - [[domain-acls]] - == Domain Object Security (ACLs) - -+This section describes how Spring Security provides domain object security with Access Control Lists (ACLs). -+ - [[domain-acls-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`). -+Complex applications often need to define access permissions beyond a web request or method invocation level. -+Instead, security decisions need to comprise 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. - --Imagine you're designing an application for a pet clinic. --There will be two main groups of users of your Spring-based application: staff of the pet clinic, as well as the pet clinic's customers. --The staff will have access to all of the data, whilst your customers will only be able to see their own customer records. --To make it a little more interesting, your customers can allow other users to see their customer records, such as their "puppy preschool" mentor or president of their local "Pony Club". --Using Spring Security as the foundation, you have several approaches that can be used: -+Imagine you are designing an application for a pet clinic. -+There are two main groups of users of your Spring-based application: staff of the pet clinic and the pet clinic's customers. -+The staff should have access to all of the data, while your customers should be able to see only their own customer records. -+To make it a little more interesting, your customers can let other users see their customer records, such as their "`puppy preschool`" mentor or the president of their local "`Pony Club`". -+When you use Spring Security as the foundation, you have several possible approaches: - - * Write your business methods to enforce the security. - You could consult a collection within the `Customer` domain object instance to determine which users have access. --By using the `SecurityContextHolder.getContext().getAuthentication()`, you'll be able to access the `Authentication` object. --* Write an `AccessDecisionVoter` to enforce the security from the `GrantedAuthority[]` s stored in the `Authentication` object. --This would mean your `AuthenticationManager` would need to populate the `Authentication` with custom ``GrantedAuthority[]``s representing each of the `Customer` domain object instances the principal has access to. -+By using `SecurityContextHolder.getContext().getAuthentication()`, you can access the `Authentication` object. -+* Write an `AccessDecisionVoter` to enforce the security from the `GrantedAuthority[]` instances stored in the `Authentication` object. -+This means that your `AuthenticationManager` needs to populate the `Authentication` with custom `GrantedAuthority[]` objects to represent each of the `Customer` domain object instances to which the principal has access. - * Write an `AccessDecisionVoter` to enforce the security and open the target `Customer` domain object directly. --This would mean your voter needs access to a DAO that allows it to retrieve the `Customer` object. --It would then access the `Customer` object's collection of approved users and make the appropriate decision. -- -+This would mean your voter needs access to a DAO that lets it retrieve the `Customer` object. -+It can then access the `Customer` object's collection of approved users and make the appropriate decision. - - Each one of these approaches is perfectly legitimate. - However, the first couples your authorization checking to your business code. --The main problems with this include the enhanced difficulty of unit testing and the fact it would be more difficult to reuse the `Customer` authorization logic elsewhere. --Obtaining the `GrantedAuthority[]` s from the `Authentication` object is also fine, but will not scale to large numbers of `Customer` s. --If a user might be able to access 5,000 `Customer` s (unlikely in this case, but imagine if it were a popular vet for a large Pony Club!) the amount of memory consumed and time required to construct the `Authentication` object would be undesirable. -+The main problems with this include the enhanced difficulty of unit testing and the fact that it would be more difficult to reuse the `Customer` authorization logic elsewhere. -+Obtaining the `GrantedAuthority[]` instances from the `Authentication` object is also fine but will not scale to large numbers of `Customer` objects. -+If a user can access 5,000 `Customer` objects (unlikely in this case, but imagine if it were a popular vet for a large Pony Club!) the amount of memory consumed and the time required to construct the `Authentication` object would be undesirable. - The final method, opening the `Customer` directly from external code, is probably the best of the three. --It achieves separation of concerns, and doesn't misuse memory or CPU cycles, but it is still inefficient in that both the `AccessDecisionVoter` and the eventual business method itself will perform a call to the DAO responsible for retrieving the `Customer` object. -+It achieves separation of concerns and does not misuse memory or CPU cycles, but it is still inefficient in that both the `AccessDecisionVoter` and the eventual business method itself perform a call to the DAO responsible for retrieving the `Customer` object. - Two accesses per method invocation is clearly undesirable. --In addition, with every approach listed you'll need to write your own access control list (ACL) persistence and business logic from scratch. -- --Fortunately, there is another alternative, which we'll talk about below. -+In addition, with every approach listed, you need to write your own access control list (ACL) persistence and business logic from scratch. - -+Fortunately, there is another alternative, which we discuss later. - - [[domain-acls-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. -+You need to add this JAR to your classpath to use Spring Security's domain object instance security capabilities. - --Spring Security's domain object instance security capabilities centre on the concept of an access control list (ACL). --Every domain object instance in your system has its own ACL, and the ACL records details of who can and can't work with that domain object. --With this in mind, Spring Security delivers three main ACL-related capabilities to your application: -+Spring Security's domain object instance security capabilities center on the concept of an access control list (ACL). -+Every domain object instance in your system has its own ACL, and the ACL records details of who can and cannot work with that domain object. -+With this in mind, Spring Security provides three main ACL-related capabilities to your application: - --* A way of efficiently retrieving ACL entries for all of your domain objects (and modifying those ACLs) --* A way of ensuring a given principal is permitted to work with your objects, before methods are called --* A way of ensuring a given principal is permitted to work with your objects (or something they return), after methods are called -+* A way to efficiently retrieve ACL entries for all of your domain objects (and modifying those ACLs) -+* A way to ensure a given principal is permitted to work with your objects before methods are called -+* A way to ensure a given principal is permitted to work with your objects (or something they return) after methods are called - - As indicated by the first bullet point, one of the main capabilities of the Spring Security ACL module is providing a high-performance way of retrieving ACLs. --This ACL repository capability is extremely important, because every domain object instance in your system might have several access control entries, and each ACL might inherit from other ACLs in a tree-like structure (this is supported out-of-the-box by Spring Security, and is very commonly used). -+This ACL repository capability is extremely important, because every domain object instance in your system might have several access control entries, and each ACL might inherit from other ACLs in a tree-like structure (this is supported by Spring Security, and it is very commonly used). - Spring Security's ACL capability has been carefully designed to provide high performance retrieval of ACLs, together with pluggable caching, deadlock-minimizing database updates, independence from ORM frameworks (we use JDBC directly), proper encapsulation, and transparent database updating. - --Given databases are central to the operation of the ACL module, let's explore the four main tables used by default in the implementation. --The tables are presented below in order of size in a typical Spring Security ACL deployment, with the table with the most rows listed last: -- -+Given that databases are central to the operation of the ACL module, we need explore the four main tables used by default in the implementation. -+The tables are presented in order of size in a typical Spring Security ACL deployment, with the table with the most rows listed last: - -- --* ACL_SID allows us to uniquely identify any principal or authority in the system ("SID" stands for "security identity"). -+[[acl_tables]] -+* `ACL_SID` lets us uniquely identify any principal or authority in the system ("`SID`" stands for "`Security IDentity`"). - The only columns are the ID, a textual representation of the SID, and a flag to indicate whether the textual representation refers to a principal name or a `GrantedAuthority`. - Thus, there is a single row for each unique principal or `GrantedAuthority`. --When used in the context of receiving a permission, a SID is generally called a "recipient". -+When used in the context of receiving a permission, an SID is generally called a "`recipient`". - --* ACL_CLASS allows us to uniquely identify any domain object class in the system. -+* `ACL_CLASS` lets us uniquely identify any domain object class in the system. - The only columns are the ID and the Java class name. --Thus, there is a single row for each unique Class we wish to store ACL permissions for. -+Thus, there is a single row for each unique Class for which we wish to store ACL permissions. - --* ACL_OBJECT_IDENTITY stores information for each unique domain object instance in the system. --Columns include the ID, a foreign key to the ACL_CLASS table, a unique identifier so we know which ACL_CLASS instance we're providing information for, the parent, a foreign key to the ACL_SID table to represent the owner of the domain object instance, and whether we allow ACL entries to inherit from any parent ACL. --We have a single row for every domain object instance we're storing ACL permissions for. -+* `ACL_OBJECT_IDENTITY` stores information for each unique domain object instance in the system. -+Columns include the ID, a foreign key to the ACL_CLASS table, a unique identifier so we know the ACL_CLASS instance for which we provide information, the parent, a foreign key to the ACL_SID table to represent the owner of the domain object instance, and whether we allow ACL entries to inherit from any parent ACL. -+We have a single row for every domain object instance for which we store ACL permissions. - --* Finally, ACL_ENTRY stores the individual permissions assigned to each recipient. --Columns include a foreign key to the ACL_OBJECT_IDENTITY, the recipient (i.e. a foreign key to ACL_SID), whether we'll be auditing or not, and the integer bit mask that represents the actual permission being granted or denied. -+* Finally, `ACL_ENTRY` stores the individual permissions assigned to each recipient. -+Columns include a foreign key to the ACL_OBJECT_IDENTITY, the recipient (which is a foreign key to ACL_SID), whether we audit or not, and the integer bit mask that represents the actual permission being granted or denied. - We have a single row for every recipient that receives a permission to work with a domain object. - -- -- -- - As mentioned in the last paragraph, the ACL system uses integer bit masking. --Don't worry, you need not be aware of the finer points of bit shifting to use the ACL system, but suffice to say that we have 32 bits we can switch on or off. --Each of these bits represents a permission, and by default the permissions are read (bit 0), write (bit 1), create (bit 2), delete (bit 3) and administer (bit 4). --It's easy to implement your own `Permission` instance if you wish to use other permissions, and the remainder of the ACL framework will operate without knowledge of your extensions. -- --It is important to understand that the number of domain objects in your system has absolutely no bearing on the fact we've chosen to use integer bit masking. --Whilst you have 32 bits available for permissions, you could have billions of domain object instances (which will mean billions of rows in ACL_OBJECT_IDENTITY and quite probably ACL_ENTRY). --We make this point because we've found sometimes people mistakenly believe they need a bit for each potential domain object, which is not the case. -+However, you need not be aware of the finer points of bit shifting to use the ACL system. -+Suffice it to say that we have 32 bits we can switch on or off. -+Each of these bits represents a permission. By default, the permissions are read (bit 0), write (bit 1), create (bit 2), delete (bit 3), and administer (bit 4). -+You can implement your own `Permission` instance if you wish to use other permissions, and the remainder of the ACL framework operates without knowledge of your extensions. - --Now that we've provided a basic overview of what the ACL system does, and what it looks like at a table structure, let's explore the key interfaces. --The key interfaces are: -+You should understand that the number of domain objects in your system has absolutely no bearing on the fact that we have chosen to use integer bit masking. -+While you have 32 bits available for permissions, you could have billions of domain object instances (which means billions of rows in ACL_OBJECT_IDENTITY and, probably, ACL_ENTRY). -+We make this point because we have found that people sometimes mistakenly that believe they need a bit for each potential domain object, which is not the case. - -+Now that we have provided a basic overview of what the ACL system does, and what it looks like at a table-structure level, we need to explore the key interfaces: - --* `Acl`: Every domain object has one and only one `Acl` object, which internally holds the `AccessControlEntry` s as well as knows the owner of the `Acl`. -+* `Acl`: Every domain object has one and only one `Acl` object, which internally holds the `AccessControlEntry` objects and knows the owner of the `Acl`. - An Acl does not refer directly to the domain object, but instead to an `ObjectIdentity`. --The `Acl` is stored in the ACL_OBJECT_IDENTITY table. -+The `Acl` is stored in the `ACL_OBJECT_IDENTITY` table. - --* `AccessControlEntry`: An `Acl` holds multiple `AccessControlEntry` s, which are often abbreviated as ACEs in the framework. --Each ACE refers to a specific tuple of `Permission`, `Sid` and `Acl`. -+* `AccessControlEntry`: An `Acl` holds multiple `AccessControlEntry` objects, which are often abbreviated as ACEs in the framework. -+Each ACE refers to a specific tuple of `Permission`, `Sid`, and `Acl`. - An ACE can also be granting or non-granting and contain audit settings. --The ACE is stored in the ACL_ENTRY table. -+The ACE is stored in the `ACL_ENTRY` table. - --* `Permission`: A permission represents a particular immutable bit mask, and offers convenience functions for bit masking and outputting information. -+* `Permission`: A permission represents a particular immutable bit mask and offers convenience functions for bit masking and outputting information. - The basic permissions presented above (bits 0 through 4) are contained in the `BasePermission` class. - --* `Sid`: The ACL module needs to refer to principals and `GrantedAuthority[]` s. --A level of indirection is provided by the `Sid` interface, which is an abbreviation of "security identity". -+* `Sid`: The ACL module needs to refer to principals and `GrantedAuthority[]` instances. -+A level of indirection is provided by the `Sid` interface. ("`SID`" is an abbreviation of "`Security IDentity`".) - Common classes include `PrincipalSid` (to represent the principal inside an `Authentication` object) and `GrantedAuthoritySid`. --The security identity information is stored in the ACL_SID table. -+The security identity information is stored in the `ACL_SID` table. - - * `ObjectIdentity`: Each domain object is represented internally within the ACL module by an `ObjectIdentity`. - The default implementation is called `ObjectIdentityImpl`. - - * `AclService`: Retrieves the `Acl` applicable for a given `ObjectIdentity`. - In the included implementation (`JdbcAclService`), retrieval operations are delegated to a `LookupStrategy`. --The `LookupStrategy` provides a highly optimized strategy for retrieving ACL information, using batched retrievals (`BasicLookupStrategy`) and supporting custom implementations that leverage materialized views, hierarchical queries and similar performance-centric, non-ANSI SQL capabilities. -- --* `MutableAclService`: Allows a modified `Acl` to be presented for persistence. --It is not essential to use this interface if you do not wish. -- -+The `LookupStrategy` provides a highly optimized strategy for retrieving ACL information, using batched retrievals (`BasicLookupStrategy`) and supporting custom implementations that use materialized views, hierarchical queries, and similar performance-centric, non-ANSI SQL capabilities. - -+* `MutableAclService`: Lets a modified `Acl` be presented for persistence. -+Use of this interface is optional. - --Please note that our out-of-the-box AclService and related database classes all use ANSI SQL. -+Note that our `AclService` and related database classes all use ANSI SQL. - This should therefore work with all major databases. --At the time of writing, the system had been successfully tested using Hypersonic SQL, PostgreSQL, Microsoft SQL Server and Oracle. -+At the time of writing, the system had been successfully tested with Hypersonic SQL, PostgreSQL, Microsoft SQL Server, and Oracle. - - Two samples ship with Spring Security that demonstrate the ACL module. --The first is the Contacts Sample, and the other is the Document Management System (DMS) Sample. --We suggest taking a look over these for examples. -+The first is the https://github.com/spring-projects/spring-security/tree/master/samples/xml/contacts[Contacts sample], and the other is the https://github.com/spring-projects/spring-security/tree/master/samples/xml/dms[Document Management System (DMS) sample]. -+We suggest taking a look at these examples. - - - [[domain-acls-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. --The latter provides high-performance ACL retrieval capabilities, and the former provides mutator capabilities. --Refer to one of the samples that ship with Spring Security for an example configuration. --You'll also need to populate the database with the four ACL-specific tables listed in the last section (refer to the ACL samples for the appropriate SQL statements). -- --Once you've created the required schema and instantiated `JdbcMutableAclService`, you'll next need to ensure your domain model supports interoperability with the Spring Security ACL package. --Hopefully `ObjectIdentityImpl` will prove sufficient, as it provides a large number of ways in which it can be used. --Most people will have domain objects that contain a `public Serializable getId()` method. --If the return type is long, or compatible with long (e.g. an int), you will find you need not give further consideration to `ObjectIdentity` issues. -+To get starting with Spring Security's ACL capability, you need to store your ACL information somewhere. -+This necessitates the instantiation of a `DataSource` in Spring. -+The `DataSource` is then injected into a `JdbcMutableAclService` and a `BasicLookupStrategy` instance. -+The former provides mutator capabilities, and the latter provides high-performance ACL retrieval capabilities. -+See one of the https://github.com/spring-projects/spring-security/tree/master/samples[samples] that ship with Spring Security for an example configuration. -+You also need to populate the database with the <> listed in the previous section (see the ACL samples for the appropriate SQL statements). -+ -+Once you have created the required schema and instantiated `JdbcMutableAclService`, you need to ensure your domain model supports interoperability with the Spring Security ACL package. -+Hopefully, `ObjectIdentityImpl` proves sufficient, as it provides a large number of ways in which it can be used. -+Most people have domain objects that contain a `public Serializable getId()` method. -+If the return type is `long` or compatible with `long` (such as an `int`), you may find that you need not give further consideration to `ObjectIdentity` issues. - Many parts of the ACL module rely on long identifiers. --If you're not using long (or an int, byte etc), there is a very good chance you'll need to reimplement a number of classes. --We do not intend to support non-long identifiers in Spring Security's ACL module, as longs are already compatible with all database sequences, the most common identifier data type, and are of sufficient length to accommodate all common usage scenarios. -+If you do not use `long` (or an `int`, `byte`, and so on), you probably need to reimplement a number of classes. -+We do not intend to support non-long identifiers in Spring Security's ACL module, as longs are already compatible with all database sequences, are the most common identifier data type, and are of sufficient length to accommodate all common usage scenarios. - --The following fragment of code shows how to create an `Acl`, or modify an existing `Acl`: -+The following fragment of code shows how to create an `Acl` or modify an existing `Acl`: - -+==== - [source,java] - ---- - // Prepare the information we'd like in our access control entry (ACE) -@@ -167,27 +160,25 @@ acl = aclService.createAcl(oi); - acl.insertAce(acl.getEntries().length, p, sid, true); - aclService.updateAcl(acl); - ---- -+==== - -- -- --In the example above, we're retrieving the ACL associated with the "Foo" domain object with identifier number 44. --We're then adding an ACE so that a principal named "Samantha" can "administer" the object. --The code fragment is relatively self-explanatory, except the insertAce method. --The first argument to the insertAce method is determining at what position in the Acl the new entry will be inserted. --In the example above, we're just putting the new ACE at the end of the existing ACEs. -+In the preceding example, we retrieve the ACL associated with the `Foo` domain object with identifier number 44. -+We then add an ACE so that a principal named "`Samantha`" can "`administer`" the object. -+The code fragment is relatively self-explanatory, except for the `insertAce` method. -+The first argument to the `insertAce` method determine position in the Acl at which the new entry is inserted. -+In the preceding example, we put the new ACE at the end of the existing ACEs. - The final argument is a Boolean indicating whether the ACE is granting or denying. --Most of the time it will be granting (true), but if it is denying (false), the permissions are effectively being blocked. -+Most of the time it grants (`true`). However, if it denies (`false`), the permissions are effectively being blocked. - --Spring Security does not provide any special integration to automatically create, update or delete ACLs as part of your DAO or repository operations. --Instead, you will need to write code like shown above for your individual domain objects. --It's worth considering using AOP on your services layer to automatically integrate the ACL information with your services layer operations. --We've found this quite an effective approach in the past. -+Spring Security does not provide any special integration to automatically create, update, or delete ACLs as part of your DAO or repository operations. -+Instead, you need to write code similar to that shown in the preceding example for your individual domain objects. -+You should consider using AOP on your services layer to automatically integrate the ACL information with your services layer operations. -+We have found this approach to be effective. - --Once you've used the above techniques to store some ACL information in the database, the next step is to actually use the ACL information as part of authorization decision logic. -+Once you have used the techniques described here to store some ACL information in the database, the next step is to actually use the ACL information as part of authorization decision logic. - You have a number of choices here. --You could write your own `AccessDecisionVoter` or `AfterInvocationProvider` that respectively fires before or after a method invocation. -+You could write your own `AccessDecisionVoter` or `AfterInvocationProvider` that (respectively) fires before or after a method invocation. - Such classes would use `AclService` to retrieve the relevant ACL and then call `Acl.isGranted(Permission[] permission, Sid[] sids, boolean administrativeMode)` to decide whether permission is granted or denied. --Alternately, you could use our `AclEntryVoter`, `AclEntryAfterInvocationProvider` or `AclEntryAfterInvocationCollectionFilteringProvider` classes. -+Alternately, you could use our `AclEntryVoter`, `AclEntryAfterInvocationProvider`, or `AclEntryAfterInvocationCollectionFilteringProvider` classes. - All of these classes provide a declarative-based approach to evaluating ACL information at runtime, freeing you from needing to write any code. --Please refer to the sample applications to learn how to use these classes. -- -+See the https://github.com/spring-projects/spring-security/tree/master/samples[sample applications] to learn how to use these classes. -diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authorization/architecture.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authorization/architecture.adoc -index 15de8dbf70..7d44250a39 100644 ---- a/docs/manual/src/docs/asciidoc/_includes/servlet/authorization/architecture.adoc -+++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authorization/architecture.adoc -@@ -1,41 +1,41 @@ - // from the original documentation -- - [[authz-arch]] - = Authorization Architecture - -+This section describes the Spring Security architecture that applies to authorization. - - [[authz-authorities]] - == Authorities --<>, discusses how all `Authentication` implementations store a list of `GrantedAuthority` objects. -+<> discusses how all `Authentication` implementations store a list of `GrantedAuthority` objects. - These represent the authorities that have been granted to the principal. --the `GrantedAuthority` objects are inserted into the `Authentication` object by the `AuthenticationManager` and are later read by `AccessDecisionManager` s when making authorization decisions. -+The `GrantedAuthority` objects are inserted into the `Authentication` object by the `AuthenticationManager` and are later read by `AccessDecisionManager` instances when making authorization decisions. - --`GrantedAuthority` is an interface with only one method: -+The `GrantedAuthority` interface has only one method: - -+==== - [source,java] - ---- -- - String getAuthority(); -- - ---- -+==== - --This method allows --`AccessDecisionManager` s to obtain a precise `String` representation of the `GrantedAuthority`. --By returning a representation as a `String`, a `GrantedAuthority` can be easily "read" by most `AccessDecisionManager` s. --If a `GrantedAuthority` cannot be precisely represented as a `String`, the `GrantedAuthority` is considered "complex" and `getAuthority()` must return `null`. -+This method lets an -+`AccessDecisionManager` instance to obtain a precise `String` representation of the `GrantedAuthority`. -+By returning a representation as a `String`, a `GrantedAuthority` can be easily "`read`" by most `AccessDecisionManager` implementations. -+If a `GrantedAuthority` cannot be precisely represented as a `String`, the `GrantedAuthority` is considered "`complex`" and `getAuthority()` must return `null`. - --An example of a "complex" `GrantedAuthority` would be an implementation that stores a list of operations and authority thresholds that apply to different customer account numbers. --Representing this complex `GrantedAuthority` as a `String` would be quite difficult, and as a result the `getAuthority()` method should return `null`. --This will indicate to any `AccessDecisionManager` that it will need to specifically support the `GrantedAuthority` implementation in order to understand its contents. -+An example of a "`complex`" `GrantedAuthority` would be an implementation that stores a list of operations and authority thresholds that apply to different customer account numbers. -+Representing this complex `GrantedAuthority` as a `String` would be quite difficult. As a result, the `getAuthority()` method should return `null`. -+This indicates to any `AccessDecisionManager` that it needs to support the specific `GrantedAuthority` implementation to understand its contents. - --Spring Security includes one concrete `GrantedAuthority` implementation, `SimpleGrantedAuthority`. --This allows any user-specified `String` to be converted into a `GrantedAuthority`. --All `AuthenticationProvider` s included with the security architecture use `SimpleGrantedAuthority` to populate the `Authentication` object. -+Spring Security includes one concrete `GrantedAuthority` implementation: `SimpleGrantedAuthority`. -+This implementation lets any user-specified `String` be converted into a `GrantedAuthority`. -+All `AuthenticationProvider` instances included with the security architecture use `SimpleGrantedAuthority` to populate the `Authentication` object. - - - [[authz-pre-invocation]] - == Pre-Invocation Handling --Spring Security provides interceptors which control access to secure objects such as method invocations or web requests. -+Spring Security provides interceptors that control access to secure objects, such as method invocations or web requests. - A pre-invocation decision on whether the invocation is allowed to proceed is made by the `AccessDecisionManager`. - - -@@ -44,6 +44,7 @@ A pre-invocation decision on whether the invocation is allowed to proceed is mad - The `AccessDecisionManager` is called by the `AbstractSecurityInterceptor` and is responsible for making final access control decisions. - The `AccessDecisionManager` interface contains three methods: - -+==== - [source,java] - ---- - void decide(Authentication authentication, Object secureObject, -@@ -53,32 +54,34 @@ boolean supports(ConfigAttribute attribute); - - boolean supports(Class clazz); - ---- -+==== - --The ``AccessDecisionManager``'s `decide` method is passed all the relevant information it needs in order to make an authorization decision. --In particular, passing the secure `Object` enables those arguments contained in the actual secure object invocation to be inspected. --For example, let's assume the secure object was a `MethodInvocation`. --It would be easy to query the `MethodInvocation` for any `Customer` argument, and then implement some sort of security logic in the `AccessDecisionManager` to ensure the principal is permitted to operate on that customer. -+The `decide` method of the `AccessDecisionManager` is passed all the relevant information it needs to make an authorization decision. -+In particular, passing the secure `Object` lets those arguments contained in the actual secure object invocation be inspected. -+For example, assume the secure object is a `MethodInvocation`. -+You can query the `MethodInvocation` for any `Customer` argument and then implement some sort of security logic in the `AccessDecisionManager` to ensure the principal is permitted to operate on that customer. - Implementations are expected to throw an `AccessDeniedException` if access is denied. - - The `supports(ConfigAttribute)` method is called by the `AbstractSecurityInterceptor` at startup time to determine if the `AccessDecisionManager` can process the passed `ConfigAttribute`. --The `supports(Class)` method is called by a security interceptor implementation to ensure the configured `AccessDecisionManager` supports the type of secure object that the security interceptor will present. -+The `supports(Class)` method is called by a security interceptor implementation to ensure the configured `AccessDecisionManager` supports the type of secure object that the security interceptor presents. - - [[authz-voting-based]] - === Voting-Based AccessDecisionManager Implementations --Whilst users can implement their own `AccessDecisionManager` to control all aspects of authorization, Spring Security includes several `AccessDecisionManager` implementations that are based on voting. --<> illustrates the relevant classes. -+While users can implement their own `AccessDecisionManager` to control all aspects of authorization, Spring Security includes several `AccessDecisionManager` implementations that are based on voting. -+<> describes the relevant classes. -+ -+The following image shows the `AccessDecisionManager` interface: - - [[authz-access-voting]] - .Voting Decision Manager - image::images/access-decision-voting.png[] - -- -- --Using this approach, a series of `AccessDecisionVoter` implementations are polled on an authorization decision. -+By using this approach, a series of `AccessDecisionVoter` implementations are polled on an authorization decision. - The `AccessDecisionManager` then decides whether or not to throw an `AccessDeniedException` based on its assessment of the votes. - - The `AccessDecisionVoter` interface has three methods: - -+==== - [source,java] - ---- - int vote(Authentication authentication, Object object, Collection attrs); -@@ -87,87 +90,88 @@ boolean supports(ConfigAttribute attribute); - - boolean supports(Class clazz); - ---- -+==== - --Concrete implementations return an `int`, with possible values being reflected in the `AccessDecisionVoter` static fields `ACCESS_ABSTAIN`, `ACCESS_DENIED` and `ACCESS_GRANTED`. --A voting implementation will return `ACCESS_ABSTAIN` if it has no opinion on an authorization decision. -+Concrete implementations return an `int`, with possible values being reflected in the `AccessDecisionVoter` static fields named `ACCESS_ABSTAIN`, `ACCESS_DENIED` and `ACCESS_GRANTED`. -+A voting implementation returns `ACCESS_ABSTAIN` if it has no opinion on an authorization decision. - If it does have an opinion, it must return either `ACCESS_DENIED` or `ACCESS_GRANTED`. - --There are three concrete `AccessDecisionManager` s provided with Spring Security that tally the votes. --The `ConsensusBased` implementation will grant or deny access based on the consensus of non-abstain votes. -+There are three concrete `AccessDecisionManager` implementations provided with Spring Security to tally the votes. -+The `ConsensusBased` implementation grants or denies access based on the consensus of non-abstain votes. - Properties are provided to control behavior in the event of an equality of votes or if all votes are abstain. --The `AffirmativeBased` implementation will grant access if one or more `ACCESS_GRANTED` votes were received (i.e. a deny vote will be ignored, provided there was at least one grant vote). -+The `AffirmativeBased` implementation grants access if one or more `ACCESS_GRANTED` votes were received (in other words, a deny vote will be ignored, provided there was at least one grant vote). - Like the `ConsensusBased` implementation, there is a parameter that controls the behavior if all voters abstain. - The `UnanimousBased` provider expects unanimous `ACCESS_GRANTED` votes in order to grant access, ignoring abstains. --It will deny access if there is any `ACCESS_DENIED` vote. --Like the other implementations, there is a parameter that controls the behaviour if all voters abstain. -+It denies access if there is any `ACCESS_DENIED` vote. -+Like the other implementations, there is a parameter that controls the behavior if all voters abstain. - --It is possible to implement a custom `AccessDecisionManager` that tallies votes differently. --For example, votes from a particular `AccessDecisionVoter` might receive additional weighting, whilst a deny vote from a particular voter may have a veto effect. -+You can implement a custom `AccessDecisionManager` that tallies votes differently. -+For example, votes from a particular `AccessDecisionVoter` might receive additional weighting, while a deny vote from a particular voter may have a veto effect. - - - [[authz-role-voter]] - ==== RoleVoter --The most commonly used `AccessDecisionVoter` provided with Spring Security is the simple `RoleVoter`, which treats configuration attributes as simple role names and votes to grant access if the user has been assigned that role. -+The most commonly used `AccessDecisionVoter` provided with Spring Security is the `RoleVoter`, which treats configuration attributes as role names and votes to grant access if the user has been assigned that role. - --It will vote if any `ConfigAttribute` begins with the prefix `ROLE_`. --It will vote to grant access if there is a `GrantedAuthority` which returns a `String` representation (via the `getAuthority()` method) exactly equal to one or more `ConfigAttributes` starting with the prefix `ROLE_`. --If there is no exact match of any `ConfigAttribute` starting with `ROLE_`, the `RoleVoter` will vote to deny access. --If no `ConfigAttribute` begins with `ROLE_`, the voter will abstain. -+It votes if any `ConfigAttribute` begins with the `ROLE_` prefix. -+It votes to grant access if there is a `GrantedAuthority` that returns a `String` representation (from the `getAuthority()` method) exactly equal to one or more `ConfigAttributes` that start with the `ROLE_` prefix. -+If there is no exact match of any `ConfigAttribute` starting with `ROLE_`, `RoleVoter` votes to deny access. -+If no `ConfigAttribute` begins with `ROLE_`, the voter abstains. - - - [[authz-authenticated-voter]] - ==== AuthenticatedVoter --Another voter which we've implicitly seen is the `AuthenticatedVoter`, which can be used to differentiate between anonymous, fully-authenticated and remember-me authenticated users. --Many sites allow certain limited access under remember-me authentication, but require a user to confirm their identity by logging in for full access. -- --When we've used the attribute `IS_AUTHENTICATED_ANONYMOUSLY` to grant anonymous access, this attribute was being processed by the `AuthenticatedVoter`. --See the Javadoc for this class for more information. -+Another voter which we have implicitly seen is the `AuthenticatedVoter`, which can be used to differentiate between anonymous, fully-authenticated, and remember-me authenticated users. -+Many sites allow certain limited access under remember-me authentication but require a user to confirm their identity by logging in for full access. - -+When we have used the `IS_AUTHENTICATED_ANONYMOUSLY` attribute to grant anonymous access, this attribute was being processed by the `AuthenticatedVoter`. -+For more information, see -+{security-api-url}org/springframework/security/access/vote/AuthenticatedVoter.html[`AuthenticatedVoter`]. - - [[authz-custom-voter]] - ==== Custom Voters --Obviously, you can also implement a custom `AccessDecisionVoter` and you can put just about any access-control logic you want in it. -+You can also implement a custom `AccessDecisionVoter` and put just about any access-control logic you want in it. - It might be specific to your application (business-logic related) or it might implement some security administration logic. --For example, you'll find a https://spring.io/blog/2009/01/03/spring-security-customization-part-2-adjusting-secured-session-in-real-time[blog article] on the Spring web site which describes how to use a voter to deny access in real-time to users whose accounts have been suspended. -+For example, on the Spring web site, you can find a https://spring.io/blog/2009/01/03/spring-security-customization-part-2-adjusting-secured-session-in-real-time[blog article] that describes how to use a voter to deny access in real-time to users whose accounts have been suspended. - - - [[authz-after-invocation-handling]] - == After Invocation Handling --Whilst the `AccessDecisionManager` is called by the `AbstractSecurityInterceptor` before proceeding with the secure object invocation, some applications need a way of modifying the object actually returned by the secure object invocation. --Whilst you could easily implement your own AOP concern to achieve this, Spring Security provides a convenient hook that has several concrete implementations that integrate with its ACL capabilities. -+While the `AccessDecisionManager` is called by the `AbstractSecurityInterceptor` before proceeding with the secure object invocation, some applications need a way to modify the object actually returned by the secure object invocation. -+While you could implement your own AOP concern to achieve this, Spring Security provides a convenient hook that has several concrete implementations that integrate with its ACL capabilities. - --<> illustrates Spring Security's `AfterInvocationManager` and its concrete implementations. -+<> describes Spring Security's `AfterInvocationManager` and its concrete implementations. -+The following image shows the `AfterInvocationManager`: - - [[authz-after-invocation]] - .After Invocation Implementation - image::images/after-invocation.png[] - --Like many other parts of Spring Security, `AfterInvocationManager` has a single concrete implementation, `AfterInvocationProviderManager`, which polls a list of `AfterInvocationProvider` s. -+Like many other parts of Spring Security, `AfterInvocationManager` has a single concrete implementation, `AfterInvocationProviderManager`, which polls a list of `AfterInvocationProvider` instances. - Each `AfterInvocationProvider` is allowed to modify the return object or throw an `AccessDeniedException`. --Indeed multiple providers can modify the object, as the result of the previous provider is passed to the next in the list. -+Indeed, multiple providers can modify the object, as the result of the previous provider is passed to the next in the list. - --Please be aware that if you're using `AfterInvocationManager`, you will still need configuration attributes that allow the ``MethodSecurityInterceptor``'s `AccessDecisionManager` to allow an operation. --If you're using the typical Spring Security included `AccessDecisionManager` implementations, having no configuration attributes defined for a particular secure method invocation will cause each `AccessDecisionVoter` to abstain from voting. --In turn, if the `AccessDecisionManager` property "`allowIfAllAbstainDecisions`" is `false`, an `AccessDeniedException` will be thrown. --You may avoid this potential issue by either (i) setting "`allowIfAllAbstainDecisions`" to `true` (although this is generally not recommended) or (ii) simply ensure that there is at least one configuration attribute that an `AccessDecisionVoter` will vote to grant access for. -+Note that, if you use `AfterInvocationManager`, you still need configuration attributes to let the `AccessDecisionManager` of the `MethodSecurityInterceptor` allow an operation. -+If you use the typical Spring Security `AccessDecisionManager` implementations, having no configuration attributes defined for a particular secure method invocation causes each `AccessDecisionVoter` to abstain from voting. -+In turn, if the `allowIfAllAbstainDecisions` property of `AccessDecisionManager` is `false`, an `AccessDeniedException` is thrown. -+You may avoid this potential issue by either (i) setting `allowIfAllAbstainDecisions` to `true` (although this is generally not recommended) or (ii) ensuring that there is at least one configuration attribute for which an `AccessDecisionVoter` votes to grant access. - This latter (recommended) approach is usually achieved through a `ROLE_USER` or `ROLE_AUTHENTICATED` configuration attribute. - - - [[authz-hierarchical-roles]] - == Hierarchical Roles --It is a common requirement that a particular role in an application should automatically "include" other roles. -+It is a common requirement that a particular role in an application should automatically "`include`" other roles. - For example, in an application which has the concept of an "admin" and a "user" role, you may want an admin to be able to do everything a normal user can. --To achieve this, you can either make sure that all admin users are also assigned the "user" role. --Alternatively, you can modify every access constraint which requires the "user" role to also include the "admin" role. --This can get quite complicated if you have a lot of different roles in your application. -+To achieve this, you can either make sure that all admin users are also assigned the "`user`" role or you can modify every access constraint which requires the "`user`" role to also include the "`admin`" role. -+This can get complicated if you have a lot of different roles in your application. - --The use of a role-hierarchy allows you to configure which roles (or authorities) should include others. --An extended version of Spring Security's <>, `RoleHierarchyVoter`, is configured with a `RoleHierarchy`, from which it obtains all the "reachable authorities" which the user is assigned. --A typical configuration might look like this: -+The use of a role-hierarchy lets you configure which roles (or authorities) should include others. -+An extended version of Spring Security's <>, `RoleHierarchyVoter`, is configured with a `RoleHierarchy`, from which it obtains all the "`reachable authorities`" that the user is assigned. -+The following example shows a typical configuration: - -+==== - [source,xml] - ---- -- - - - -@@ -182,10 +186,11 @@ A typical configuration might look like this: - - - ---- -+==== - --Here we have four roles in a hierarchy `ROLE_ADMIN => ROLE_STAFF => ROLE_USER => ROLE_GUEST`. --A user who is authenticated with `ROLE_ADMIN`, will behave as if they have all four roles when security constraints are evaluated against an `AccessDecisionManager` configured with the above `RoleHierarchyVoter`. --The `>` symbol can be thought of as meaning "includes". -+Here, we have four roles in a hierarchy `ROLE_ADMIN => ROLE_STAFF => ROLE_USER => ROLE_GUEST`. -+A user who is authenticated with `ROLE_ADMIN` behaves as if they have all four roles when security constraints are evaluated against an `AccessDecisionManager` configured with the preceding `RoleHierarchyVoter`. -+The `>` symbol can be thought of as meaning "`includes`". - --Role hierarchies offer a convenient means of simplifying the access-control configuration data for your application and/or reducing the number of authorities which you need to assign to a user. --For more complex requirements you may wish to define a logical mapping between the specific access-rights your application requires and the roles that are assigned to users, translating between the two when loading the user information. -+Role hierarchies offer a convenient means of simplifying the access-control configuration data for your application and reducing the number of authorities that you need to assign to a user. -+For more complex requirements, you may wish to define a logical mapping between the specific access-rights your application requires and the roles that are assigned to users, translating between the two when loading the user information. -diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authorization/authorize-requests.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authorization/authorize-requests.adoc -index 31ce88ecee..48ad3a3e15 100644 ---- a/docs/manual/src/docs/asciidoc/_includes/servlet/authorization/authorize-requests.adoc -+++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authorization/authorize-requests.adoc -@@ -3,27 +3,28 @@ - :figures: images/servlet/authorization - :icondir: images/icons - --This section builds on <> by digging deeper into how <> works within Servlet based applications. -+This section builds on <> by digging deeper into how <> works within Servlet-based applications. - --The {security-api-url}org/springframework/security/web/access/intercept/FilterSecurityInterceptor.html[`FilterSecurityInterceptor`] provides <> for ``HttpServletRequest``s. -+The {security-api-url}org/springframework/security/web/access/intercept/FilterSecurityInterceptor.html[`FilterSecurityInterceptor`] provides <> for `HttpServletRequest` instances. - It is inserted into the <> as one of the <>. - -+The following image shows the role of `FilterSecurityInterceptor`: -+ - .Authorize HttpServletRequest - image::{figures}/filtersecurityinterceptor.png[] - --* image:{icondir}/number_1.png[] First, the `FilterSecurityInterceptor` obtains an <> from the <>. --* image:{icondir}/number_2.png[] Second, `FilterSecurityInterceptor` creates a {security-api-url}org/springframework/security/web/FilterInvocation.html[`FilterInvocation`] from the `HttpServletRequest`, `HttpServletResponse`, and `FilterChain` that are passed into the `FilterSecurityInterceptor`. --// FIXME: link to FilterInvocation --* image:{icondir}/number_3.png[] Next, it passes the `FilterInvocation` to `SecurityMetadataSource` to get the ``ConfigAttribute``s. --* image:{icondir}/number_4.png[] Finally, it passes the `Authentication`, `FilterInvocation`, and ``ConfigAttribute``s to the `AccessDecisionManager`. --** image:{icondir}/number_5.png[] If authorization is denied, an `AccessDeniedException` is thrown. --In this case the <> handles the `AccessDeniedException`. --** image:{icondir}/number_6.png[] If access is granted, `FilterSecurityInterceptor` continues with the <> which allows the application to process normally. -+image:{icondir}/number_1.png[] The `FilterSecurityInterceptor` obtains an <> from the <>. -+image:{icondir}/number_2.png[] `FilterSecurityInterceptor` creates a {security-api-url}org/springframework/security/web/FilterInvocation.html[`FilterInvocation`] from the `HttpServletRequest`, `HttpServletResponse`, and `FilterChain` that are passed into the `FilterSecurityInterceptor`. -+image:{icondir}/number_3.png[] It passes the `FilterInvocation` to `SecurityMetadataSource` to get the ``ConfigAttribute``s. -+image:{icondir}/number_4.png[] It passes the `Authentication`, `FilterInvocation`, and ``ConfigAttribute``s to the `AccessDecisionManager`. -+image:{icondir}/number_5.png[] If authorization is denied, an `AccessDeniedException` is thrown. -+In this case, the <> handles the `AccessDeniedException`. -+image:{icondir}/number_6.png[] If access is granted, `FilterSecurityInterceptor` continues with the <>, which lets the application process normally. - - // configuration (xml/java) - --By default, Spring Security's authorization will require all requests to be authenticated. --The explicit configuration looks like: -+By default, Spring Security's authorization requires all requests to be authenticated. -+The following listing shows the explicit configuration: - - .Every Request Must be Authenticated - ==== -@@ -62,7 +63,7 @@ fun configure(http: HttpSecurity) { - ---- - ==== - --We can configure Spring Security to have different rules by adding more rules in order of precedence. -+We can configure Spring Security to have different rules by adding more rules in order of precedence: - - .Authorize Requests - ==== -@@ -115,13 +116,13 @@ fun configure(http: HttpSecurity) { - } - ---- - ==== --<1> There are multiple authorization rules specified. --Each rule is considered in the order they were declared. --<2> We specified multiple URL patterns that any user can access. --Specifically, any user can access a request if the URL starts with "/resources/", equals "/signup", or equals "/about". --<3> Any URL that starts with "/admin/" will be restricted to users who have the role "ROLE_ADMIN". --You will notice that since we are invoking the `hasRole` method we do not need to specify the "ROLE_" prefix. --<4> Any URL that starts with "/db/" requires the user to have both "ROLE_ADMIN" and "ROLE_DBA". --You will notice that since we are using the `hasRole` expression we do not need to specify the "ROLE_" prefix. --<5> Any URL that has not already been matched on is denied access. -+<1> Multiple authorization rules are specified. -+Each rule is considered in the order in which it is declared. -+<2> Specify multiple URL patterns that any user can access. -+Specifically, any user can access a request if the URL starts with `/resources/`, equals `/signup`, or equals `/about`. -+<3> Any URL that starts with `/admin/` is restricted to users who have the `ROLE_ADMIN` role. -+Notice that, since we invoke the `hasRole` method, we need not specify the `ROLE_` prefix. -+<4> Any URL that starts with `/db/` requires the user to have both `ROLE_ADMIN` and `ROLE_DBA`. -+Notice that, since we use the `hasRole` expression, we need not specify the `ROLE_` prefix. -+<5> Any URL that has not already been matched is denied access. - This is a good strategy if you do not want to accidentally forget to update your authorization rules. -diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authorization/expression-based.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authorization/expression-based.adoc -index 76d5f0ae5a..a9f15822f6 100644 ---- a/docs/manual/src/docs/asciidoc/_includes/servlet/authorization/expression-based.adoc -+++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authorization/expression-based.adoc -@@ -1,20 +1,20 @@ - - [[el-access]] - == 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 seen before. --Expression-based access control is built on the same architecture but allows complicated Boolean logic to be encapsulated in a single expression. -+Spring Security 3.0 introduced the ability to use Spring Expression Language (SpEL) expressions as an authorization mechanism in addition to the existing configuration attributes and access-decision voters. -+Expression-based access control is built on the same architecture but lets complicated Boolean logic be encapsulated in a single expression. - - - === 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. -+Spring Security uses SpEL 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 to provide built-in expressions and access to values, such as the current principal. - - - [[el-common-built-in]] - ==== 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. -+This provides some common expressions that are available in both web and method security: - - [[common-expressions]] - .Common built-in expressions -@@ -24,95 +24,94 @@ This provides some common expressions which are available in both web and method - | `hasRole(String role)` - | Returns `true` if the current principal has the specified role. - --For example, `hasRole('admin')` -+Example: `hasRole('admin')` - --By default if the supplied role does not start with 'ROLE_' it will be added. --This can be customized by modifying the `defaultRolePrefix` on `DefaultWebSecurityExpressionHandler`. -+By default, if the supplied role does not start with `ROLE_`, it is added. -+You can customize this behavior by modifying the `defaultRolePrefix` on `DefaultWebSecurityExpressionHandler`. - - | `hasAnyRole(String... roles)` - | Returns `true` if the current principal has any of the supplied roles (given as a comma-separated list of strings). - --For example, `hasAnyRole('admin', 'user')` -+Example: `hasAnyRole('admin', 'user')`. - --By default if the supplied role does not start with 'ROLE_' it will be added. --This can be customized by modifying the `defaultRolePrefix` on `DefaultWebSecurityExpressionHandler`. -+By default, if the supplied role does not start with `ROLE_`, it is added. -+You can customize this behavior by modifying the `defaultRolePrefix` on `DefaultWebSecurityExpressionHandler`. - - | `hasAuthority(String authority)` - | Returns `true` if the current principal has the specified authority. - --For example, `hasAuthority('read')` -+Example: `hasAuthority('read')` - - | `hasAnyAuthority(String... authorities)` --| Returns `true` if the current principal has any of the supplied authorities (given as a comma-separated list of strings) -+| Returns `true` if the current principal has any of the supplied authorities (given as a comma-separated list of strings). - --For example, `hasAnyAuthority('read', 'write')` -+Example: `hasAnyAuthority('read', 'write')`. - - | `principal` --| Allows direct access to the principal object representing the current user -+| Allows direct access to the principal object that represents the current user. - - | `authentication` --| Allows direct access to the current `Authentication` object obtained from the `SecurityContext` -+| Allows direct access to the current `Authentication` object obtained from the `SecurityContext`. - - | `permitAll` --| Always evaluates to `true` -+| Always evaluates to `true`. - - | `denyAll` --| Always evaluates to `false` -+| Always evaluates to `false`. - - | `isAnonymous()` --| Returns `true` if the current principal is an anonymous user -+| Returns `true` if the current principal is an anonymous user. - - | `isRememberMe()` --| Returns `true` if the current principal is a remember-me user -+| Returns `true` if the current principal is a remember-me user. - - | `isAuthenticated()` --| Returns `true` if the user is not anonymous -+| Returns `true` if the user is not anonymous. - - | `isFullyAuthenticated()` --| Returns `true` if the user is not an anonymous or a remember-me user -+| Returns `true` if the user is not an anonymous and is not a remember-me user. - - | `hasPermission(Object target, Object permission)` - | Returns `true` if the user has access to the provided target for the given permission. --For example, `hasPermission(domainObject, 'read')` -+Example, `hasPermission(domainObject, 'read')`. - - | `hasPermission(Object targetId, String targetType, Object permission)` - | Returns `true` if the user has access to the provided target for the given permission. --For example, `hasPermission(1, 'com.example.domain.Message', 'read')` -+Example, `hasPermission(1, 'com.example.domain.Message', 'read')`. - |=== - - -- - [[el-access-web]] - === Web Security Expressions --To use expressions to secure individual URLs, you would first need to set the `use-expressions` attribute in the `` element to `true`. --Spring Security will then expect the `access` attributes of the `` elements to contain Spring EL expressions. --The expressions should evaluate to a Boolean, defining whether access should be allowed or not. --For example: -+To use expressions to secure individual URLs, you first need to set the `use-expressions` attribute in the `` element to `true`. -+Spring Security then expects the `access` attributes of the `` elements to contain SpEL expressions. -+Each expression should evaluate to a Boolean, defining whether access should be allowed or not. -+The following listing shows an example: - -+==== - [source,xml] - ---- -- - - - ... - -- - ---- -+==== - --Here we have defined that the "admin" area of an application (defined by the URL pattern) should only be available to users who have the granted authority "admin" and whose IP address matches a local subnet. --We've already seen the built-in `hasRole` expression in the previous section. --The expression `hasIpAddress` is an additional built-in expression which is specific to web security. -+Here, we have defined that the `admin` area of an application (defined by the URL pattern) should be available only to users who have the granted authority (`admin`) and whose IP address matches a local subnet. -+We have already seen the built-in `hasRole` expression in the previous section. -+The `hasIpAddress` expression is an additional built-in expression that is specific to web security. - It is defined by the `WebSecurityExpressionRoot` class, an instance of which is used as the expression root object when evaluating web-access expressions. --This object also directly exposed the `HttpServletRequest` object under the name `request` so you can invoke the request directly in an expression. --If expressions are being used, a `WebExpressionVoter` will be added to the `AccessDecisionManager` which is used by the namespace. --So if you aren't using the namespace and want to use expressions, you will have to add one of these to your configuration. -+This object also directly exposed the `HttpServletRequest` object under the name `request` so that you can invoke the request directly in an expression. -+If expressions are being used, a `WebExpressionVoter` is added to the `AccessDecisionManager` that is used by the namespace. -+So, if you do not use the namespace and want to use expressions, you have to add one of these to your configuration. - - [[el-access-web-beans]] - ==== 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: -+For example, you could use the following, assuming you have a Bean with the name of `webSecurity` that contains the following method signature: - - ==== - .Java -@@ -136,7 +135,7 @@ class WebSecurity { - ---- - ==== - --You could refer to the method using: -+You could then refer to the method as follows: - - .Refer to method - ==== -@@ -174,11 +173,11 @@ http { - [[el-access-web-path-variables]] - ==== 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}+`. -+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 a URL path in a format of `+/user/{userId}+`. - - You can easily refer to the path variable by placing it in the pattern. --For example, if you had a Bean with the name of `webSecurity` that contains the following method signature: -+For example, you could use the following if you had a Bean with the name of `webSecurity` that contains the following method signature: - - ==== - .Java -@@ -202,7 +201,7 @@ class WebSecurity { - ---- - ==== - --You could refer to the method using: -+You could then refer to the method as follows: - - .Path Variables - ==== -@@ -237,28 +236,30 @@ 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`. -+In this configuration, URLs that match would pass in the path variable (and convert it) into the `checkUserId` method. -+For example, if the URL were `/user/123/resource`, the ID passed in would be `123`. - - === 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. -+Spring Security 3.0 introduced some new annotations to allow comprehensive support for the use of expressions. - - - [[el-pre-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`. -+There are four annotations that 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: - -+==== - [source,xml] - ---- - - ---- -+==== - - ===== 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 "Contacts" sample application) -+The most obviously useful annotation is `@PreAuthorize`, which decides whether a method can actually be invoked or not. -+The following example (from the "Contacts" sample application) uses the `@PreAuthorize` annotation: - - ==== - .Java -@@ -276,9 +277,9 @@ fun create(contact: Contact?) - ---- - ==== - --which means that access will only be allowed for users with the role "ROLE_USER". --Obviously the same thing could easily be achieved using a traditional configuration and a simple configuration attribute for the required role. --But what about: -+This means that access is allowed only for users with the `ROLE_USER` role. -+Obviously, the same thing could easily be achieved by using a traditional configuration and a simple configuration attribute for the required role. -+However, consider the following example: - - ==== - .Java -@@ -296,20 +297,18 @@ fun deletePermission(contact: Contact?, recipient: Sid?, permission: Permission? - ---- - ==== - --Here we're actually using a method argument as part of the expression to decide whether the current user has the "admin"permission for the given contact. --The built-in `hasPermission()` expression is linked into the Spring Security ACL module through the application context, as we'll <>. -+Here, we actually use a method argument as part of the expression to decide whether the current user has the `admin` permission for the given contact. -+The built-in `hasPermission()` expression is linked into the Spring Security ACL module through the application context, as we <>. - You can access any of the method arguments by name as expression variables. - --There are a number of ways in which Spring Security can resolve the method arguments. -+Spring Security can resolve the method arguments in a number of ways. - Spring Security uses `DefaultSecurityParameterNameDiscoverer` to discover the parameter names. --By default, the following options are tried for a method as a whole. -- --* If Spring Security's `@P` annotation is present on a single argument to the method, the value will be used. --This is useful for interfaces compiled with a JDK prior to JDK 8 which do not contain any information about the parameter names. --For example: -+By default, the following options are tried for a method. - -+* If Spring Security's `@P` annotation is present on a single argument to the method, the value is used. -+This is useful for interfaces compiled with a JDK prior to JDK 8 (which do not contain any information about the parameter names). -+The following example uses the `@P` annotation: - + -- - ==== - .Java - [source,java,role="primary"] -@@ -333,17 +332,13 @@ import org.springframework.security.access.method.P - fun doSomething(@P("c") contact: Contact?) - ---- - ==== -- - + -+Behind the scenes, this is implemented by using `AnnotationParameterNameDiscoverer`, which you can customize to support the value attribute of any specified annotation. - --Behind the scenes this is implemented using `AnnotationParameterNameDiscoverer` which can be customized to support the value attribute of any specified annotation. -- --* If Spring Data's `@Param` annotation is present on at least one parameter for the method, the value will be used. -+* If Spring Data's `@Param` annotation is present on at least one parameter for the method, the value is used. - This is useful for interfaces compiled with a JDK prior to JDK 8 which do not contain any information about the parameter names. --For example: -- -+The following example uses the `@Param` annotation: - + -- - ==== - .Java - [source,java,role="primary"] -@@ -367,23 +362,19 @@ import org.springframework.data.repository.query.Param - fun findContactByName(@Param("n") name: String?): Contact? - ---- - ==== -- - + -+Behind the scenes, this is implemented by using `AnnotationParameterNameDiscoverer`, which you can customize to support the value attribute of any specified annotation. - --Behind the scenes this is implemented using `AnnotationParameterNameDiscoverer` which can be customized to support the value attribute of any specified annotation. -- --* If JDK 8 was used to compile the source with the -parameters argument and Spring 4+ is being used, then the standard JDK reflection API is used to discover the parameter names. -+* If JDK 8 was used to compile the source with the `-parameters` argument and Spring 4+ is being used, the standard JDK reflection API is used to discover the parameter names. - This works on both classes and interfaces. - --* Last, if the code was compiled with the debug symbols, the parameter names will be discovered using the debug symbols. --This will not work for interfaces since they do not have debug information about the parameter names. -+* Finally, if the code was compiled with the debug symbols, the parameter names are discovered by using the debug symbols. -+This does not work for interfaces, since they do not have debug information about the parameter names. - For interfaces, annotations or the JDK 8 approach must be used. - - .[[el-pre-post-annotations-spel]] ---- --Any Spring-EL functionality is available within the expression, so you can also access properties on the arguments. --For example, if you wanted a particular method to only allow access to a user whose username matched that of the contact, you could write ---- -+Any SpEL functionality is available within the expression, so you can also access properties on the arguments. -+For example, if you wanted a particular method to allow access only to a user whose username matched that of the contact, you could write - - ==== - .Java -@@ -401,21 +392,19 @@ fun doSomething(contact: Contact?) - ---- - ==== - --Here we are accessing another built-in expression, `authentication`, which is the `Authentication` stored in the security context. --You can also access its "principal" property directly, using the expression `principal`. --The value will often be a `UserDetails` instance, so you might use an expression like `principal.username` or `principal.enabled`. -+Here, we access another built-in expression, `authentication`, which is the `Authentication` stored in the security context. -+You can also access its `principal` property directly, by using the `principal` expression. -+The value is often a `UserDetails` instance, so you might use an expression such as `principal.username` or `principal.enabled`. - - .[[el-pre-post-annotations-post]] ---- - Less commonly, you may wish to perform an access-control check after the method has been invoked. --This can be achieved using the `@PostAuthorize` annotation. -+You can do so by 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 --Spring Security supports filtering of collections, arrays, maps and streams using expressions. -+Spring Security supports filtering of collections, arrays, maps, and streams by using expressions. - This is most commonly performed on the return value of a method. --For example: -+The following example uses `@PostFilter`: - - ==== - .Java -@@ -436,29 +425,30 @@ fun getAll(): List - ==== - - When using the `@PostFilter` annotation, Spring Security iterates through the returned collection or map and removes any elements for which the supplied expression is false. --For an array, a new array instance will be returned containing filtered elements. --The name `filterObject` refers to the current object in the collection. --In case when a map is used it will refer to the current `Map.Entry` object which allows one to use `filterObject.key` or `filterObject.value` in the expresion. --You can also filter before the method call, using `@PreFilter`, though this is a less common requirement. --The syntax is just the same, but if there is more than one argument which is a collection type then you have to select one by name using the `filterTarget` property of this annotation. -+For an array, a new array instance that contains filtered elements is returned. -+`filterObject` refers to the current object in the collection. -+When a map is used, it refers to the current `Map.Entry` object, which lets you use `filterObject.key` or `filterObject.value` in the expression. -+You can also filter before the method call by using `@PreFilter`, though this is a less common requirement. -+The syntax is the same. However, if there is more than one argument that is a collection type, you have to select one by name using the `filterTarget` property of this annotation. - - Note that filtering is obviously not a substitute for tuning your data retrieval queries. --If you are filtering large collections and removing many of the entries then this is likely to be inefficient. -+If you are filtering large collections and removing many of the entries, this is likely to be inefficient. - - - [[el-method-built-in]] - ==== Built-In Expressions --There are some built-in expressions which are specific to method security, which we have already seen in use above. -+There are some built-in expressions that are specific to method security, which we have already seen in use earlier. - 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 - `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 is intended to bridge between the expression system and Spring Security's ACL system, letting you 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. - The interface has two methods: - -+==== - [source,java] - ---- - boolean hasPermission(Authentication authentication, Object targetDomainObject, -@@ -467,17 +457,19 @@ boolean hasPermission(Authentication authentication, Object targetDomainObject, - boolean hasPermission(Authentication authentication, Serializable targetId, - String targetType, Object permission); - ---- -+==== - --which map directly to the available versions of the expression, with the exception that the first argument (the `Authentication` object) is not supplied. -+These methods map directly to the available versions of the expression, with the exception that the first argument (the `Authentication` object) is not supplied. - The first is used in situations where the domain object, to which access is being controlled, is already loaded. --Then expression will return true if the current user has the given permission for that object. --The second version is used in cases where the object is not loaded, but its identifier is known. --An abstract "type" specifier for the domain object is also required, allowing the correct ACL permissions to be loaded. --This has traditionally been the Java class of the object, but does not have to be as long as it is consistent with how the permissions are loaded. -+Then the expression returns `true` if the current user has the given permission for that object. -+The second version is used in cases where the object is not loaded but its identifier is known. -+An abstract "`type`" specifier for the domain object is also required, letting the correct ACL permissions be loaded. -+This has traditionally been the Java class of the object but does not have to be, as long as it is consistent with how the permissions are loaded. - - To use `hasPermission()` expressions, you have to explicitly configure a `PermissionEvaluator` in your application context. --This would look something like this: -+The following example shows how to do so: - -+==== - [source,xml] - ---- - -@@ -489,23 +481,26 @@ This would look something like this: - - - ---- -+==== - - Where `myPermissionEvaluator` is the bean which implements `PermissionEvaluator`. --Usually this will be the implementation from the ACL module which is called `AclPermissionEvaluator`. --See the "Contacts" sample application configuration for more details. -+Usually, this is the implementation from the ACL module, which is called `AclPermissionEvaluator`. -+See the "`Contacts`" sample application configuration for more details. - - ===== 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. -+This is especially convenient if you find that you repeat the same complex expression throughout your code base. - For example, consider the following: - -+==== - [source,java] - ---- - @PreAuthorize("#contact.name == authentication.name") - ---- -+==== - --Instead of repeating this everywhere, we can create a meta annotation that can be used instead. -+Instead of repeating this everywhere, you can create a meta annotation: - - ==== - .Java -@@ -525,6 +520,5 @@ annotation class ContactPermission - ---- - ==== - --Meta annotations can be used for any of the Spring Security method security annotations. --In order to remain compliant with the specification JSR-250 annotations do not support meta annotations. -- -+You can use meta annotations for any of the Spring Security method security annotations. -+To remain compliant with the specification, JSR-250 annotations do not support meta annotations. -diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authorization/index.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authorization/index.adoc -index 2e4dfc59ac..d16b22ca15 100644 ---- a/docs/manual/src/docs/asciidoc/_includes/servlet/authorization/index.adoc -+++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authorization/index.adoc -@@ -1,10 +1,10 @@ - [[servlet-authorization]] - = Authorization - The advanced authorization capabilities within Spring Security represent one of the most compelling reasons for its popularity. --Irrespective of how you choose to authenticate - whether using a Spring Security-provided mechanism and provider, or integrating with a container or other non-Spring Security authentication authority - you will find the authorization services can be used within your application in a consistent and simple way. -+Irrespective of how you choose to authenticate (whether using a Spring Security-provided mechanism and provider or integrating with a container or other non-Spring Security authentication authority), the authorization services can be used within your application in a consistent and simple way. - --In this part we'll explore the different `AbstractSecurityInterceptor` implementations, which were introduced in Part I. --We then move on to explore how to fine-tune authorization through use of domain access control lists. -+In this part, we explore the different `AbstractSecurityInterceptor` implementations, which were introduced in Part I. -+We then move on to explore how to fine-tune authorization through the use of domain access control lists. - - include::architecture.adoc[leveloffset=+1] - -@@ -17,4 +17,3 @@ include::secure-objects.adoc[] - include::method-security.adoc[] - - include::acls.adoc[] -- -diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authorization/method-security.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authorization/method-security.adoc -index 573412f6bf..30a4ccc234 100644 ---- a/docs/manual/src/docs/asciidoc/_includes/servlet/authorization/method-security.adoc -+++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authorization/method-security.adoc -@@ -1,16 +1,17 @@ - [[jc-method]] - == Method Security - --From version 2.0 onwards Spring Security has improved support substantially for adding security to your service layer methods. -+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 <>. --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. -+From 3.0, you can also make use of new <>. -+You can apply security to a single bean, by using the `intercept-methods` element to decorate the bean declaration, or you can secure multiple beans across the entire service layer by using AspectJ style pointcuts. - - === 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. -+We can enable annotation-based security by using the `@EnableGlobalMethodSecurity` annotation on any `@Configuration` instance. -+The following example enables Spring Security's `@Secured` annotation: - -+==== - [source,java] - ---- - @EnableGlobalMethodSecurity(securedEnabled = true) -@@ -18,11 +19,13 @@ public class MethodSecurityConfig { - // ... - } - ---- -+==== - - Adding an annotation to a method (on a class or interface) would then limit the access to that method accordingly. - Spring Security's native annotation support defines a set of attributes for the method. --These will be passed to the AccessDecisionManager for it to make the actual decision: -+These are passed to the `AccessDecisionManager` for it to make the actual decision: - -+==== - [source,java] - ---- - public interface BankService { -@@ -37,9 +40,11 @@ public Account[] findAccounts(); - public Account post(Account account, double amount); - } - ---- -+==== - --Support for JSR-250 annotations can be enabled using -+Support for JSR-250 annotations can be enabled by using: - -+==== - [source,java] - ---- - @EnableGlobalMethodSecurity(jsr250Enabled = true) -@@ -47,10 +52,12 @@ public class MethodSecurityConfig { - // ... - } - ---- -+==== - --These are standards-based and allow simple role-based constraints to be applied but do not have the power Spring Security's native annotations. --To use the new expression-based syntax, you would use -+These are standards-based and let simple role-based constraints be applied but do not have the power Spring Security's native annotations. -+To use the new expression-based syntax, you would use: - -+==== - [source,java] - ---- - @EnableGlobalMethodSecurity(prePostEnabled = true) -@@ -58,9 +65,11 @@ public class MethodSecurityConfig { - // ... - } - ---- -+==== - --and the equivalent Java code would be -+The equivalent Java code is: - -+==== - [source,java] - ---- - public interface BankService { -@@ -75,13 +84,15 @@ public Account[] findAccounts(); - public Account post(Account account, double amount); - } - ---- -+==== - - === 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. -+Sometimes, you may need to perform operations that are more complicated than are possible with the `@EnableGlobalMethodSecurity` annotation. -+For these instances, you can extend the `GlobalMethodSecurityConfiguration`, ensuring that the `@EnableGlobalMethodSecurity` annotation is present on your subclass. - For example, if you wanted to provide a custom `MethodSecurityExpressionHandler`, you could use the following configuration: - -+==== - [source,java] - ---- - @EnableGlobalMethodSecurity(prePostEnabled = true) -@@ -93,24 +104,29 @@ public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration { - } - } - ---- -+==== - --For additional information about methods that can be overridden, refer to the `GlobalMethodSecurityConfiguration` Javadoc. -+For additional information about methods that can be overridden, see the Javadoc for the {security-api-url}org/springframework/security/config/annotation/method/configuration/GlobalMethodSecurityConfiguration.html[`GlobalMethodSecurityConfiguration`] class. - - [[ns-global-method]] - === The 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. -+This element is used to enable annotation-based security in your application (by setting the appropriate attributes on the element) and to group together security pointcut declarations that are applied across your entire application context. - You should only declare one `` element. --The following declaration would enable support for Spring Security's `@Secured`: -+The following declaration enables support for Spring Security's `@Secured`: - -+==== - [source,xml] - ---- - - ---- -+==== - --Adding an annotation to a method (on an class or interface) would then limit the access to that method accordingly. -+Adding an annotation to a method (on a class or interface) would then limit the access to that method accordingly. - Spring Security's native annotation support defines a set of attributes for the method. --These will be passed to the `AccessDecisionManager` for it to make the actual decision: -+These are passed to the `AccessDecisionManager` for it to make the actual decision. -+The following example shows the `@Secured` annotation in a typical interface: - -+==== - [source,java] - ---- - public interface BankService { -@@ -125,24 +141,30 @@ public Account[] findAccounts(); - public Account post(Account account, double amount); - } - ---- -+==== - --Support for JSR-250 annotations can be enabled using -+Support for JSR-250 annotations can be enabled by using: - -+==== - [source,xml] - ---- - - ---- -+==== - --These are standards-based and allow simple role-based constraints to be applied but do not have the power Spring Security's native annotations. --To use the new expression-based syntax, you would use -+These are standards-based and allow simple role-based constraints to be applied, but they do not have the power Spring Security's native annotations. -+To use the expression-based syntax, use: - -+==== - [source,xml] - ---- - - ---- -+==== - --and the equivalent Java code would be -+The equivalent Java code is: - -+==== - [source,java] - ---- - public interface BankService { -@@ -157,27 +179,23 @@ public Account[] findAccounts(); - public Account post(Account account, double amount); - } - ---- -+==== - - Expression-based annotations are a good choice if you need to define simple rules that go beyond checking the role names against the user's list of authorities. - --[NOTE] --==== --The annotated methods will only be secured for instances which are defined as Spring beans (in the same application context in which method-security is enabled). -+NOTE: The annotated methods will only be secured for instances which are defined as Spring beans (in the same application context in which method-security is enabled). - If you want to secure instances which are not created by Spring (using the `new` operator, for example) then you need to use AspectJ. --==== - --[NOTE] --==== --You can enable more than one type of annotation in the same application, but only one type should be used for any interface or class as the behaviour will not be well-defined otherwise. -+NOTE: You can enable more than one type of annotation in the same application, but only one type should be used for any interface or class as the behaviour will not be well-defined otherwise. - If two annotations are found which apply to a particular method, then only one of them will be applied. --==== - - [[ns-protect-pointcut]] --=== Adding Security Pointcuts using protect-pointcut -+=== Adding Security Pointcuts by 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. -+`protect-pointcut` is particularly powerful, as it lets you apply security to many beans with only a simple declaration. - Consider the following example: - -+==== - [source,xml] - ---- - -@@ -185,8 +203,9 @@ Consider the following example: - access="ROLE_USER"/> - - ---- -+==== - --This will protect all methods on beans declared in the application context whose classes are in the `com.mycompany` package and whose class names end in "Service". --Only users with the `ROLE_USER` role will be able to invoke these methods. --As with URL matching, the most specific matches must come first in the list of pointcuts, as the first matching expression will be used. -+This configuration protects all methods on beans declared in the application context whose classes are in the `com.mycompany` package and whose class names end in `Service`. -+Only users with the `ROLE_USER` role can invoke these methods. -+As with URL matching, the most specific matches must come first in the list of pointcuts, as the first matching expression is used. - Security annotations take precedence over pointcuts. -diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authorization/secure-objects.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authorization/secure-objects.adoc -index 7370a4202c..ebc9008e44 100644 ---- a/docs/manual/src/docs/asciidoc/_includes/servlet/authorization/secure-objects.adoc -+++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authorization/secure-objects.adoc -@@ -2,25 +2,27 @@ - [[secure-object-impls]] - == Secure Object Implementations - -+This section covers how Spring Security handles Secure Object implementations. -+ - [[aop-alliance]] - === AOP Alliance (MethodInvocation) Security Interceptor --Prior to Spring Security 2.0, securing `MethodInvocation` s needed quite a lot of boiler plate configuration. -+Prior to Spring Security 2.0, securing `MethodInvocation` instances needed a lot of boiler plate configuration. - Now the recommended approach for method security is to use <>. --This way the method security infrastructure beans are configured automatically for you so you don't really need to know about the implementation classes. --We'll just provide a quick overview of the classes that are involved here. -+This way, the method security infrastructure beans are configured automatically for you, so you need not know about the implementation classes. -+We provide only a quick overview of the classes that are involved here. - --Method security is enforced using a `MethodSecurityInterceptor`, which secures `MethodInvocation` s. -+Method security is enforced by using a `MethodSecurityInterceptor`, which secures `MethodInvocation` instances. - Depending on the configuration approach, an interceptor may be specific to a single bean or shared between multiple beans. - The interceptor uses a `MethodSecurityMetadataSource` instance to obtain the configuration attributes that apply to a particular method invocation. --`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 `` or `` elements. --Other implementations will be used to handle annotation-based configuration. -+`MapBasedMethodSecurityMetadataSource` is used to store configuration attributes keyed by method names (which can be wildcarded) and is used internally when the attributes are defined in the application context by using the `` or `` elements. -+Other implementations are used to handle annotation-based 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: -+You can configure a `MethodSecurityInterceptor` directly in your application context for use with one of Spring AOP's proxying mechanisms: - -+==== - [source,xml] - ---- -- - - -@@ -34,22 +36,22 @@ You can of course configure a `MethodSecurityInterceptor` directly in your appli - - - ---- -+==== - - [[aspectj]] - === 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. -+We discuss only the differences in this section. - - The AspectJ interceptor is named `AspectJSecurityInterceptor`. --Unlike the AOP Alliance security interceptor, which relies on the Spring application context to weave in the security interceptor via proxying, the `AspectJSecurityInterceptor` is weaved in via the AspectJ compiler. -+Unlike the AOP Alliance security interceptor, which relies on the Spring application context to weave in the security interceptor through proxying, the `AspectJSecurityInterceptor` is woven in through the AspectJ compiler. - It would not be uncommon to use both types of security interceptors in the same application, with `AspectJSecurityInterceptor` being used for domain object instance security and the AOP Alliance `MethodSecurityInterceptor` being used for services layer security. - --Let's first consider how the `AspectJSecurityInterceptor` is configured in the Spring application context: -- -+We first consider how the `AspectJSecurityInterceptor` is configured in the Spring application context: - -+==== - [source,xml] - ---- -- - - -@@ -63,19 +65,17 @@ Let's first consider how the `AspectJSecurityInterceptor` is configured in the S - - - ---- -- -+==== - - As you can see, aside from the class name, the `AspectJSecurityInterceptor` is exactly the same as the AOP Alliance security interceptor. --Indeed the two interceptors can share the same `securityMetadataSource`, as the `SecurityMetadataSource` works with `java.lang.reflect.Method` s rather than an AOP library-specific class. --Of course, your access decisions have access to the relevant AOP library-specific invocation (ie `MethodInvocation` or `JoinPoint`) and as such can consider a range of addition criteria when making access decisions (such as method arguments). -- --Next you'll need to define an AspectJ `aspect`. --For example: -+The two interceptors can share the same `securityMetadataSource`, as the `SecurityMetadataSource` works with `java.lang.reflect.Method` instances rather than an AOP library-specific class. -+Your access decisions have access to the relevant AOP library-specific invocation (`MethodInvocation` or `JoinPoint`) and can consider a range of additional criteria (such as method arguments) when making access decisions. - -+Next, you need to define an AspectJ `aspect`, as the following example shows: - -+==== - [source,java] - ---- -- - package org.springframework.security.samples.aspectj; - - import org.springframework.security.access.intercept.aspectj.AspectJSecurityInterceptor; -@@ -118,16 +118,16 @@ public aspect DomainObjectInstanceSecurityAspect implements InitializingBean { - } - } - ---- -+==== - -- --In the above example, the security interceptor will be applied to every instance of `PersistableEntity`, which is an abstract class not shown (you can use any other class or `pointcut` expression you like). -+In the preceding example, the security interceptor is applied to every instance of `PersistableEntity`, which is an abstract class not shown (you can use any other class or `pointcut` expression you like). - For those curious, `AspectJCallback` is needed because the `proceed();` statement has special meaning only within an `around()` body. - The `AspectJSecurityInterceptor` calls this anonymous `AspectJCallback` class when it wants the target object to continue. - --You will need to configure Spring to load the aspect and wire it with the `AspectJSecurityInterceptor`. --A bean declaration which achieves this is shown below: -- -+You need to configure Spring to load the aspect and wire it with the `AspectJSecurityInterceptor`. -+The following example shows a bean declaration that achieves this: - -+==== - [source,xml] - ---- - -@@ -137,7 +137,6 @@ A bean declaration which achieves this is shown below: - - - ---- -+==== - -- --That's it! --Now you can create your beans from anywhere within your application, using whatever means you think fit (e.g. `new Person();`) and they will have the security interceptor applied. -+Now you can create your beans from anywhere within your application, using whatever means you think fit (e.g. `new Person();`), and they have the security interceptor applied. -diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/crypto/index.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/crypto/index.adoc -index 137b3e8b69..e5cd9f81e5 100644 ---- a/docs/manual/src/docs/asciidoc/_includes/servlet/crypto/index.adoc -+++ b/docs/manual/src/docs/asciidoc/_includes/servlet/crypto/index.adoc -@@ -3,21 +3,22 @@ - - - [[spring-security-crypto-introduction]] --== Introduction - The Spring Security Crypto module provides support for symmetric encryption, key generation, and password encoding. - The code is distributed as part of the core module but has no dependencies on any other Spring Security (or Spring) code. - - - [[spring-security-crypto-encryption]] - == Encryptors --The Encryptors class provides factory methods for constructing symmetric encryptors. --Using this class, you can create ByteEncryptors to encrypt data in raw byte[] form. --You can also construct TextEncryptors to encrypt text strings. -+The {security-api-url}org/springframework/security/crypto/encrypt/Encryptors.html[`Encryptors`] class provides factory methods for constructing symmetric encryptors. -+This class lets you create {security-api-url}org/springframework/security/crypto/encrypt/BytesEncryptor.html[`BytesEncryptor`] instances to encrypt data in raw `byte[]` form. -+You can also construct {security-api-url}org/springframework/security/crypto/encrypt/TextEncryptor.html[TextEncryptor] instances to encrypt text strings. - Encryptors are thread-safe. - -+NOTE: Both `BytesEncryptor` and `TextEncryptor` are interfaces. `BytesEncryptor` has multiple implementations. -+ - [[spring-security-crypto-encryption-bytes]] - === BytesEncryptor --Use the `Encryptors.stronger` factory method to construct a BytesEncryptor: -+YOu can use the `Encryptors.stronger` factory method to construct a `BytesEncryptor`: - - .BytesEncryptor - ==== -@@ -34,16 +35,16 @@ Encryptors.stronger("password", "salt") - ---- - ==== - --The "stronger" encryption method creates an encryptor using 256 bit AES encryption with -+The `stronger` encryption method creates an encryptor by using 256-bit AES encryption with - Galois Counter Mode (GCM). --It derives the secret key using PKCS #5's PBKDF2 (Password-Based Key Derivation Function #2). -+It derives the secret key by using PKCS #5's PBKDF2 (Password-Based Key Derivation Function #2). - This method requires Java 6. --The password used to generate the SecretKey should be kept in a secure place and not be shared. --The salt is used to prevent dictionary attacks against the key in the event your encrypted data is compromised. --A 16-byte random initialization vector is also applied so each encrypted message is unique. -+The password used to generate the `SecretKey` should be kept in a secure place and should not be shared. -+The salt is used to prevent dictionary attacks against the key in the event that your encrypted data is compromised. -+A 16-byte random initialization vector is also applied so that each encrypted message is unique. - - The provided salt should be in hex-encoded String form, be random, and be at least 8 bytes in length. --Such a salt may be generated using a KeyGenerator: -+You can generate such a salt by using a `KeyGenerator`: - - .Generating a key - ==== -@@ -60,14 +61,14 @@ val salt = KeyGenerators.string().generateKey() // generates a random 8-byte sal - ---- - ==== - --Users may also use the `standard` encryption method, which is 256-bit AES in Cipher Block Chaining (CBC) Mode. -+You can also use the `standard` encryption method, which is 256-bit AES in Cipher Block Chaining (CBC) Mode. - This mode is not https://en.wikipedia.org/wiki/Authenticated_encryption[authenticated] and does not provide any - guarantees about the authenticity of the data. --For a more secure alternative, users should prefer `Encryptors.stronger`. -+For a more secure alternative, use `Encryptors.stronger`. - - [[spring-security-crypto-encryption-text]] - === TextEncryptor --Use the Encryptors.text factory method to construct a standard TextEncryptor: -+You can use the `Encryptors.text` factory method to construct a standard TextEncryptor: - - .TextEncryptor - ==== -@@ -84,10 +85,10 @@ Encryptors.text("password", "salt") - ---- - ==== - --A TextEncryptor uses a standard BytesEncryptor to encrypt text data. --Encrypted results are returned as hex-encoded strings for easy storage on the filesystem or in the database. -+A `TextEncryptor` uses a standard `BytesEncryptor` to encrypt text data. -+Encrypted results are returned as hex-encoded strings for easy storage on the filesystem or in a database. - --Use the Encryptors.queryableText factory method to construct a "queryable" TextEncryptor: -+You can use the `Encryptors.queryableText` factory method to construct a "`queryable`" `TextEncryptor`: - - .Queryable TextEncryptor - ==== -@@ -104,21 +105,21 @@ Encryptors.queryableText("password", "salt") - ---- - ==== - --The difference between a queryable TextEncryptor and a standard TextEncryptor has to do with initialization vector (iv) handling. --The iv used in a queryable TextEncryptor#encrypt operation is shared, or constant, and is not randomly generated. --This means the same text encrypted multiple times will always produce the same encryption result. --This is less secure, but necessary for encrypted data that needs to be queried against. --An example of queryable encrypted text would be an OAuth apiKey. -+The difference between a queryable `TextEncryptor` and a standard `TextEncryptor` has to do with initialization vector (IV) handling. -+The IV used in a queryable `TextEncryptor.encrypt` operation is shared, or constant, and is not randomly generated. -+This means the same text encrypted multiple times always produces the same encryption result. -+This is less secure but necessary for encrypted data that needs to be queried against. -+An example of queryable encrypted text would be an OAuth `apiKey`. - - [[spring-security-crypto-keygenerators]] - == Key Generators --The KeyGenerators class provides a number of convenience factory methods for constructing different types of key generators. --Using this class, you can create a BytesKeyGenerator to generate byte[] keys. --You can also construct a StringKeyGenerator to generate string keys. --KeyGenerators are thread-safe. -+The {security-api-url}org/springframework/security/crypto/keygen/KeyGenerators.html[`KeyGenerators`] class provides a number of convenience factory methods for constructing different types of key generators. -+By using this class, you can create a {security-api-url}org/springframework/security/crypto/keygen/BytesKeyGenerator.html[`BytesKeyGenerator`] to generate `byte[]` keys. -+You can also construct a {security-api-url}org/springframework/security/crypto/keygen/StringKeyGenerator.html`[StringKeyGenerator]` to generate string keys. -+`KeyGenerators` is a thread-safe class. - - === BytesKeyGenerator --Use the KeyGenerators.secureRandom factory methods to generate a BytesKeyGenerator backed by a SecureRandom instance: -+You can use the `KeyGenerators.secureRandom` factory methods to generate a `BytesKeyGenerator` backed by a `SecureRandom` instance: - - .BytesKeyGenerator - ==== -@@ -138,7 +139,7 @@ val key = generator.generateKey() - ==== - - The default key length is 8 bytes. --There is also a KeyGenerators.secureRandom variant that provides control over the key length: -+A `KeyGenerators.secureRandom` variant provides control over the key length: - - .KeyGenerators.secureRandom - ==== -@@ -155,7 +156,7 @@ KeyGenerators.secureRandom(16) - ---- - ==== - --Use the KeyGenerators.shared factory method to construct a BytesKeyGenerator that always returns the same key on every invocation: -+Use the `KeyGenerators.shared` factory method to construct a BytesKeyGenerator that always returns the same key on every invocation: - - .KeyGenerators.shared - ==== -@@ -173,7 +174,7 @@ KeyGenerators.shared(16) - ==== - - === StringKeyGenerator --Use the KeyGenerators.string factory method to construct a 8-byte, SecureRandom KeyGenerator that hex-encodes each key as a String: -+You can use the `KeyGenerators.string` factory method to construct an 8-byte, `SecureRandom` `KeyGenerator` that hex-encodes each key as a `String`: - - .StringKeyGenerator - ==== -@@ -192,9 +193,10 @@ KeyGenerators.string() - - [[spring-security-crypto-passwordencoders]] - == Password Encoding --The password package of the spring-security-crypto module provides support for encoding passwords. -+The password package of the `spring-security-crypto` module provides support for encoding passwords. - `PasswordEncoder` is the central service interface and has the following signature: - -+==== - [source,java] - ---- - public interface PasswordEncoder { -@@ -204,16 +206,18 @@ String encode(String rawPassword); - boolean matches(String rawPassword, String encodedPassword); - } - ---- -+==== - --The matches method returns true if the rawPassword, once encoded, equals the encodedPassword. -+The `matches` method returns true if the `rawPassword`, once encoded, equals the `encodedPassword`. - This method is designed to support password-based authentication schemes. - --The `BCryptPasswordEncoder` implementation uses the widely supported "bcrypt" algorithm to hash the passwords. --Bcrypt uses a random 16 byte salt value and is a deliberately slow algorithm, in order to hinder password crackers. --The amount of work it does can be tuned using the "strength" parameter which takes values from 4 to 31. -+The `BCryptPasswordEncoder` implementation uses the widely supported "`bcrypt`" algorithm to hash the passwords. -+Bcrypt uses a random 16-byte salt value and is a deliberately slow algorithm, to hinder password crackers. -+You can tune the amount of work it does by using the `strength` parameter, which takes a value from 4 to 31. - The higher the value, the more work has to be done to calculate the hash. --The default value is 10. -+The default value is `10`. - You can change this value in your deployed system without affecting existing passwords, as the value is also stored in the encoded hash. -+The following example uses the `BCryptPasswordEncoder`: - - .BCryptPasswordEncoder - ==== -@@ -239,8 +243,8 @@ assertTrue(encoder.matches("myPassword", result)) - ==== - - The `Pbkdf2PasswordEncoder` implementation uses PBKDF2 algorithm to hash the passwords. --In order to defeat password cracking PBKDF2 is a deliberately slow algorithm and should be tuned to take about .5 seconds to verify a password on your system. -- -+To defeat password cracking, PBKDF2 is a deliberately slow algorithm and should be tuned to take about .5 seconds to verify a password on your system. -+The following system uses the `Pbkdf2PasswordEncoder`: - - .Pbkdf2PasswordEncoder - ==== -diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/exploits/csrf.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/exploits/csrf.adoc -index ec05a78fc0..ca941c692f 100644 ---- a/docs/manual/src/docs/asciidoc/_includes/servlet/exploits/csrf.adoc -+++ b/docs/manual/src/docs/asciidoc/_includes/servlet/exploits/csrf.adoc -@@ -7,33 +7,32 @@ This section discusses Spring Security's <> --* <> --* <> -+* <> -+* <> -+* <> - - [[servlet-csrf-idempotent]] - === Use proper HTTP verbs --The first step to protecting against CSRF attacks is to ensure your website uses proper HTTP verbs. -+The first step to protecting against CSRF attacks is to ensure that your website uses proper HTTP verbs. - This is covered in detail in <>. - - [[servlet-csrf-configure]] - === Configure CSRF Protection - The next step is to configure Spring Security's CSRF protection within your application. - Spring Security's CSRF protection is enabled by default, but you may need to customize the configuration. --Below are a few common customizations. -+The next few sections cover a few common customizations. - - [[servlet-csrf-configure-custom-repository]] - ==== Custom CsrfTokenRepository - --By default Spring Security stores the expected CSRF token in the `HttpSession` using `HttpSessionCsrfTokenRepository`. --There can be cases where users will want to configure a custom `CsrfTokenRepository`. --For example, it might be desirable to persist the `CsrfToken` in a cookie to <>. -+By default, Spring Security stores the expected CSRF token in the `HttpSession` by using `HttpSessionCsrfTokenRepository`. -+There can be cases where users want to configure a custom `CsrfTokenRepository`. -+For example, it might be desirable to persist the `CsrfToken` in a cookie to <>. - --By default the `CookieCsrfTokenRepository` will write to a cookie named `XSRF-TOKEN` and read it from a header named `X-XSRF-TOKEN` or the HTTP parameter `_csrf`. --These defaults come from https://docs.angularjs.org/api/ng/service/$http#cross-site-request-forgery-xsrf-protection[AngularJS] -- --You can configure `CookieCsrfTokenRepository` in XML using the following: -+By default, the `CookieCsrfTokenRepository` writes to a cookie named `XSRF-TOKEN` and reads it from a header named `X-XSRF-TOKEN` or the HTTP parameter `_csrf`. -+These defaults come from https://docs.angularjs.org/api/ng/service/$http#cross-site-request-forgery-xsrf-protection[AngularJS]. - -+You can configure `CookieCsrfTokenRepository` in XML byusing the following: - - .Store CSRF Token in a Cookie with XML Configuration - ==== -@@ -49,15 +48,11 @@ You can configure `CookieCsrfTokenRepository` in XML using the following: - ---- - ==== - --[NOTE] --==== --The sample explicitly sets `cookieHttpOnly=false`. --This is necessary to allow JavaScript (i.e. AngularJS) to read it. --If you do not need the ability to read the cookie with JavaScript directly, it is recommended to omit `cookieHttpOnly=false` to improve security. --==== -+NOTE: The sample explicitly sets `cookieHttpOnly=false`. -+This is necessary to allow JavaScript (such as AngularJS) to read it. -+If you do not need the ability to read the cookie with JavaScript directly, we recommend omitting `cookieHttpOnly=false` to improve security. - -- --You can configure `CookieCsrfTokenRepository` in Java Configuration using: -+You can configure `CookieCsrfTokenRepository` in Java or Kotlin configuration by using: - - .Store CSRF Token in a Cookie - ==== -@@ -95,20 +90,16 @@ class SecurityConfig : WebSecurityConfigurerAdapter() { - ---- - ==== - --[NOTE] --==== --The sample explicitly sets `cookieHttpOnly=false`. --This is necessary to allow JavaScript (i.e. AngularJS) to read it. --If you do not need the ability to read the cookie with JavaScript directly, it is recommended to omit `cookieHttpOnly=false` (by using `new CookieCsrfTokenRepository()` instead) to improve security. --==== -+NOTE: The sample explicitly sets `cookieHttpOnly=false`. -+This is necessary to let JavaScript (such as AngularJS) read it. -+If you do not need the ability to read the cookie with JavaScript directly, we recommend omitting `cookieHttpOnly=false` (by using `new CookieCsrfTokenRepository()` instead) to improve security. - - [[servlet-csrf-configure-disable]] - ==== Disable CSRF Protection --CSRF protection is enabled by default. --However, it is simple to disable CSRF protection if it <>. -- --The XML configuration below will disable CSRF protection. -+By default, CSRF protection is enabled. -+However, you can disable CSRF protection if it <>. - -+The following XML configuration disables CSRF protection: - - .Disable CSRF XML Configuration - ==== -@@ -121,7 +112,7 @@ The XML configuration below will disable CSRF protection. - ---- - ==== - --The Java configuration below will disable CSRF protection. -+The following Java or Kotlin configuration disables CSRF protection: - - .Disable CSRF - ==== -@@ -162,16 +153,16 @@ class SecurityConfig : WebSecurityConfigurerAdapter() { - [[servlet-csrf-include]] - === Include the CSRF Token - --In order for the <> to protect against CSRF attacks, we must include the actual CSRF token in the HTTP request. --This must be included in a part of the request (i.e. form parameter, HTTP header, etc) that is not automatically included in the HTTP request by the browser. -+For the <> to protect against CSRF attacks, we must include the actual CSRF token in the HTTP request. -+This must be included in a part of the request (a form parameter, an HTTP header, or other part) that is not automatically included in the HTTP request by the browser. - --Spring Security's https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/web/csrf/CsrfFilter.html[CsrfFilter] exposes a https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/web/csrf/CsrfToken.html[CsrfToken] as an `HttpServletRequest` attribute named `_csrf`. -+Spring Security's https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/web/csrf/CsrfFilter.html[`CsrfFilter`] exposes a https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/web/csrf/CsrfToken.html[`CsrfToken`] as an `HttpServletRequest` attribute named `_csrf`. - This means that any view technology can access the `CsrfToken` to expose the expected token as either a <> or <>. --Fortunately, there are integrations listed below that make including the token in <> and <> requests even easier. -+Fortunately, there are integrations listed later in this chapter that make including the token in <> and <> requests even easier. - - [[servlet-csrf-include-form]] - ==== Form URL Encoded --In order to post an HTML form the CSRF token must be included in the form as a hidden input. -+To post an HTML form, the CSRF token must be included in the form as a hidden input. - For example, the rendered HTML might look like: - - .CSRF Token HTML -@@ -184,26 +175,26 @@ For example, the rendered HTML might look like: - ---- - ==== - --Next we will discuss various ways of including the CSRF token in a form as a hidden input. -+Next, we discuss various ways of including the CSRF token in a form as a hidden input. - - [[servlet-csrf-include-form-auto]] - ===== Automatic CSRF Token Inclusion - --Spring Security's CSRF support provides integration with Spring's https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/servlet/support/RequestDataValueProcessor.html[RequestDataValueProcessor] via its https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/web/servlet/support/csrf/CsrfRequestDataValueProcessor.html[CsrfRequestDataValueProcessor]. --This means that if you leverage https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#mvc-view-jsp-formtaglib[Spring’s form tag library], https://www.thymeleaf.org/doc/tutorials/2.1/thymeleafspring.html#integration-with-requestdatavalueprocessor[Thymeleaf], or any other view technology that integrates with `RequestDataValueProcessor`, then forms that have an unsafe HTTP method (i.e. post) will automatically include the actual CSRF token. -+Spring Security's CSRF support provides integration with Spring's https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/servlet/support/RequestDataValueProcessor.html[`RequestDataValueProcessor`] through its https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/web/servlet/support/csrf/CsrfRequestDataValueProcessor.html[`CsrfRequestDataValueProcessor`]. -+This means that, if you use https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#mvc-view-jsp-formtaglib[Spring’s form tag library], https://www.thymeleaf.org/doc/tutorials/2.1/thymeleafspring.html#integration-with-requestdatavalueprocessor[Thymeleaf], or any other view technology that integrates with `RequestDataValueProcessor`, then forms that have an unsafe HTTP method (such as post) automatically include the actual CSRF token. - - [[servlet-csrf-include-form-tag]] - ===== csrfInput Tag - --If you are using JSPs, then you can use https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#mvc-view-jsp-formtaglib[Spring’s form tag library]. --However, if that is not an option, you can also easily include the token with the <> tag. -+If you use JSPs, you can use https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#mvc-view-jsp-formtaglib[Spring’s form tag library]. -+However, if that is not an option, you can also include the token with the <> tag. - - [[servlet-csrf-include-form-attr]] - ===== CsrfToken Request Attribute - - If the <> for including the actual CSRF token in the request do not work, you can take advantage of the fact that the `CsrfToken` <> as an `HttpServletRequest` attribute named `_csrf`. - --An example of doing this with a JSP is shown below: -+The following example does this with a JSP: - - .CSRF Token in Form with Request Attribute - ==== -@@ -223,19 +214,19 @@ An example of doing this with a JSP is shown below: - - [[servlet-csrf-include-ajax]] - ==== Ajax and JSON Requests --If you are using JSON, then it is not possible to submit the CSRF token within an HTTP parameter. --Instead you can submit the token within a HTTP header. -+If you use JSON, you cannot submit the CSRF token within an HTTP parameter. -+Instead, you can submit the token within a HTTP header. - --In the following sections we will discuss various ways of including the CSRF token as an HTTP request header in JavaScript based applications. -+The following sections discuss various ways of including the CSRF token as an HTTP request header in JavaScript based applications. - - [[servlet-csrf-include-ajax-auto]] - ===== Automatic Inclusion - --Spring Security can easily be <> to store the expected CSRF token in a cookie. --By storing the expected CSRF in a cookie, JavaScript frameworks like https://docs.angularjs.org/api/ng/service/$http#cross-site-request-forgery-xsrf-protection[AngularJS] will automatically include the actual CSRF token in the HTTP request headers. -+You can <> Spring Security to store the expected CSRF token in a cookie. -+By storing the expected CSRF in a cookie, JavaScript frameworks, such as https://docs.angularjs.org/api/ng/service/$http#cross-site-request-forgery-xsrf-protection[AngularJS], automatically include the actual CSRF token in the HTTP request headers. - - [[servlet-csrf-include-ajax-meta]] --===== Meta tags -+===== Meta Tags - - An alternative pattern to <> is to include the CSRF token within your `meta` tags. - The HTML might look something like this: -@@ -254,8 +245,8 @@ The HTML might look something like this: - ---- - ==== - --Once the meta tags contained the CSRF token, the JavaScript code would read the meta tags and include the CSRF token as a header. --If you were using jQuery, this could be done with the following: -+Once the meta tags contain the CSRF token, the JavaScript code can read the meta tags and include the CSRF token as a header. -+If you use jQuery, you can do this with the following code: - - .AJAX send CSRF Token - ==== -@@ -274,13 +265,13 @@ $(function () { - [[servlet-csrf-include-ajax-meta-tag]] - ====== csrfMeta tag - --If you are using JSPs a simple way to write the CSRF token to the `meta` tags is by leveraging the <> tag. -+If you use JSPs, one way to write the CSRF token to the `meta` tags is by using the <> tag. - - [[servlet-csrf-include-ajax-meta-attr]] - ====== CsrfToken Request Attribute - - If the <> for including the actual CSRF token in the request do not work, you can take advantage of the fact that the `CsrfToken` <> as an `HttpServletRequest` attribute named `_csrf`. --An example of doing this with a JSP is shown below: -+The following example does this with a JSP: - - .CSRF meta tag JSP - ==== -@@ -300,31 +291,31 @@ An example of doing this with a JSP is shown below: - [[servlet-csrf-considerations]] - == CSRF Considerations - There are a few special considerations to consider when implementing protection against CSRF attacks. --This section discusses those considerations as it pertains to servlet environments. --Refer to <> for a more general discussion. -+This section discusses those considerations as they pertain to servlet environments. -+See <> for a more general discussion. - - - [[servlet-considerations-csrf-login]] - === Logging In - --It is important to <> requests to protect against forging log in attempts. -+It is important to <> requests, to protect against forging login attempts. - Spring Security's servlet support does this out of the box. - - [[servlet-considerations-csrf-logout]] - === Logging Out - --It is important to <> requests to protect against forging log out attempts. --If CSRF protection is enabled (default), Spring Security's `LogoutFilter` to only process HTTP POST. --This ensures that log out requires a CSRF token and that a malicious user cannot forcibly log out your users. -+It is important to <> requests to protect against forging logout attempts. -+If CSRF protection is enabled (the default), Spring Security's `LogoutFilter` to only process HTTP POST. -+This ensures that logging out requires a CSRF token and that a malicious user cannot forcibly log out your users. - - The easiest approach is to use a form to log out. --If you really want a link, you can use JavaScript to have the link perform a POST (i.e. maybe on a hidden form). --For browsers with JavaScript that is disabled, you can optionally have the link take the user to a log out confirmation page that will perform the POST. -+If you really want a link, you can use JavaScript to have the link perform a POST (maybe on a hidden form). -+For browsers with JavaScript that is disabled, you can optionally have the link take the user to a log out confirmation page that performs the POST. - --If you really want to use HTTP GET with logout you can do so, but remember this is generally not recommended. --For example, the following Java Configuration will perform logout with the URL `/logout` is requested with any HTTP method: -+If you really want to use HTTP GET with logout, you can do so. However, remember that this is generally not recommended. -+For example, the following Java Configuration logs out when the `/logout` URL is requested with any HTTP method: - --.Log out with HTTP GET -+.Log out with any HTTP method - ==== - .Java - [source,java,role="primary"] -@@ -364,18 +355,18 @@ class SecurityConfig : WebSecurityConfigurerAdapter() { - [[servlet-considerations-csrf-timeouts]] - === CSRF and Session Timeouts - --By default Spring Security stores the CSRF token in the `HttpSession`. --This can lead to a situation where the session expires which means there is not an expected CSRF token to validate against. -+By default, Spring Security stores the CSRF token in the `HttpSession`. -+This can lead to a situation where the session expires, leaving no CSRF token to validate against. - --We've already discussed <> to session timeouts. -+We have already discussed <> to session timeouts. - This section discusses the specifics of CSRF timeouts as it pertains to the servlet support. - --It is simple to change storage of the expected CSRF token to be in a cookie. --For details, refer to the <> section. -+You can change the storage of the CSRF token to be in a cookie. -+For details, see the <> section. - - If a token does expire, you might want to customize how it is handled by specifying a custom `AccessDeniedHandler`. - The custom `AccessDeniedHandler` can process the `InvalidCsrfTokenException` any way you like. --For an example of how to customize the `AccessDeniedHandler` refer to the provided links for both <> and https://github.com/spring-projects/spring-security/blob/3.2.0.RC1/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpAccessDeniedHandlerTests.java#L64[Java configuration]. -+For an example of how to customize the `AccessDeniedHandler`, see the provided links for both <> and https://github.com/spring-projects/spring-security/blob/3.2.0.RC1/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpAccessDeniedHandlerTests.java#L64[Java configuration]. - // FIXME: We should add a custom AccessDeniedHandler section in the reference and update the links above - - -@@ -384,25 +375,22 @@ For an example of how to customize the `AccessDeniedHandler` refer to the provid - We have <> how protecting multipart requests (file uploads) from CSRF attacks causes a https://en.wikipedia.org/wiki/Chicken_or_the_egg[chicken and the egg] problem. - This section discusses how to implement placing the CSRF token in the <> and <> within a servlet application. - --[NOTE] --==== --More information about using multipart forms with Spring can be found within the https://docs.spring.io/spring/docs/5.2.x/spring-framework-reference/web.html#mvc-multipart[1.1.11. Multipart Resolver] section of the Spring reference and the https://docs.spring.io/spring/docs/5.2.x/javadoc-api/org/springframework/web/multipart/support/MultipartFilter.html[MultipartFilter javadoc]. --==== -+NOTE: You can find more information about using multipart forms with Spring in the https://docs.spring.io/spring/docs/5.2.x/spring-framework-reference/web.html#mvc-multipart[1.1.11. Multipart Resolver] section of the Spring reference and the https://docs.spring.io/spring/docs/5.2.x/javadoc-api/org/springframework/web/multipart/support/MultipartFilter.html[`MultipartFilter` javadoc]. - - [[servlet-csrf-considerations-multipart-body]] - ==== Place CSRF Token in the Body - - We have <> the tradeoffs of placing the CSRF token in the body. --In this section we will discuss how to configure Spring Security to read the CSRF from the body. -+In this section, we discuss how to configure Spring Security to read the CSRF from the body. - --In order to read the CSRF token from the body, the `MultipartFilter` is specified before the Spring Security filter. --Specifying the `MultipartFilter` before the Spring Security filter means that there is no authorization for invoking the `MultipartFilter` which means anyone can place temporary files on your server. --However, only authorized users will be able to submit a File that is processed by your application. -+To read the CSRF token from the body, the `MultipartFilter` is specified before the Spring Security filter. -+Specifying the `MultipartFilter` before the Spring Security filter means that there is no authorization for invoking the `MultipartFilter`, which means anyone can place temporary files on your server. -+However, only authorized users can submit a file that is processed by your application. - In general, this is the recommended approach because the temporary file upload should have a negligible impact on most servers. - - // FIXME: Document Spring Boot - --To ensure `MultipartFilter` is specified before the Spring Security filter with java configuration, users can override beforeSpringSecurityFilterChain as shown below: -+To ensure `MultipartFilter` is specified before the Spring Security filter with Java configuration, you can override `beforeSpringSecurityFilterChain`: - - .Initializer MultipartFilter - ==== -@@ -429,7 +417,7 @@ class SecurityApplicationInitializer : AbstractSecurityWebApplicationInitializer - ---- - ==== - --To ensure `MultipartFilter` is specified before the Spring Security filter with XML configuration, users can ensure the element of the `MultipartFilter` is placed before the springSecurityFilterChain within the web.xml as shown below: -+To ensure that `MultipartFilter` is specified before the Spring Security filter with XML configuration, you can ensure the `` element of the `MultipartFilter` is placed before the `springSecurityFilterChain` within the `web.xml` file: - - .web.xml - MultipartFilter - ==== -@@ -455,11 +443,11 @@ To ensure `MultipartFilter` is specified before the Spring Security filter with - ==== - - [[servlet-csrf-considerations-multipart-url]] --==== Include CSRF Token in URL -+==== Include a CSRF Token in a URL - --If allowing unauthorized users to upload temporary files is not acceptable, an alternative is to place the `MultipartFilter` after the Spring Security filter and include the CSRF as a query parameter in the action attribute of the form. -+If letting unauthorized users upload temporary files is not acceptable, an alternative is to place the `MultipartFilter` after the Spring Security filter and include the CSRF as a query parameter in the action attribute of the form. - Since the `CsrfToken` is exposed as an `HttpServletRequest` <>, we can use that to create an `action` with the CSRF token in it. --An example with a jsp is shown below -+The following example does this with a JSP: - - .CSRF Token in Action - ==== -@@ -475,5 +463,5 @@ An example with a jsp is shown below - === HiddenHttpMethodFilter - We have <> the trade-offs of placing the CSRF token in the body. - --In Spring's Servlet support, overriding the HTTP method is done using https://docs.spring.io/spring-framework/docs/5.2.x/javadoc-api/org/springframework/web/filter/reactive/HiddenHttpMethodFilter.html[HiddenHttpMethodFilter]. --More information can be found in https://docs.spring.io/spring/docs/5.2.x/spring-framework-reference/web.html#mvc-rest-method-conversion[HTTP Method Conversion] section of the reference documentation. -+In Spring's Servlet support, overriding the HTTP method is done by using https://docs.spring.io/spring-framework/docs/5.2.x/javadoc-api/org/springframework/web/filter/reactive/HiddenHttpMethodFilter.html[`HiddenHttpMethodFilter`]. -+You can find more information in the https://docs.spring.io/spring/docs/5.2.x/spring-framework-reference/web.html#mvc-rest-method-conversion[HTTP Method Conversion] section of the reference documentation. -diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/exploits/firewall.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/exploits/firewall.adoc -index 71171992b3..618368eef4 100644 ---- a/docs/manual/src/docs/asciidoc/_includes/servlet/exploits/firewall.adoc -+++ b/docs/manual/src/docs/asciidoc/_includes/servlet/exploits/firewall.adoc -@@ -1,49 +1,49 @@ - [[servlet-httpfirewall]] - = HttpFirewall --Spring Security has several areas where patterns you have defined are tested against incoming requests in order to decide how the request should be handled. --This occurs when the `FilterChainProxy` decides which filter chain a request should be passed through and also when the `FilterSecurityInterceptor` decides which security constraints apply to a request. --It's important to understand what the mechanism is and what URL value is used when testing against the patterns that you define. -+Spring Security has several areas where patterns you have defined are tested against incoming requests to decide how the request should be handled. -+This occurs when the `FilterChainProxy` decides which filter chain a request should be passed through and when the `FilterSecurityInterceptor` decides which security constraints apply to a request. -+It is important to understand what the mechanism is and what URL value is used when testing against the patterns that you define. - --The Servlet Specification defines several properties for the `HttpServletRequest` which are accessible via getter methods, and which we might want to match against. --These are the `contextPath`, `servletPath`, `pathInfo` and `queryString`. -+The servlet specification defines several properties for the `HttpServletRequest` that are accessible via getter methods and that we might want to match against. -+These are the `contextPath`, `servletPath`, `pathInfo`, and `queryString`. - Spring Security is only interested in securing paths within the application, so the `contextPath` is ignored. --Unfortunately, the servlet spec does not define exactly what the values of `servletPath` and `pathInfo` will contain for a particular request URI. -+Unfortunately, the servlet spec does not define exactly what the values of `servletPath` and `pathInfo` contain for a particular request URI. - For example, each path segment of a URL may contain parameters, as defined in https://www.ietf.org/rfc/rfc2396.txt[RFC 2396] --footnote:[You have probably seen this when a browser doesn't support cookies and the `jsessionid` parameter is appended to the URL after a semi-colon. --However the RFC allows the presence of these parameters in any path segment of the URL]. --The Specification does not clearly state whether these should be included in the `servletPath` and `pathInfo` values and the behaviour varies between different servlet containers. --There is a danger that when an application is deployed in a container which does not strip path parameters from these values, an attacker could add them to the requested URL in order to cause a pattern match to succeed or fail unexpectedly. --footnote:[The original values will be returned once the request leaves the `FilterChainProxy`, so will still be available to the application.]. -+(You have probably seen this when a browser does not support cookies and the `jsessionid` parameter is appended to the URL after a semicolon. -+However, the RFC allows the presence of these parameters in any path segment of the URL.) -+The Specification does not clearly state whether these should be included in the `servletPath` and `pathInfo` values and the behavior varies between different servlet containers. -+There is a danger that, when an application is deployed in a container that does not strip path parameters from these values, an attacker could add them to the requested URL to cause a pattern match to succeed or fail unexpectedly. -+(The original values will be returned once the request leaves the `FilterChainProxy`, so will still be available to the application.) - Other variations in the incoming URL are also possible. --For example, it could contain path-traversal sequences (like `/../`) or multiple forward slashes (`//`) which could also cause pattern-matches to fail. --Some containers normalize these out before performing the servlet mapping, but others don't. -+For example, it could contain path-traversal sequences (such as `/../`) or multiple forward slashes (`//`) that could also cause pattern-matches to fail. -+Some containers normalize these out before performing the servlet mapping, but others do not. - To protect against issues like these, `FilterChainProxy` uses an `HttpFirewall` strategy to check and wrap the request. --Un-normalized requests are automatically rejected by default, and path parameters and duplicate slashes are removed for matching purposes. --footnote:[So, for example, an original request path `/secure;hack=1/somefile.html;hack=2` will be returned as `/secure/somefile.html`.]. --It is therefore essential that a `FilterChainProxy` is used to manage the security filter chain. --Note that the `servletPath` and `pathInfo` values are decoded by the container, so your application should not have any valid paths which contain semi-colons, as these parts will be removed for matching purposes. -+By default, un-normalized requests are automatically rejected, and path parameters and duplicate slashes are removed for matching purposes. -+(So, for example, an original request path of `/secure;hack=1/somefile.html;hack=2` is returned as `/secure/somefile.html`.) -+It is, therefore, essential that a `FilterChainProxy` is used to manage the security filter chain. -+Note that the `servletPath` and `pathInfo` values are decoded by the container, so your application should not have any valid paths that contain semi-colons, as these parts are removed for matching purposes. - --As mentioned above, the default strategy is to use Ant-style paths for matching and this is likely to be the best choice for most users. --The strategy is implemented in the class `AntPathRequestMatcher` which uses Spring's `AntPathMatcher` to perform a case-insensitive match of the pattern against the concatenated `servletPath` and `pathInfo`, ignoring the `queryString`. -+As mentioned earlier, the default strategy is to use Ant-style paths for matching, and this is likely to be the best choice for most users. -+The strategy is implemented in the class `AntPathRequestMatcher`, which uses Spring's `AntPathMatcher` to perform a case-insensitive match of the pattern against the concatenated `servletPath` and `pathInfo`, ignoring the `queryString`. - --If for some reason, you need a more powerful matching strategy, you can use regular expressions. -+If you need a more powerful matching strategy, you can use regular expressions. - The strategy implementation is then `RegexRequestMatcher`. --See the Javadoc for this class for more information. -+See the {security-api-url}/org/springframework/security/web/util/matcher/RegexRequestMatcher.html[Javadoc for this class] for more information. - --In practice we recommend that you use method security at your service layer, to control access to your application, and do not rely entirely on the use of security constraints defined at the web-application level. --URLs change and it is difficult to take account of all the possible URLs that an application might support and how requests might be manipulated. --You should try and restrict yourself to using a few simple ant paths which are simple to understand. --Always try to use a "deny-by-default" approach where you have a catch-all wildcard ( /** or **) defined last and denying access. -+In practice, we recommend that you use method security at your service layer, to control access to your application, rather than rely entirely on the use of security constraints defined at the web-application level. -+URLs change, and it is difficult to take into account all the possible URLs that an application might support and how requests might be manipulated. -+You should restrict yourself to using a few simple Ant paths that are simple to understand. -+Always try to use a "`deny-by-default`" approach, where you have a catch-all wildcard (`/**` or `**`) defined last to deny access. - - Security defined at the service layer is much more robust and harder to bypass, so you should always take advantage of Spring Security's method security options. - - The `HttpFirewall` also prevents https://www.owasp.org/index.php/HTTP_Response_Splitting[HTTP Response Splitting] by rejecting new line characters in the HTTP Response headers. - --By default the `StrictHttpFirewall` is used. -+By default, the `StrictHttpFirewall` implementation is used. - This implementation rejects requests that appear to be malicious. --If it is too strict for your needs, then you can customize what types of requests are rejected. -+If it is too strict for your needs, you can customize what types of requests are rejected. - However, it is important that you do so knowing that this can open your application up to attacks. --For example, if you wish to leverage Spring MVC's Matrix Variables, the following configuration could be used: -+For example, if you wish to use Spring MVC's matrix variables, you could use the following configuration: - - .Allow Matrix Variables - ==== -@@ -80,11 +80,10 @@ fun httpFirewall(): StrictHttpFirewall { - ---- - ==== - --The `StrictHttpFirewall` provides an allowed list of valid HTTP methods that are allowed to protect against https://www.owasp.org/index.php/Cross_Site_Tracing[Cross Site Tracing (XST)] and https://www.owasp.org/index.php/Test_HTTP_Methods_(OTG-CONFIG-006)[HTTP Verb Tampering]. --The default valid methods are "DELETE", "GET", "HEAD", "OPTIONS", "PATCH", "POST", and "PUT". -+To protect against https://www.owasp.org/index.php/Cross_Site_Tracing[Cross Site Tracing (XST)] and https://www.owasp.org/index.php/Test_HTTP_Methods_(OTG-CONFIG-006)[HTTP Verb Tampering], the `StrictHttpFirewall` provides an allowed list of valid HTTP methods that are allowed. -+The default valid methods are `DELETE`, `GET`, `HEAD`, `OPTIONS`, `PATCH`, `POST`, and `PUT`. - If your application needs to modify the valid methods, you can configure a custom `StrictHttpFirewall` bean. --For example, the following will only allow HTTP "GET" and "POST" methods: -- -+The following example allows only HTTP `GET` and `POST` methods: - - .Allow Only GET & POST - ==== -@@ -121,31 +120,28 @@ fun httpFirewall(): StrictHttpFirewall { - ---- - ==== - --[TIP] --==== --If you are using `new MockHttpServletRequest()` it currently creates an HTTP method as an empty String "". --This is an invalid HTTP method and will be rejected by Spring Security. -+TIP: If you use `new MockHttpServletRequest()`, it currently creates an HTTP method as an empty String (`""`). -+This is an invalid HTTP method and is rejected by Spring Security. - You can resolve this by replacing it with `new MockHttpServletRequest("GET", "")`. --See https://jira.spring.io/browse/SPR-16851[SPR_16851] for an issue requesting to improve this. --==== -+See https://jira.spring.io/browse/SPR-16851[SPR_16851] for an issue that requests improving this. - - If you must allow any HTTP method (not recommended), you can use `StrictHttpFirewall.setUnsafeAllowAnyHttpMethod(true)`. --This will disable validation of the HTTP method entirely. -+Doing so entirely disables validation of the HTTP method. - - [[servlet-httpfirewall-headers-parameters]] - - `StrictHttpFirewall` also checks header names and values and parameter names. - It requires that each character have a defined code point and not be a control character. - --This requirement can be relaxed or adjusted as necessary using the following methods: -+This requirement can be relaxed or adjusted as necessary by using the following methods: - - * `StrictHttpFirewall#setAllowedHeaderNames(Predicate)` - * `StrictHttpFirewall#setAllowedHeaderValues(Predicate)` - * `StrictHttpFirewall#setAllowedParameterNames(Predicate)` - --NOTE: Also, parameter values can be controlled with `setAllowedParameterValues(Predicate)`. -+NOTE: Parameter values can be also controlled with `setAllowedParameterValues(Predicate)`. - --For example, to switch off this check, you can wire your `StrictHttpFirewall` with `Predicate` s that always return `true`, like so: -+For example, to switch off this check, you can wire your `StrictHttpFirewall` with `Predicate` instances that always return `true`: - - .Allow Any Header Name, Header Value, and Parameter Name - ==== -@@ -176,12 +172,12 @@ fun httpFirewall(): StrictHttpFirewall { - ---- - ==== - --Or, there might be a specific value that you need to allow. -+Alternatively, there might be a specific value that you need to allow. - --For example, iPhone Xʀ uses a `User-Agent` that includes a character not in the ISO-8859-1 charset. --Due to this fact, some application servers will parse this value into two separate characters, the latter being an undefined character. -+For example, iPhone Xʀ uses a `User-Agent` that includes a character that is not in the ISO-8859-1 charset. -+Due to this fact, some application servers parse this value into two separate characters, the latter being an undefined character. - --You can address this with the `setAllowedHeaderValues` method, as you can see below: -+You can address this with the `setAllowedHeaderValues` method: - - .Allow Certain User Agents - ==== -@@ -212,7 +208,7 @@ fun httpFirewall(): StrictHttpFirewall { - ---- - ==== - --In the case of header values, you may instead consider parsing them as UTF-8 at verification time like so: -+In the case of header values, you may instead consider parsing them as UTF-8 at verification time: - - .Parse Headers As UTF-8 - ==== -diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/exploits/headers.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/exploits/headers.adoc -index e45c5c96c9..15978085b4 100644 ---- a/docs/manual/src/docs/asciidoc/_includes/servlet/exploits/headers.adoc -+++ b/docs/manual/src/docs/asciidoc/_includes/servlet/exploits/headers.adoc -@@ -1,19 +1,19 @@ - [[servlet-headers]] - = Security HTTP Response Headers - --<> can be used to increase the security of web applications. --This section is dedicated to servlet based support for Security HTTP Response Headers. -+You can use <> to increase the security of web applications. -+This section is dedicated to servlet-based support for Security HTTP Response Headers. - - [[servlet-headers-default]] - == Default Security Headers - - Spring Security provides a <> to provide secure defaults. --While each of these headers are considered best practice, it should be noted that not all clients utilize the headers, so additional testing is encouraged. -+While each of these headers are considered best practice, it should be noted that not all clients use the headers, so additional testing is encouraged. - - You can customize specific headers. --For example, assume that you want the defaults except you wish to specify `SAMEORIGIN` for <>. -+For example, assume that you want the defaults but you wish to specify `SAMEORIGIN` for <>. - --You can easily do this with the following Configuration: -+You can do so with the following configuration: - - .Customize Default Security Headers - ==== -@@ -69,9 +69,9 @@ class SecurityConfig : WebSecurityConfigurerAdapter() { - ==== - - If you do not want the defaults to be added and want explicit control over what should be used, you can disable the defaults. --An example is provided below: -+The next code listing shows how to do so. - --If you are using Spring Security's Configuration the following will only add <>. -+If you use Spring Security's configuration, the following adds only <>: - - .Customize Cache Control Headers - ==== -@@ -127,7 +127,7 @@ class SecurityConfig : WebSecurityConfigurerAdapter() { - ---- - ==== - --If necessary, you can disable all of the HTTP Security response headers with the following Configuration: -+If necessary, you can disable all of the HTTP Security response headers with the following configuration: - - .Disable All HTTP Security Headers - ==== -@@ -179,11 +179,11 @@ class SecurityConfig : WebSecurityConfigurerAdapter() { - - Spring Security includes <> headers by default. - --However, if you actually want to cache specific responses, your application can selectively invoke https://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletResponse.html#setHeader(java.lang.String,java.lang.String)[HttpServletResponse.setHeader(String,String)] to override the header set by Spring Security. --This is useful to ensure things like CSS, JavaScript, and images are properly cached. -+However, if you actually want to cache specific responses, your application can selectively invoke https://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletResponse.html#setHeader(java.lang.String,java.lang.String)[`HttpServletResponse.setHeader(String,String)`] to override the header set by Spring Security. -+You can use this to ensure that content (such as CSS, JavaScript, and images) is properly cached. - --When using Spring Web MVC, this is typically done within your configuration. --Details on how to do this can be found in the https://docs.spring.io/spring/docs/5.0.0.RELEASE/spring-framework-reference/web.html#mvc-config-static-resources[Static Resources] portion of the Spring Reference documentation -+When you use Spring Web MVC, this is typically done within your configuration. -+You can find details on how to do this in the https://docs.spring.io/spring/docs/5.0.0.RELEASE/spring-framework-reference/web.html#mvc-config-static-resources[Static Resources] portion of the Spring Reference documentation - - If necessary, you can also disable Spring Security's cache control HTTP response headers. - -@@ -243,7 +243,7 @@ class SecurityConfig : WebSecurityConfigurerAdapter() { - == Content Type Options - - Spring Security includes <> headers by default. --However, you can disable it with: -+However, you can disable it: - - .Content Type Options Disabled - ==== -@@ -300,9 +300,9 @@ class SecurityConfig : WebSecurityConfigurerAdapter() { - [[servlet-headers-hsts]] - == HTTP Strict Transport Security (HSTS) - --Spring Security provides the <> header by default. --However, you can customize the results explicitly. --For example, the following is an example of explicitly providing HSTS: -+By default, Spring Security provides the <> header. -+However, you can explicitly customize the results. -+The following example explicitly provides HSTS: - - .Strict Transport Security - ==== -@@ -366,9 +366,9 @@ class SecurityConfig : WebSecurityConfigurerAdapter() { - - [[servlet-headers-hpkp]] - == HTTP Public Key Pinning (HPKP) --For passivity reasons, Spring Security provides servlet support for <> but it is <>. -+Spring Security provides servlet support for <>, but it is <>. - --You can enable HPKP headers with the following Configuration: -+You can enable HPKP headers with the following configuration: - - .HTTP Public Key Pinning - ==== -@@ -437,9 +437,9 @@ class SecurityConfig : WebSecurityConfigurerAdapter() { - [[servlet-headers-frame-options]] - == X-Frame-Options - --By default, Spring Security disables rendering within an iframe using <>. -+By default, Spring Security disables rendering within an iframe by using <>. - --You can customize frame options to use the same origin within a Configuration using the following: -+You can customize frame options to use the same origin within a configuration by using the following: - - .X-Frame-Options: SAMEORIGIN - ==== -@@ -499,9 +499,9 @@ class SecurityConfig : WebSecurityConfigurerAdapter() { - [[servlet-headers-xss-protection]] - == X-XSS-Protection - --By default, Spring Security instructs browsers to block reflected XSS attacks using the <. -+By default, Spring Security instructs browsers to block reflected XSS attacks by using the <>. - However, you can change this default. --For example, the following Configuration specifies that Spring Security should no longer instruct browsers to block the content: -+For example, the following configuration specifies that Spring Security should no longer instruct browsers to block the content: - - .X-XSS-Protection Customization - ==== -@@ -560,10 +560,10 @@ class SecurityConfig : WebSecurityConfigurerAdapter() { - [[servlet-headers-csp]] - == Content Security Policy (CSP) - --Spring Security does not add <> by default, because a reasonable default is impossible to know without context of the application. --The web application author must declare the security policy(s) to enforce and/or monitor for the protected resources. -+Spring Security does not add <> by default, because a reasonable default is impossible to know without knowing the context of the application. -+The web application author must declare the security policy (or policies) to enforce or monitor for the protected resources. - --For example, given the following security policy: -+Consider the following security policy: - - .Content Security Policy Example - ==== -@@ -573,7 +573,7 @@ Content-Security-Policy: script-src 'self' https://trustedscripts.example.com; o - ---- - ==== - --You can enable the CSP header as shown below: -+Given the preceding security policy, you can enable the CSP header: - - .Content Security Policy - ==== -@@ -694,7 +694,7 @@ class SecurityConfig : WebSecurityConfigurerAdapter() { - == Referrer Policy - - Spring Security does not add <> headers by default. --You can enable the Referrer Policy header using the configuration as shown below: -+You can enable the Referrer Policy header by using the configuration: - - .Referrer Policy - ==== -@@ -754,7 +754,7 @@ class SecurityConfig : WebSecurityConfigurerAdapter() { - == Feature Policy - - Spring Security does not add <> headers by default. --The following `Feature-Policy` header: -+Consider the following `Feature-Policy` header: - - .Feature-Policy Example - ==== -@@ -764,7 +764,7 @@ Feature-Policy: geolocation 'self' - ---- - ==== - --can enable the Feature Policy header using the configuration shown below: -+You can enable the preceding feature policy header by using the following configuration: - - .Feature-Policy - ==== -@@ -820,7 +820,7 @@ class SecurityConfig : WebSecurityConfigurerAdapter() { - == Permissions Policy - - Spring Security does not add <> headers by default. --The following `Permissions-Policy` header: -+Consider the following `Permissions-Policy` header: - - .Permissions-Policy Example - ==== -@@ -830,7 +830,7 @@ Permissions-Policy: geolocation=(self) - ---- - ==== - --can enable the Permissions Policy header using the configuration shown below: -+You can enable the preceding permissions policy header using the following configuration: - - .Permissions-Policy - ==== -@@ -890,7 +890,7 @@ class SecurityConfig : WebSecurityConfigurerAdapter() { - == Clear Site Data - - Spring Security does not add <> headers by default. --The following Clear-Site-Data header: -+Consider the following Clear-Site-Data header: - - .Clear-Site-Data Example - ==== -@@ -899,7 +899,7 @@ Clear-Site-Data: "cache", "cookies" - ---- - ==== - --can be sent on log out with the following configuration: -+You can send the preceding header on log out with the following configuration: - - .Clear-Site-Data - ==== -@@ -945,15 +945,15 @@ However, it also provides hooks to enable adding custom headers. - - [[servlet-headers-static]] - === Static Headers --There may be times you wish to inject custom security headers into your application that are not supported out of the box. --For example, given the following custom security header: -+There may be times when you wish to inject custom security headers that are not supported out of the box into your application. -+Consider the following custom security header: - - [source] - ---- - X-Custom-Security-Header: header-value - ---- - --The headers could be added to the response using the following Configuration: -+Given the preceding header, you could add the headers to the response by using the following configuration: - - .StaticHeadersWriter - ==== -@@ -1009,8 +1009,8 @@ class SecurityConfig : WebSecurityConfigurerAdapter() { - === Headers Writer - When the namespace or Java configuration does not support the headers you want, you can create a custom `HeadersWriter` instance or even provide a custom implementation of the `HeadersWriter`. - --Let's take a look at an example of using an custom instance of `XFrameOptionsHeaderWriter`. --If you wanted to explicitly configure <> it could be done with the following Configuration: -+The next example use a custom instance of `XFrameOptionsHeaderWriter`. -+If you wanted to explicitly configure <>, you could do so with the following configuration: - - .Headers Writer - ==== -@@ -1071,11 +1071,11 @@ class SecurityConfig : WebSecurityConfigurerAdapter() { - [[headers-delegatingrequestmatcherheaderwriter]] - === DelegatingRequestMatcherHeaderWriter - --At times you may want to only write a header for certain requests. --For example, perhaps you want to only protect your log in page from being framed. -+At times, you may want to write a header only for certain requests. -+For example, perhaps you want to protect only your login page from being framed. - You could use the `DelegatingRequestMatcherHeaderWriter` to do so. - --An example of using `DelegatingRequestMatcherHeaderWriter` in Java Configuration can be seen below: -+The following configuration example uses `DelegatingRequestMatcherHeaderWriter`: - - .DelegatingRequestMatcherHeaderWriter Java Configuration - ==== -diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/exploits/http.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/exploits/http.adoc -index f9d8c3275b..c077006a08 100644 ---- a/docs/manual/src/docs/asciidoc/_includes/servlet/exploits/http.adoc -+++ b/docs/manual/src/docs/asciidoc/_includes/servlet/exploits/http.adoc -@@ -1,16 +1,16 @@ - [[servlet-http]] - = HTTP - --All HTTP based communication should be protected <>. -+All HTTP-based communication should be protected <>. - --Below you can find details around Servlet specific features that assist with HTTPS usage. -+This section discusses the details of servlet-specific features that assist with HTTPS usage. - - [[servlet-http-redirect]] - == Redirect to HTTPS - --If a client makes a request using HTTP rather than HTTPS, Spring Security can be configured to redirect to HTTPS. -+If a client makes a request using HTTP rather than HTTPS, you can configure Spring Security to redirect to HTTPS. - --For example, the following Java configuration will redirect any HTTP requests to HTTPS: -+For example, the following Java or Kotlin configuration redirects any HTTP requests to HTTPS: - - .Redirect to HTTPS - ==== -@@ -52,7 +52,7 @@ class SecurityConfig : WebSecurityConfigurerAdapter() { - ---- - ==== - --The following XML configuration will redirect all HTTP requests to HTTPS -+The following XML configuration redirects all HTTP requests to HTTPS - - .Redirect to HTTPS with XML Configuration - ==== -diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/exploits/index.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/exploits/index.adoc -index bc955238c2..6a8e4b15e7 100644 ---- a/docs/manual/src/docs/asciidoc/_includes/servlet/exploits/index.adoc -+++ b/docs/manual/src/docs/asciidoc/_includes/servlet/exploits/index.adoc -@@ -1,6 +1,8 @@ - [[servlet-exploits]] - = Protection Against Exploits - -+This section details how Spring Security provides protection against some of the most common exploits. -+ - include::csrf.adoc[leveloffset=+1] - - include::headers.adoc[leveloffset=+1] -diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/hello/index.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/hello/index.adoc -index 57e9f5f1ce..98bd31f5c4 100644 ---- a/docs/manual/src/docs/asciidoc/_includes/servlet/hello/index.adoc -+++ b/docs/manual/src/docs/asciidoc/_includes/servlet/hello/index.adoc -@@ -3,11 +3,8 @@ - - This section covers the minimum setup for how to use Spring Security with Spring Boot. - --[NOTE] --==== --The completed application can be found at {gh-samples-url}/boot/helloworld[samples/boot/helloworld] --For your convenience, you can download a minimal Spring Boot + Spring Security application by https://start.spring.io/starter.zip?type=maven-project&language=java&packaging=jar&jvmVersion=1.8&groupId=example&artifactId=hello-security&name=hello-security&description=Hello%20Security&packageName=example.hello-security&dependencies=web,security[clicking here]. --==== -+NOTE: The completed application can be found at {gh-samples-url}/boot/helloworld[samples/boot/helloworld] -+For your convenience, you can download https://start.spring.io/starter.zip?type=maven-project&language=java&packaging=jar&jvmVersion=1.8&groupId=example&artifactId=hello-security&name=hello-security&description=Hello%20Security&packageName=example.hello-security&dependencies=web,security[a minimal Spring Boot + Spring Security application]. - - [[servlet-hello-dependencies]] - == Updating Dependencies -@@ -40,12 +37,12 @@ Using generated security password: 8e557245-73e2-4286-969a-ff57fe326336 - - // FIXME: Link to relevant portions of documentation - // FIXME: Link to Spring Boot's Security Auto configuration classes --// FIXME: Add a links for what user's should do next -+// FIXME: Add links for what user's should do next - - Spring Boot automatically: - - * Enables Spring Security's default configuration, which creates a servlet `Filter` as a bean named `springSecurityFilterChain`. --This bean is responsible for all the security (protecting the application URLs, validating submitted username and passwords, redirecting to the log in form, and so on) within your application. -+This bean is responsible for all the security (protecting the application URLs, validating submitted username and passwords, redirecting to the login form, and so on) within your application. - * Creates a `UserDetailsService` bean with a username of `user` and a randomly generated password that is logged to the console. - * Registers the `Filter` with a bean named `springSecurityFilterChain` with the Servlet container for every request. - -@@ -71,4 +68,3 @@ A summary of the features follows: - ** https://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletRequest.html#isUserInRole(java.lang.String)[`HttpServletRequest.html#isUserInRole(java.lang.String)`] - ** https://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletRequest.html#login(java.lang.String,%20java.lang.String)[`HttpServletRequest.html#login(java.lang.String, java.lang.String)`] - ** https://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletRequest.html#logout()[`HttpServletRequest.html#logout()`] -- -diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/concurrency.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/concurrency.adoc -index 78aeb0b674..d276815e2d 100644 ---- a/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/concurrency.adoc -+++ b/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/concurrency.adoc -@@ -1,19 +1,20 @@ - [[concurrency]] - == Concurrency Support - --In most environments, Security is stored on a per `Thread` basis. -+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. --Spring Security provides some infrastructure to help make this much easier for users. --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 <> and <>. -+Spring Security provides some infrastructure to help make this much easier to manage. -+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 integrate with <> and <>. - - === 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. --It then invokes the delegate Runnable ensuring to clear the `SecurityContextHolder` afterwards. -+It wraps a delegate `Runnable` to initialize the `SecurityContextHolder` with a specified `SecurityContext` for the delegate. -+It then invokes the delegate `Runnable`, ensuring to clear the `SecurityContextHolder` afterwards. - The `DelegatingSecurityContextRunnable` looks something like this: - -+==== - [source,java] - ---- - public void run() { -@@ -25,13 +26,15 @@ try { - } - } - ---- -+==== - --While very simple, it makes it seamless to transfer the SecurityContext from one Thread to another. --This is important since, in most cases, the SecurityContextHolder acts on a per Thread basis. -+While very simple, it makes it seamless to transfer the `SecurityContext` from one `Thread` to another. -+This is important since, in most cases, the `SecurityContextHolder` acts on a per-`Thread` basis. - For example, you might have used Spring Security's <> support to secure one of your services. --You can now easily transfer the `SecurityContext` of the current `Thread` to the `Thread` that invokes the secured service. --An example of how you might do this can be found below: -+You can now transfer the `SecurityContext` of the current `Thread` to the `Thread` that invokes the secured service. -+The following example show how you might do so: - -+==== - [source,java] - ---- - Runnable originalRunnable = new Runnable() { -@@ -46,18 +49,18 @@ DelegatingSecurityContextRunnable wrappedRunnable = - - new Thread(wrappedRunnable).start(); - ---- -+==== - --The code above performs the following steps: -+The preceding code: - --* Creates a `Runnable` that will be invoking our secured service. --Notice that it is not aware of Spring Security --* Obtains the `SecurityContext` that we wish to use from the `SecurityContextHolder` and initializes the `DelegatingSecurityContextRunnable` --* Use the `DelegatingSecurityContextRunnable` to create a Thread --* Start the Thread we created -- --Since it is quite common to create a `DelegatingSecurityContextRunnable` with the `SecurityContext` from the `SecurityContextHolder` there is a shortcut constructor for it. --The following code is the same as the code above: -+* Creates a `Runnable` that invokes our secured service. -+Note that it is not aware of Spring Security. -+* Obtains the `SecurityContext` that we wish to use from the `SecurityContextHolder` and initializes the `DelegatingSecurityContextRunnable`. -+* Uses the `DelegatingSecurityContextRunnable` to create a `Thread`. -+* Starts the `Thread` we created. - -+Since it is common to create a `DelegatingSecurityContextRunnable` with the `SecurityContext` from the `SecurityContextHolder`, there is a shortcut constructor for it. -+The following code has the same effect as the preceding code: - - [source,java] - ---- -@@ -73,18 +76,18 @@ DelegatingSecurityContextRunnable wrappedRunnable = - new 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. -+This code still requires us to know that we are using Spring Security. -+In the next section, we take a look at how we can use `DelegatingSecurityContextExecutor` to hide the fact that we use Spring Security. - - === 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. -- --The design of `DelegatingSecurityContextExecutor` is very similar to that of `DelegatingSecurityContextRunnable` except it accepts a delegate `Executor` instead of a delegate `Runnable`. --You can see an example of how it might be used below: -+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 to use it. -+Now we look at how `DelegatingSecurityContextExecutor` can shield our code from any knowledge that we are using Spring Security. - -+The design of `DelegatingSecurityContextExecutor` is similar to that of `DelegatingSecurityContextRunnable`, except that it accepts a delegate `Executor` instead of a delegate `Runnable`. -+The following example shows how to use it: - -+==== - [source,java] - ---- - SecurityContext context = SecurityContextHolder.createEmptyContext(); -@@ -105,19 +108,23 @@ public void run() { - - executor.execute(originalRunnable); - ---- -+==== - --The code performs the following steps: -+This code: - - * Creates the `SecurityContext` to be used for our `DelegatingSecurityContextExecutor`. --Note that in this example we simply create the `SecurityContext` by hand. --However, it does not matter where or how we get the `SecurityContext` (i.e. we could obtain it from the `SecurityContextHolder` if we wanted). --* Creates a delegateExecutor that is in charge of executing submitted ``Runnable``s --* Finally we create a `DelegatingSecurityContextExecutor` which is in charge of wrapping any Runnable that is passed into the execute method with a `DelegatingSecurityContextRunnable`. --It then passes the wrapped Runnable to the delegateExecutor. --In this instance, the same `SecurityContext` will be used for every Runnable submitted to our `DelegatingSecurityContextExecutor`. --This is nice if we are running background tasks that need to be run by a user with elevated privileges. --* At this point you may be asking yourself "How does this shield my code of any knowledge of Spring Security?" Instead of creating the `SecurityContext` and the `DelegatingSecurityContextExecutor` in our own code, we can inject an already initialized instance of `DelegatingSecurityContextExecutor`. -- -+Note that, in this example, we create the `SecurityContext` by hand. -+However, it does not matter where or how we get the `SecurityContext` (for example, we could obtain it from the `SecurityContextHolder`). -+* Creates a `delegateExecutor` that is in charge of executing submitted `Runnable` objects. -+* Finally, we create a `DelegatingSecurityContextExecutor`, which is in charge of wrapping any `Runnable` that is passed into the `execute` method with a `DelegatingSecurityContextRunnable`. -+It then passes the wrapped `Runnable` to the `delegateExecutor`. -+In this case, the same `SecurityContext` is used for every `Runnable` submitted to our `DelegatingSecurityContextExecutor`. -+This is nice if we run background tasks that need to be run by a user with elevated privileges. -+* At this point, you may ask yourself, "`How does this shield my code of any knowledge of Spring Security?`" Instead of creating the `SecurityContext` and the `DelegatingSecurityContextExecutor` in our own code, we can inject an already initialized instance of `DelegatingSecurityContextExecutor`. -+ -+Consider the following example: -+ -+==== - [source,java] - ---- - @Autowired -@@ -132,35 +139,36 @@ Runnable originalRunnable = new Runnable() { - executor.execute(originalRunnable); - } - ---- -+==== - --Now our code is unaware that the `SecurityContext` is being propagated to the `Thread`, then the `originalRunnable` is run, and then the `SecurityContextHolder` is cleared out. -+Now our code is unaware that the `SecurityContext` is being propagated to the `Thread`, the `originalRunnable` is run, and the `SecurityContextHolder` is cleared out. - In this example, the same user is being used to run each thread. --What if we wanted to use the user from `SecurityContextHolder` at the time we invoked `executor.execute(Runnable)` (i.e. the currently logged in user) to process ``originalRunnable``? --This can be done by removing the `SecurityContext` argument from our `DelegatingSecurityContextExecutor` constructor. --For example: -- -+What if we wanted to use the user from `SecurityContextHolder` (that is, the currently logged in-user) at the time we invoked `executor.execute(Runnable)` to process `originalRunnable`? -+You can do so by removing the `SecurityContext` argument from our `DelegatingSecurityContextExecutor` constructor: - -+==== - [source,java] - ---- - SimpleAsyncTaskExecutor delegateExecutor = new SimpleAsyncTaskExecutor(); - DelegatingSecurityContextExecutor executor = - new 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`. -+Now, any time `executor.execute(Runnable)` is run, 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 - --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. -- --* `DelegatingSecurityContextCallable` --* `DelegatingSecurityContextExecutor` --* `DelegatingSecurityContextExecutorService` --* `DelegatingSecurityContextRunnable` --* `DelegatingSecurityContextScheduledExecutorService` --* `DelegatingSecurityContextSchedulingTaskExecutor` --* `DelegatingSecurityContextAsyncTaskExecutor` --* `DelegatingSecurityContextTaskExecutor` --* `DelegatingSecurityContextTaskScheduler` -+See the {security-api-url}index.html[Javadoc] for additional integrations with both the Java concurrent APIs and the Spring Task abstractions. -+They are self-explanatory once you understand the previous code. -+ -+* {security-api-url}org/springframework/security/concurrent/DelegatingSecurityContextCallable.html[`DelegatingSecurityContextCallable`] -+* {security-api-url}org/springframework/security/concurrent/DelegatingSecurityContextExecutor.html[`DelegatingSecurityContextExecutor`] -+* {security-api-url}org/springframework/security/concurrent/DelegatingSecurityContextExecutorService.html[`DelegatingSecurityContextExecutorService`] -+* {security-api-url}org/springframework/security/concurrent/DelegatingSecurityContextRunnable.html[`DelegatingSecurityContextRunnable`] -+* {security-api-url}org/springframework/security/concurrent/DelegatingSecurityContextScheduledExecutorService.html[`DelegatingSecurityContextScheduledExecutorService`] -+* {security-api-url}org/springframework/security/scheduling/DelegatingSecurityContextSchedulingTaskExecutor.html[`DelegatingSecurityContextSchedulingTaskExecutor`] -+* {security-api-url}org/springframework/security/task/DelegatingSecurityContextAsyncTaskExecutor.html[`DelegatingSecurityContextAsyncTaskExecutor`] -+* {security-api-url}org/springframework/security/task/DelegatingSecurityContextTaskExecutor.html[`DelegatingSecurityContextTaskExecutor`] -+* {security-api-url}org/springframework/security/scheduling/DelegatingSecurityContextTaskScheduler.html[`DelegatingSecurityContextTaskScheduler`] -diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/cors.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/cors.adoc -index 188da871c1..ce315decd1 100644 ---- a/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/cors.adoc -+++ b/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/cors.adoc -@@ -2,12 +2,13 @@ - == 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`). --If the request does not contain any cookies and Spring Security is first, the request will determine the user is not authenticated (since there are no cookies in the request) and reject it. -+CORS must be processed before Spring Security, because the pre-flight request does not contain any cookies (that is, the `JSESSIONID`). -+If the request does not contain any cookies and Spring Security is first, the request determines that the user is not authenticated (since there are no cookies in the request) and rejects it. - - The easiest way to ensure that CORS is handled first is to use the `CorsFilter`. --Users can integrate the `CorsFilter` with Spring Security by providing a `CorsConfigurationSource` using the following: -+Users can integrate the `CorsFilter` with Spring Security by providing a `CorsConfigurationSource` that uses the following: - -+==== - [source,java] - ---- - @EnableWebSecurity -@@ -32,9 +33,11 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter { - } - } - ---- -+==== - --or in XML -+The following listing does the same thing in XML: - -+==== - [source,xml] - ---- - -@@ -45,9 +48,11 @@ or in XML - ... - - ---- -+==== - --If you are using Spring MVC's CORS support, you can omit specifying the `CorsConfigurationSource` and Spring Security will leverage the CORS configuration provided to Spring MVC. -+If you use Spring MVC's CORS support, you can omit specifying the `CorsConfigurationSource` and Spring Security uses the CORS configuration provided to Spring MVC: - -+==== - [source,java] - ---- - @EnableWebSecurity -@@ -63,9 +68,11 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter { - } - } - ---- -+==== - --or in XML -+The following listing does the same thing in XML: - -+==== - [source,xml] - ---- - -@@ -74,3 +81,4 @@ or in XML - ... - - ---- -+==== -diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/data.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/data.adoc -index 07a1decc3f..04e5a8c7bf 100644 ---- a/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/data.adoc -+++ b/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/data.adoc -@@ -2,14 +2,15 @@ - == 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. -+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 - --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: -+To use this support, add the `org.springframework.security:spring-security-data` dependency and provide a bean of type `SecurityEvaluationContextExtension`. -+In Java configuration, this would look like: - -+==== - [source,java] - ---- - @Bean -@@ -17,20 +18,23 @@ public SecurityEvaluationContextExtension securityEvaluationContextExtension() { - return new SecurityEvaluationContextExtension(); - } - ---- -+==== - - In XML Configuration, this would look like: - -+==== - [source,xml] - ---- - - ---- -+==== - - [[data-query]] - === Security Expressions within @Query - --Now Spring Security can be used within your queries. --For example: -+Now you can use Spring Security within your queries: - -+==== - [source,java] - ---- - @Repository -@@ -39,7 +43,8 @@ public interface MessageRepository extends PagingAndSortingRepository findInbox(Pageable pageable); - } - ---- -+==== - - This checks to see if the `Authentication.getPrincipal().getId()` is equal to the recipient of the `Message`. --Note that this example assumes you have customized the principal to be an Object that has an id property. --By exposing the `SecurityEvaluationContextExtension` bean, all of the <> are available within the Query. -+Note that this example assumes you have customized the principal to be an `Object` that has an `id` property. -+By exposing the `SecurityEvaluationContextExtension` bean, all of the <> are available within the query. -diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/index.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/index.adoc -index 90b9783a1f..8673bae878 100644 ---- a/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/index.adoc -+++ b/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/index.adoc -@@ -1,5 +1,7 @@ - = Integrations - -+This section describes various integrations that Spring Security has with other technologies: -+ - include::servlet-api.adoc[] - - include::data.adoc[] -diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/jackson.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/jackson.adoc -index 9e6418a175..d7ef8670ca 100644 ---- a/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/jackson.adoc -+++ b/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/jackson.adoc -@@ -1,11 +1,12 @@ - [[jackson]] - == 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). -+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 (session replication, Spring Session, and so on). - - To use it, register the `SecurityJackson2Modules.getModules(ClassLoader)` with `ObjectMapper` (https://github.com/FasterXML/jackson-databind[jackson-databind]): - -+==== - [source,java] - ---- - ObjectMapper mapper = new ObjectMapper(); -@@ -18,13 +19,14 @@ SecurityContext context = new SecurityContextImpl(); - // ... - String json = mapper.writeValueAsString(context); - ---- -+==== - - [NOTE] - ==== - The following Spring Security modules provide Jackson support: - --- spring-security-core (`CoreJackson2Module`) --- spring-security-web (`WebJackson2Module`, `WebServletJackson2Module`, `WebServerJackson2Module`) --- <> (`OAuth2ClientJackson2Module`) --- spring-security-cas (`CasJackson2Module`) -+- spring-security-core ({security-api-url}org/springframework/security/jackson2/CoreJackson2Module.html[`CoreJackson2Module`]) -+- spring-security-web ({security-api-url}org/springframework/security/web/jackson2/WebJackson2Module.html[`WebJackson2Module`], {security-api-url}org/springframework/security/web/jackson2/WebServletJackson2Module.html[`WebServletJackson2Module`], {security-api-url}org/springframework/security/web/server/jackson2/WebServerJackson2Module.html[`WebServerJackson2Module`]) -+- <> ({security-api-url}org/springframework/security/oauth2/client/jackson2/OAuth2ClientJackson2Module.html[`OAuth2ClientJackson2Module`]) -+- spring-security-cas ({security-api-url}org/springframework/security/cas/jackson2/CasJackson2Module.html[`CasJackson2Module`]) - ==== -diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/jsp-taglibs.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/jsp-taglibs.adoc -index 3f31683258..b0c1e3a5d9 100644 ---- a/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/jsp-taglibs.adoc -+++ b/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/jsp-taglibs.adoc -@@ -1,26 +1,30 @@ - [[taglibs]] - == JSP Tag Libraries --Spring Security has its own taglib which provides basic support for accessing security information and applying security constraints in JSPs. -+Spring Security has its own taglib, which provides basic support for accessing security information and applying security constraints in JSPs. - - - === Declaring the Taglib - To use any of the tags, you must have the security taglib declared in your JSP: - -+==== - [source,xml] - ---- - <%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags" %> - ---- -+==== - - [[taglibs-authorize]] - === 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. --]. --The first approach uses a <>, specified in the `access` attribute of the tag. --The expression evaluation will be delegated to the `SecurityExpressionHandler` defined in the application context (you should have web expressions enabled in your `` namespace configuration to make sure this service is available). --So, for example, you might have -+In Spring Security 3.0, it can be used in two ways. - -+NOTE: The legacy options from Spring Security 2.0 are also supported, but discouraged. -+ -+The first approach uses a <>, which is specified in the `access` attribute of the tag. -+The expression evaluation is delegated to the `SecurityExpressionHandler` defined in the application context (you should have web expressions enabled in your `` namespace configuration to make sure this service is available). -+So, for example, you might have: -+ -+==== - [source,xml] - ---- - -@@ -29,10 +33,11 @@ This content will only be visible to users who have the "supervisor" authority i - - - ---- -+==== - --When used in conjunction with Spring Security's PermissionEvaluator, the tag can also be used to check permissions. --For example: -+When used in conjunction with Spring Security's `PermissionEvaluator`, the tag can also be used to check permissions: - -+==== - [source,xml] - ---- - -@@ -41,12 +46,14 @@ This content will only be visible to users who have read or write permission to - - - ---- -+==== - --A common requirement is to only show a particular link, if the user is actually allowed to click it. --How can we determine in advance whether something will be allowed? This tag can also operate in an alternative mode which allows you to define a particular URL as an attribute. --If the user is allowed to invoke that URL, then the tag body will be evaluated, otherwise it will be skipped. --So you might have something like -+A common requirement is to show only a particular link, assuming the user is actually allowed to click it. -+How can we determine in advance whether something is allowed? This tag can also operate in an alternative mode that lets you define a particular URL as an attribute. -+If the user is allowed to invoke that URL, the tag body is evaluated. Otherwise, it is skipped. -+So you might have something like: - -+==== - [source,xml] - ---- - -@@ -55,60 +62,64 @@ This content will only be visible to users who are authorized to send requests t - - - ---- -+==== - --To use this tag there must also be an instance of `WebInvocationPrivilegeEvaluator` in your application context. --If you are using the namespace, one will automatically be registered. -+To use this tag, you must also have an instance of `WebInvocationPrivilegeEvaluator` in your application context. -+If you are using the namespace, one is automatically registered. - This is an instance of `DefaultWebInvocationPrivilegeEvaluator`, which creates a dummy web request for the supplied URL and invokes the security interceptor to see whether the request would succeed or fail. --This allows you to delegate to the access-control setup you defined using `intercept-url` declarations within the `` namespace configuration and saves having to duplicate the information (such as the required roles) within your JSPs. --This approach can also be combined with a `method` attribute, supplying the HTTP method, for a more specific match. -+This lets you delegate to the access-control setup you defined by using `intercept-url` declarations within the `` namespace configuration and saves having to duplicate the information (such as the required roles) within your JSPs. -+You can also combine this approach with a `method` attribute (supplying the HTTP method, such as `POST`) for a more specific match. - --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. -+You can store the Boolean result of evaluating the tag (whether it grants or denies access) 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 --Hiding a link in a page for unauthorized users doesn't prevent them from accessing the URL. -+Hiding a link in a page for unauthorized users does not 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. --If you set the system property `spring.security.disableUISecurity` to `true`, the `authorize` tag will still run but will not hide its contents. --By default it will also surround the content with `...` tags. --This allows you to display "hidden" content with a particular CSS style such as a different background colour. --Try running the "tutorial" sample application with this property enabled, for example. -+As part of your testing process, you may want to reveal the hidden areas, to check that links really are secured at the back end. -+If you set the `spring.security.disableUISecurity` system property to `true`, the `authorize` tag still runs but does not hide its contents. -+By default, it also surrounds the content with `...` tags. -+This lets you to display "`hidden`" content with a particular CSS style, such as a different background color. -+Try running the "`tutorial`" sample application, for example, with this property enabled. - --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). -+You can also set the `spring.security.securedUIPrefix` and `spring.security.securedUISuffix` properties if you want to change surrounding text from the default `span` tags (or use empty strings to remove it completely). - - - === 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 `` will render the name of the current user. -+So, for example, if the `principal` property of the `Authentication` is an instance of Spring Security's `UserDetails` object, then using `` renders the name of the current user. - --Of course, it isn't necessary to use JSP tags for this kind of thing and some people prefer to keep as little logic as possible in the view. -+Of course, it is not necessary to use JSP tags for this kind of thing, and some people prefer to keep as little logic as possible in the view. - 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 - 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. --If they don't, it will be skipped. --An example might be -+If the current user has all of those permissions, the tag body is evaluated. -+If they do not, it is skipped. - - CAUTION: In general this tag should be considered deprecated. - Instead use the <>. - -+The following listing shows an example: -+ -+==== - [source,xml] - ---- - - --This will be shown if the user has all of the permissions represented by the values "1" or "2" on the given object. -+ - - - ---- -+==== - --The permissions are passed to the `PermissionFactory` defined in the application context, converting them to ACL `Permission` instances, so they may be any format which is supported by the factory - they don't have to be integers, they could be strings like `READ` or `WRITE`. --If no `PermissionFactory` is found, an instance of `DefaultPermissionFactory` will be used. --The `AclService` from the application context will be used to load the `Acl` instance for the supplied object. --The `Acl` will be invoked with the required permissions to check if all of them are granted. -+The permissions are passed to the `PermissionFactory` defined in the application context, converting them to ACL `Permission` instances, so they may be any format that is supported by the factory. They do not have to be integers. They could be strings such as `READ` or `WRITE`. -+If no `PermissionFactory` is found, an instance of `DefaultPermissionFactory` is used. -+The `AclService` from the application context is used to load the `Acl` instance for the supplied object. -+The `Acl` is invoked with the required permissions to check if all of them are granted. - - This tag also supports the `var` attribute, in the same way as the `authorize` tag. - -@@ -117,12 +128,14 @@ This tag also supports the `var` attribute, in the same way as the `authorize` t - 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. - --Normally Spring Security automatically inserts a CSRF form field for any `` tags you use, but if for some reason you cannot use ``, `csrfInput` is a handy replacement. -+Normally, Spring Security automatically inserts a CSRF form field for any `` tags you use, but if for some reason you cannot use ``, `csrfInput` is a handy replacement. - - You should place this tag within an HTML `
` block, where you would normally place other input fields. - Do NOT place this tag within a Spring `` block. - Spring Security handles Spring forms automatically. -+The following listing shows an example: - -+==== - [source,xml] - ---- -
-@@ -132,16 +145,19 @@ Spring Security handles Spring forms automatically. - ... -
- ---- -+==== - - [[taglibs-csrfmeta]] - === 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. -+If CSRF protection is enabled, this tag inserts meta tags that contain 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. - - You should place `csrfMetaTags` within an HTML ` ` block, where you would normally place other meta tags. --Once you use this tag, you can access the form field name, header name, and token value easily using JavaScript. -+Once you use this tag, you can access the form field name, header name, and token value by using JavaScript. - JQuery is used in this example to make the task easier. -+The following listing shows an example: - -+==== - [source,xml] - ---- - -@@ -197,6 +213,6 @@ JQuery is used in this example to make the task easier. - - - ---- -+==== - - If CSRF protection is not enabled, `csrfMetaTags` outputs nothing. -- -diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/localization.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/localization.adoc -index 0f8f9b402e..d7bff6a279 100644 ---- a/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/localization.adoc -+++ b/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/localization.adoc -@@ -1,17 +1,18 @@ - [[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. -+If your application is designed for English-speaking users, you need not do anything as, by default, all Security messages are in English. -+If you need to support other locales, this section contains everything you need to know. - --All exception messages can be localized, including messages related to authentication failures and access being denied (authorization failures). --Exceptions and logging messages that are focused on developers or system deplopers (including incorrect attributes, interface contract violations, using incorrect constructors, startup time validation, debug-level logging) are not localized and instead are hard-coded in English within Spring Security's code. -+All exception messages, including messages related to authentication failures and access being denied (authorization failures), can be localized. -+Exceptions and logging messages that are focused on developers or system deployers (including incorrect attributes, interface contract violations, using incorrect constructors, startup time validation, debug-level logging) are not localized and instead are hard-coded in English within Spring Security's code. - --Shipping in the `spring-security-core-xx.jar` you will find an `org.springframework.security` package that in turn contains a `messages.properties` file, as well as localized versions for some common languages. --This should be referred to by your `ApplicationContext`, as Spring Security classes implement Spring's `MessageSourceAware` interface and expect the message resolver to be dependency injected at application context startup time. --Usually all you need to do is register a bean inside your application context to refer to the messages. --An example is shown below: -+In the `spring-security-core-xx.jar`, you find an `org.springframework.security` package that, in turn, contains a `messages.properties` file as well as localized versions for some common languages. -+Your `ApplicationContext` should refer to this, as Spring Security classes implement Spring's `MessageSourceAware` interface and expect the message resolver to be dependency injected at application context startup time. -+Usually, all you need to do is register a bean inside your application context to refer to the messages. -+The following listing shows an example: - -+==== - [source,xml] - ---- - - - ---- -+==== - - The `messages.properties` is named in accordance with standard resource bundles and represents the default language supported by Spring Security messages. - This default file is in English. - --If you wish to customize the `messages.properties` file, or support other languages, you should copy the file, rename it accordingly, and register it inside the above bean definition. -+To customize the `messages.properties` file or support other languages, you should copy the file, rename it accordingly, and register it inside the preceding bean definition. - There are not a large number of message keys inside this file, so localization should not be considered a major initiative. --If you do perform localization of this file, please consider sharing your work with the community by logging a JIRA task and attaching your appropriately-named localized version of `messages.properties`. -+If you do perform localization of this file, consider sharing your work with the community by logging a JIRA task and attaching your appropriately-named localized version of `messages.properties`. - --Spring Security relies on Spring's localization support in order to actually lookup the appropriate message. --In order for this to work, you have to make sure that the locale from the incoming request is stored in Spring's `org.springframework.context.i18n.LocaleContextHolder`. --Spring MVC's `DispatcherServlet` does this for your application automatically, but since Spring Security's filters are invoked before this, the `LocaleContextHolder` needs to be set up to contain the correct `Locale` before the filters are called. -+Spring Security relies on Spring's localization support in order to actually look up the appropriate message. -+For this to work, you have to make sure that the locale from the incoming request is stored in Spring's `org.springframework.context.i18n.LocaleContextHolder`. -+Spring MVC's `DispatcherServlet` does this for your application automatically. However, since Spring Security's filters are invoked before this, the `LocaleContextHolder` needs to be set up to contain the correct `Locale` before the filters are called. - You can either do this in a filter yourself (which must come before the Spring Security filters in `web.xml`) or you can use Spring's `RequestContextFilter`. --Please refer to the Spring Framework documentation for further details on using localization with Spring. -+See the Spring Framework documentation for further details on using localization with Spring. - --The "contacts" sample application is set up to use localized messages. -+The `contacts` sample application is set up to use localized messages. -diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/mvc.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/mvc.adoc -index fe34eb8e29..020e209adf 100644 ---- a/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/mvc.adoc -+++ b/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/mvc.adoc -@@ -8,24 +8,25 @@ This section covers the integration in further detail. - === @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. -+The replacement is `@EnableWebSecurity`, which adds the Spring MVC features, based upon the classpath. - --To enable Spring Security integration with Spring MVC add the `@EnableWebSecurity` annotation to your configuration. -+To enable Spring Security integration with Spring MVC, add the `@EnableWebSecurity` annotation to your configuration. - --NOTE: Spring Security provides the configuration using Spring MVC's https://docs.spring.io/spring/docs/5.0.0.RELEASE/spring-framework-reference/web.html#mvc-config-customize[WebMvcConfigurer]. --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. -+NOTE: Spring Security provides the configuration by using Spring MVC's https://docs.spring.io/spring/docs/5.0.0.RELEASE/spring-framework-reference/web.html#mvc-config-customize[`WebMvcConfigurer`]. -+This means that, if you use more advanced options, such as integrating with `WebMvcConfigurationSupport` directly, you need to manually provide the Spring Security configuration. - - [[mvc-requestmatcher]] - === 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. -+This is helpful to ensure that your Security rules match the logic used to handle your requests. - --In order to use `MvcRequestMatcher` you must place the Spring Security Configuration in the same `ApplicationContext` as your `DispatcherServlet`. -+To use `MvcRequestMatcher`, you must place the Spring Security Configuration in the same `ApplicationContext` as your `DispatcherServlet`. - This is necessary because Spring Security's `MvcRequestMatcher` expects a `HandlerMappingIntrospector` bean with the name of `mvcHandlerMappingIntrospector` to be registered by your Spring MVC configuration that is used to perform the matching. - --For a `web.xml` this means that you should place your configuration in the `DispatcherServlet.xml`. -+For a `web.xml` file, this means that you should place your configuration in the `DispatcherServlet.xml`: - -+==== - [source,xml] - ---- - -@@ -53,9 +54,11 @@ For a `web.xml` this means that you should place your configuration in the `Disp - / - - ---- -+==== - --Below `WebSecurityConfiguration` in placed in the ``DispatcherServlet``s `ApplicationContext`. -+The following `WebSecurityConfiguration` in placed in the `ApplicationContext` of the `DispatcherServlet`. - -+==== - [source,java] - ---- - public class SecurityInitializer extends -@@ -78,26 +81,32 @@ public class SecurityInitializer extends - } - } - ---- -+==== - - [NOTE] - ==== --It is always recommended to provide authorization rules by matching on the `HttpServletRequest` and method security. -+We always recommend that you provide authorization rules by matching on the `HttpServletRequest` and method security. - --Providing authorization rules by matching on `HttpServletRequest` is good because it happens very early in the code path and helps reduce the https://en.wikipedia.org/wiki/Attack_surface[attack surface]. --Method security ensures that if someone has bypassed the web authorization rules, that your application is still secured. --This is what is known as https://en.wikipedia.org/wiki/Defense_in_depth_(computing)[Defence in Depth] -+Providing authorization rules by matching on `HttpServletRequest` is good, because it happens very early in the code path and helps reduce the https://en.wikipedia.org/wiki/Attack_surface[attack surface]. -+Method security ensures that, if someone has bypassed the web authorization rules, your application is still secured. -+This is known as https://en.wikipedia.org/wiki/Defense_in_depth_(computing)[Defense in Depth] - ==== - - Consider a controller that is mapped as follows: - -+==== - [source,java] - ---- - @RequestMapping("/admin") - public String admin() { -+ ... -+} - ---- -+==== - --If we wanted to restrict access to this controller method to admin users, a developer can provide authorization rules by matching on the `HttpServletRequest` with the following: -+To restrict access to this controller method to admin users, you can provide authorization rules by matching on the `HttpServletRequest` with the following: - -+==== - [source,java] - ---- - protected configure(HttpSecurity http) throws Exception { -@@ -107,27 +116,30 @@ protected configure(HttpSecurity http) throws Exception { - ); - } - ---- -+==== - --or in XML -+The following listing does the same thing in XML: - -+==== - [source,xml] - ---- - - - - ---- -+==== - --With either configuration, the URL `/admin` will require the authenticated user to be an admin user. --However, depending on our Spring MVC configuration, the URL `/admin.html` will also map to our `admin()` method. --Additionally, depending on our Spring MVC configuration, the URL `/admin/` will also map to our `admin()` method. -+With either configuration, the `/admin` URL requires the authenticated user to be an admin user. -+However, depending on our Spring MVC configuration, the `/admin.html` URL also maps to our `admin()` method. -+Additionally, depending on our Spring MVC configuration, the `/admin` URL also maps to our `admin()` method. - --The problem is that our security rule is only protecting `/admin`. -+The problem is that our security rule protects only `/admin`. - We could add additional rules for all the permutations of Spring MVC, but this would be quite verbose and tedious. - --Instead, we can leverage Spring Security's `MvcRequestMatcher`. --The following configuration will protect the same URLs that Spring MVC will match on by using Spring MVC to match on the URL. -- -+Instead, we can use Spring Security's `MvcRequestMatcher`. -+The following configuration protects the same URLs that Spring MVC matches on by using Spring MVC to match on the URL. - -+==== - [source,java] - ---- - protected configure(HttpSecurity http) throws Exception { -@@ -137,24 +149,27 @@ protected configure(HttpSecurity http) throws Exception { - ); - } - ---- -+==== - --or in XML -+The following XML has the same effect: - -+==== - [source,xml] - ---- - - - - ---- -+==== - - [[mvc-authentication-principal]] - === @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. --If you use XML based configuration, you must add this yourself. --For example: -+Spring Security provides `AuthenticationPrincipalArgumentResolver`, which can automatically resolve the current `Authentication.getPrincipal()` for Spring MVC arguments. -+By using `@EnableWebSecurity`, you automatically have this added to your Spring MVC configuration. -+If you use XML-based configuration, you must add this yourself: - -+==== - [source,xml] - ---- - -@@ -163,11 +178,13 @@ For example: - - - ---- -+==== - --Once `AuthenticationPrincipalArgumentResolver` is properly configured, you can be entirely decoupled from Spring Security in your Spring MVC layer. -+Once you have properly configured `AuthenticationPrincipalArgumentResolver`, you can entirely decouple from Spring Security in your Spring MVC layer. - --Consider a situation where a custom `UserDetailsService` that returns an `Object` that implements `UserDetails` and your own `CustomUser` `Object`. The `CustomUser` of the currently authenticated user could be accessed using the following code: -+Consider a situation where a custom `UserDetailsService` returns an `Object` that implements `UserDetails` and your own `CustomUser` `Object`. The `CustomUser` of the currently authenticated user could be accessed by using the following code: - -+==== - [source,java] - ---- - @RequestMapping("/messages/inbox") -@@ -179,9 +196,11 @@ public ModelAndView findMessagesForUser() { - // .. find messages for this user and return them ... - } - ---- -+==== - --As of Spring Security 3.2 we can resolve the argument more directly by adding an annotation. For example: -+As of Spring Security 3.2, we can resolve the argument more directly by adding an annotation: - -+==== - [source,java] - ---- - import org.springframework.security.core.annotation.AuthenticationPrincipal; -@@ -194,12 +213,13 @@ public ModelAndView findMessagesForUser(@AuthenticationPrincipal CustomUser cust - // .. find messages for this user and return them ... - } - ---- -+==== - --Sometimes it may be necessary to transform the principal in some way. --For example, if `CustomUser` needed to be final it could not be extended. --In this situation the `UserDetailsService` might returns an `Object` that implements `UserDetails` and provides a method named `getCustomUser` to access `CustomUser`. --For example, it might look like: -+Sometimes, you may need to transform the principal in some way. -+For example, if `CustomUser` needed to be final, it could not be extended. -+In this situation, the `UserDetailsService` might return an `Object` that implements `UserDetails` and provides a method named `getCustomUser` to access `CustomUser`: - -+==== - [source,java] - ---- - public class CustomUserUserDetails extends User { -@@ -209,9 +229,11 @@ public class CustomUserUserDetails extends User { - } - } - ---- -+==== - --We could then access the `CustomUser` using a https://docs.spring.io/spring/docs/current/spring-framework-reference/html/expressions.html[SpEL expression] that uses `Authentication.getPrincipal()` as the root object: -+We could then access the `CustomUser` by using a https://docs.spring.io/spring/docs/current/spring-framework-reference/html/expressions.html[SpEL expression] that uses `Authentication.getPrincipal()` as the root object: - -+==== - [source,java] - ---- - import org.springframework.security.core.annotation.AuthenticationPrincipal; -@@ -224,10 +246,12 @@ public ModelAndView findMessagesForUser(@AuthenticationPrincipal(expression = "c - // .. find messages for this user and return them ... - } - ---- -+==== - --We can also refer to Beans in our SpEL expressions. --For example, the following could be used if we were using JPA to manage our Users and we wanted to modify and save a property on the current user. -+We can also refer to beans in our SpEL expressions. -+For example, we could use the following if we were using JPA to manage our users and if we wanted to modify and save a property on the current user: - -+==== - [source,java] - ---- - import org.springframework.security.core.annotation.AuthenticationPrincipal; -@@ -244,13 +268,15 @@ public ModelAndView updateName(@AuthenticationPrincipal(expression = "@jpaEntity - // ... - } - ---- -+==== - --We can further remove our dependency on Spring Security by making `@AuthenticationPrincipal` a meta annotation on our own annotation. --Below we demonstrate how we could do this on an annotation named `@CurrentUser`. -+We can further remove our dependency on Spring Security by making `@AuthenticationPrincipal` a meta-annotation on our own annotation. -+The next example demonstrates how we could do so on an annotation named `@CurrentUser`. - --NOTE: It is important to realize that in order to remove the dependency on Spring Security, it is the consuming application that would create `@CurrentUser`. --This step is not strictly required, but assists in isolating your dependency to Spring Security to a more central location. -+NOTE: To remove the dependency on Spring Security, it is the consuming application that would create `@CurrentUser`. -+This step is not strictly required but assists in isolating your dependency to Spring Security to a more central location. - -+==== - [source,java] - ---- - @Target({ElementType.PARAMETER, ElementType.TYPE}) -@@ -259,10 +285,12 @@ This step is not strictly required, but assists in isolating your dependency to - @AuthenticationPrincipal - public @interface CurrentUser {} - ---- -+==== - --Now that `@CurrentUser` has been specified, we can use it to signal to resolve our `CustomUser` of the currently authenticated user. --We have also isolated our dependency on Spring Security to a single file. -+We have isolated our dependency on Spring Security to a single file. -+Now that `@CurrentUser` has been specified, we can use it to signal to resolve our `CustomUser` of the currently authenticated user: - -+==== - [source,java] - ---- - @RequestMapping("/messages/inbox") -@@ -271,15 +299,16 @@ public ModelAndView findMessagesForUser(@CurrentUser CustomUser customUser) { - // .. find messages for this user and return them ... - } - ---- -- -+==== - - [[mvc-async]] - === 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. --For example, the following method will automatically have its `Callable` invoked with the `SecurityContext` that was available when the `Callable` was created: -+With no additional configuration, Spring Security automatically sets up the `SecurityContext` to the `Thread` that invokes a `Callable` returned by your controllers. -+For example, the following method automatically has its `Callable` invoked with the `SecurityContext` that was available when the `Callable` was created: - -+==== - [source,java] - ---- - @RequestMapping(method=RequestMethod.POST) -@@ -293,26 +322,27 @@ return new Callable() { - }; - } - ---- -+==== - --[NOTE] - .Associating SecurityContext to Callable's --==== --More technically speaking, Spring Security integrates with `WebAsyncManager`. --The `SecurityContext` that is used to process the `Callable` is the `SecurityContext` that exists on the `SecurityContextHolder` at the time `startCallableProcessing` is invoked. --==== -+NOTE: More technically speaking, Spring Security integrates with `WebAsyncManager`. -+The `SecurityContext` that is used to process the `Callable` is the `SecurityContext` that exists on the `SecurityContextHolder` when `startCallableProcessing` is invoked. - - There is no automatic integration with a `DeferredResult` that is returned by controllers. --This is because `DeferredResult` is processed by the users and thus there is no way of automatically integrating with it. -+This is because `DeferredResult` is processed by the users and, thus, there is no way of automatically integrating with it. - However, you can still use <> to provide transparent integration with Spring Security. - - [[mvc-csrf]] - === Spring MVC and CSRF Integration - -+Spring Security integrates with Spring MVC to add CSRF protection. -+ - ==== Automatic Token Inclusion - --Spring Security will automatically <> 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: -+Spring Security automatically <> within forms that use the https://docs.spring.io/spring-framework/docs/current/reference/html/web.html#mvc-view-jsp-formtaglib[Spring MVC form tag]. -+Consider the following JSP: - -+==== - [source,xml] - ---- - - - ---- -+==== - --Will output HTML that is similar to the following: -+The preceding example output HTMLs that is similar to the following: - -+==== - [source,xml] - ---- - -@@ -350,16 +382,18 @@ Will output HTML that is similar to the following: - - - ---- -+==== - - [[mvc-csrf-resolver]] - ==== Resolving the CsrfToken - --Spring Security provides `CsrfTokenArgumentResolver` which can automatically resolve the current `CsrfToken` for Spring MVC arguments. --By using <> you will automatically have this added to your Spring MVC configuration. --If you use XML based configuration, you must add this yourself. -+Spring Security provides `CsrfTokenArgumentResolver`, which can automatically resolve the current `CsrfToken` for Spring MVC arguments. -+By using <>, you automatically have this added to your Spring MVC configuration. -+If you use XML-based configuration, you must add this yourself. - --Once `CsrfTokenArgumentResolver` is properly configured, you can expose the `CsrfToken` to your static HTML based application. -+Once `CsrfTokenArgumentResolver` is properly configured, you can expose the `CsrfToken` to your static HTML based application: - -+==== - [source,java] - ---- - @RestController -@@ -371,6 +405,7 @@ public class CsrfController { - } - } - ---- -+==== - - It is important to keep the `CsrfToken` a secret from other domains. --This means if you are using https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS[Cross Origin Sharing (CORS)], you should **NOT** expose the `CsrfToken` to any external domains. -+This means that, if you use https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS[Cross Origin Sharing (CORS)], you should *NOT* expose the `CsrfToken` to any external domains. -diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/servlet-api.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/servlet-api.adoc -index 5e4077c3f9..c2a4f0a47e 100644 ---- a/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/servlet-api.adoc -+++ b/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/servlet-api.adoc -@@ -6,24 +6,26 @@ This section describes how Spring Security is integrated with the Servlet API. - [[servletapi-25]] - === Servlet 2.5+ Integration - -+This section describes how Spring Security integrates with the Servlet 2.5 specification. -+ - - [[servletapi-remote-user]] - ==== 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. -+https://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletRequest.html#getRemoteUser()[`HttpServletRequest.getRemoteUser()`] returns 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. --Knowing if the user is authenticated or not can be useful for determining if certain UI elements should be shown or not (i.e. a log out link should only be displayed if the user is authenticated). -+Additionally, you can check this for null to determine whether a user has authenticated or is anonymous. -+Knowing whether the user is authenticated or not can be useful for determining if certain UI elements should be shown or not (for example, a logout link that should be displayed only if the user is authenticated). - - - [[servletapi-user-principal]] - ==== 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. -+https://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletRequest.html#getUserPrincipal()[`HttpServletRequest.getUserPrincipal()`] returns the result of `SecurityContextHolder.getContext().getAuthentication()`. -+This means that 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. - For example, you might have created a custom `UserDetailsService` that returns a custom `UserDetails` containing a first and last name for your user. - You could obtain this information with the following: - -- -+==== - [source,java] - ---- - Authentication auth = httpServletRequest.getUserPrincipal(); -@@ -33,43 +35,44 @@ MyCustomUserDetails userDetails = (MyCustomUserDetails) auth.getPrincipal(); - String firstName = userDetails.getFirstName(); - String lastName = userDetails.getLastName(); - ---- -- --[NOTE] --==== --It should be noted that it is typically bad practice to perform so much logic throughout your application. --Instead, one should centralize it to reduce any coupling of Spring Security and the Servlet API's. - ==== - -+NOTE: It is typically bad practice to perform logic throughout your application. -+Instead, you should centralize it to reduce any coupling of Spring Security and the Servlet API. -+ - [[servletapi-user-in-role]] - ==== 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. -+https://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletRequest.html#isUserInRole(java.lang.String)[`HttpServletRequest.isUserInRole(String)`] determines if `SecurityContextHolder.getContext().getAuthentication().getAuthorities()` contains a `GrantedAuthority` with the role passed into `isUserInRole(String)`. -+Typically, users should not pass the `ROLE_` prefix to 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: - -+==== - [source,java] - ---- - boolean isAdmin = httpServletRequest.isUserInRole("ADMIN"); - ---- -+==== - - 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 --The following section describes the Servlet 3 methods that Spring Security integrates with. -+The following section describes the Servlet 3 methods with which Spring Security integrates. - - - [[servletapi-authenticate]] - ==== 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). -+You can use the https://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletRequest.html#authenticate%28javax.servlet.http.HttpServletResponse%29[`HttpServletRequest.authenticate(HttpServletRequest,HttpServletResponse)`] method to ensure that a user is authenticated. -+If they are not authenticated, the configured `AuthenticationEntryPoint` is used to request the user to authenticate (redirect to the login page). - - - [[servletapi-login]] - ==== 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": -+You can use 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 to authenticate the user with the current `AuthenticationManager`. -+For example, the following would attempt to authenticate with a username of `user` and a password of `password`: - -+==== - [source,java] - ---- - try { -@@ -78,27 +81,26 @@ httpServletRequest.login("user","password"); - // fail to authenticate - } - ---- -- --[NOTE] --==== --It is not necessary to catch the ServletException if you want Spring Security to process the failed authentication attempt. - ==== - -+NOTE: You need not catch the `ServletException` if you want Spring Security to process the failed authentication attempt. -+ - [[servletapi-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. -+You can use the https://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletRequest.html#logout%28%29[`HttpServletRequest.logout()`] method to log out the current user. - --Typically this means that the SecurityContextHolder will be cleared out, the HttpSession will be invalidated, any "Remember Me" authentication will be cleaned up, etc. --However, the configured LogoutHandler implementations will vary depending on your Spring Security configuration. --It is important to note that after HttpServletRequest.logout() has been invoked, you are still in charge of writing a response out. --Typically this would involve a redirect to the welcome page. -+Typically, this means that the `SecurityContextHolder` is cleared out, the `HttpSession` is invalidated, any "`Remember Me`" authentication is cleaned up, and so on. -+However, the configured `LogoutHandler` implementations vary, depending on your Spring Security configuration. -+Note that, after `HttpServletRequest.logout()` has been invoked, you are still in charge of writing out a response. -+Typically, this would involve a redirect to the welcome page. - - [[servletapi-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: -+The https://docs.oracle.com/javaee/6/api/javax/servlet/AsyncContext.html#start%28java.lang.Runnable%29[`AsyncContext.start(Runnable)`] method ensures your credentials are propagated to the new `Thread`. -+By using Spring Security's concurrency support, Spring Security overrides `AsyncContext.start(Runnable)` to ensure that the current `SecurityContext` is used when processing the Runnable. -+The following example outputs the current user's Authentication: - -+==== - [source,java] - ---- - final AsyncContext async = httpServletRequest.startAsync(); -@@ -116,13 +118,15 @@ async.start(new Runnable() { - } - }); - ---- -+==== - - [[servletapi-async]] - ==== 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: -+If you use Java-based configuration, you are ready to go. -+If you use XML configuration, a few updates are necessary. -+The first step is to ensure that you have updated your `web.xml` file to use at least the 3.0 schema: - -+==== - [source,xml] - ---- - - - - ---- -+==== - --Next you need to ensure that your springSecurityFilterChain is setup for processing asynchronous requests. -+Next, you need to ensure that your `springSecurityFilterChain` is set up for processing asynchronous requests: - -+==== - [source,xml] - ---- - -@@ -151,16 +157,17 @@ Next you need to ensure that your springSecurityFilterChain is setup for process - ASYNC -
- ---- -+==== - --That's it! --Now Spring Security will ensure that your SecurityContext is propagated on asynchronous requests too. -+Now Spring Security ensures that your `SecurityContext` is propagated on asynchronous requests, too. - --So how does it work? If you are not really interested, feel free to skip the remainder of this section, otherwise read on. --Most of this is built into the Servlet specification, but there is a little bit of tweaking that Spring Security does to ensure things work with asynchronous requests properly. --Prior to Spring Security 3.2, the SecurityContext from the SecurityContextHolder was automatically saved as soon as the HttpServletResponse was committed. --This can cause issues in an Async environment. --For example, consider the following: -+So how does it work? If you are not really interested, feel free to skip the remainder of this section -+Most of this is built into the Servlet specification, but there is a little bit of tweaking that Spring Security does to ensure things work properly with asynchronous requests. -+Prior to Spring Security 3.2, the `SecurityContext` from the `SecurityContextHolder` was automatically saved as soon as the `HttpServletResponse` was committed. -+This can cause issues in an asynchronous environment. -+Consider the following example: - -+==== - [source,java] - ---- - httpServletRequest.startAsync(); -@@ -179,12 +186,13 @@ new Thread("AsyncThread") { - } - }.start(); - ---- -+==== - --The issue is that this Thread is not known to Spring Security, so the SecurityContext is not propagated to it. --This means when we commit the HttpServletResponse there is no SecurityContext. --When Spring Security automatically saved the SecurityContext on committing the HttpServletResponse it would lose our logged in user. -+The issue is that this `Thread` is not known to Spring Security, so the `SecurityContext` is not propagated to it. -+This means that, when we commit the `HttpServletResponse`, there is no `SecurityContext`. -+When Spring Security automatically saved the `SecurityContext` on committing the `HttpServletResponse`, it would lose a logged in user. - --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. -+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 -@@ -192,4 +200,4 @@ The following section describes the Servlet 3.1 methods that Spring Security int - - [[servletapi-change-session-id]] - ==== 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 <> attacks in Servlet 3.1 and higher. -+https://docs.oracle.com/javaee/7/api/javax/servlet/http/HttpServletRequest.html#changeSessionId()[`HttpServletRequest.changeSessionId()`] is the default method for protecting against <> attacks in Servlet 3.1 and higher. -diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/websocket.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/websocket.adoc -index ffcf46b5a4..b785fe5f8c 100644 ---- a/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/websocket.adoc -+++ b/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/websocket.adoc -@@ -6,18 +6,18 @@ This section describes how to use Spring Security's WebSocket support. - - .Direct JSR-356 Support - **** --Spring Security does not provide direct JSR-356 support because doing so would provide little value. --This is because the format is unknown, so there is https://docs.spring.io/spring/docs/current/spring-framework-reference/html/websocket.html#websocket-intro-sub-protocol[little Spring can do to secure an unknown format]. --Additionally, JSR-356 does not provide a way to intercept messages, so security would be rather invasive. -+Spring Security does not provide direct JSR-356 support, because doing so would provide little value. -+This is because the format is unknown, and there is https://docs.spring.io/spring/docs/current/spring-framework-reference/html/websocket.html#websocket-intro-sub-protocol[little Spring can do to secure an unknown format]. -+Additionally, JSR-356 does not provide a way to intercept messages, so security would be invasive. - **** - - [[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`. --For example: -+To configure authorization by using Java Configuration, extend the `AbstractSecurityWebSocketMessageBrokerConfigurer` and configure the `MessageSecurityMetadataSourceRegistry`: - -+==== - [source,java] - ---- - @Configuration -@@ -30,16 +30,15 @@ public class WebSocketSecurityConfig - } - } - ---- -- --This will ensure that: -- --<1> Any inbound CONNECT message requires a valid CSRF token to enforce <> --<2> The SecurityContextHolder is populated with the user within the simpUser header attribute for any inbound request. --<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 <> -+<1> Any inbound CONNECT message requires a valid CSRF token to enforce the <>. -+<2> The `SecurityContextHolder` is populated with the user within the `simpUser` header attribute for any inbound request. -+<3> Our messages require the proper authorization. Specifically, any inbound message that starts with `/user/` will requires `ROLE_USER`. You can find additional details on authorization in <> -+==== - - Spring Security also provides <> support for securing WebSockets. - A comparable XML based configuration looks like the following: - -+==== - [source,xml] - ---- - -@@ -47,29 +46,27 @@ A comparable XML based configuration looks like the following: - - - ---- -- --This will ensure that: -- --<1> Any inbound CONNECT message requires a valid CSRF token to enforce <> --<2> The SecurityContextHolder is populated with the user within the simpUser header attribute for any inbound request. --<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 <> -+<1> Any inbound CONNECT message requires a valid CSRF token to enforce the <>. -+<2> The `SecurityContextHolder` is populated with the user within the `simpUser` header attribute for any inbound request. -+<3> Our messages require the proper authorization. Specifically, any inbound message that starts with `/user/` require `ROLE_USER`. You can find additional details on authorization in <>. -+==== - - [[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. --If you are using Spring Security, the `Principal` on the `HttpServletRequest` is overridden automatically. -+This means that the `Principal` on the `HttpServletRequest` is handed off to WebSockets. -+If you use Spring Security, the `Principal` on the `HttpServletRequest` is overridden automatically. - --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. -+More concretely, to ensure a user has authenticated to your WebSocket application, all you need to do is ensure that you set up Spring Security to authenticate your HTTP based web application. - - [[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`. --For example: -+To configure authorization by using Java configuration, extend the `AbstractSecurityWebSocketMessageBrokerConfigurer` and configure the `MessageSecurityMetadataSourceRegistry`: - -+==== - [source,java] - ---- - @Configuration -@@ -88,19 +85,18 @@ public class WebSocketSecurityConfig extends AbstractSecurityWebSocketMessageBro - } - } - ---- -- --This will ensure that: -- --<1> Any message without a destination (i.e. anything other than Message type of MESSAGE or SUBSCRIBE) will require the user to be authenticated --<2> Anyone can subscribe to /user/queue/errors --<3> Any message that has a destination starting with "/app/" will be require the user to have the role ROLE_USER --<4> Any message that starts with "/user/" or "/topic/friends/" that is of type SUBSCRIBE will require ROLE_USER --<5> Any other message of type MESSAGE or SUBSCRIBE is rejected. Due to 6 we do not need this step, but it illustrates how one can match on specific message types. --<6> Any other Message is rejected. This is a good idea to ensure that you do not miss any messages. -+<1> Any message without a destination (anything other than message type of `MESSAGE` or `SUBSCRIBE`) requires the user to be authenticated. -+<2> Anyone can subscribe to `/user/queue/errors`. -+<3> Any message that has a destination starting with `/app/` requires the user to have a role of `ROLE_USER`. -+<4> Any message that starts with `/user/` or `/topic/friends/` that is of type `SUBSCRIBE` requires `ROLE_USER`. -+<5> Any other message of type `MESSAGE` or `SUBSCRIBE` is rejected. Due to 6, we do not need this step, but it illustrates how you can match on specific message types. -+<6> Any other message is rejected. This is a good idea to ensure that you do not miss any messages. -+==== - - Spring Security also provides <> support for securing WebSockets. - A comparable XML based configuration looks like the following: - -+==== - [source,xml] - ---- - -@@ -123,115 +119,117 @@ A comparable XML based configuration looks like the following: - - - ---- -- --This will ensure that: -- --<1> Any message of type CONNECT, UNSUBSCRIBE, or DISCONNECT will require the user to be authenticated -+<1> Any message of type `CONNECT`, `UNSUBSCRIBE`, or `DISCONNECT` requires the user to be authenticated. - <2> Anyone can subscribe to /user/queue/errors - <3> Any message that has a destination starting with "/app/" will be require the user to have the role ROLE_USER - <4> Any message that starts with "/user/" or "/topic/friends/" that is of type SUBSCRIBE will require ROLE_USER - <5> Any other message of type MESSAGE or SUBSCRIBE is rejected. Due to 6 we do not need this step, but it illustrates how one can match on specific message types. - <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 - --In order to properly secure your application it is important to understand Spring's WebSocket support. -+To properly secure your application, you need to understand Spring's WebSocket support. - - [[websocket-authorization-notes-messagetypes]] - ===== 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. -+You need to understand the distinction between `SUBSCRIBE` and `MESSAGE` types of messages and how they work within Spring. - --Consider a chat application. -+Consider a chat application: - --* The system can send notifications MESSAGE to all users through a destination of "/topic/system/notifications" --* Clients can receive notifications by SUBSCRIBE to the "/topic/system/notifications". -+* The system can send a notification `MESSAGE` to all users through a destination of `/topic/system/notifications`. -+* Clients can receive notifications by `SUBSCRIBE` to the `/topic/system/notifications`. - --While we want clients to be able to SUBSCRIBE to "/topic/system/notifications", we do not want to enable them to send a MESSAGE to that destination. --If we allowed sending a MESSAGE to "/topic/system/notifications", then clients could send a message directly to that endpoint and impersonate the system. -+While we want clients to be able to `SUBSCRIBE` to `/topic/system/notifications`, we do not want to enable them to send a `MESSAGE` to that destination. -+If we allowed sending a `MESSAGE` to `/topic/system/notifications`, clients could send a message directly to that endpoint and impersonate the system. - --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/"). -+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] (`/topic/` or `/queue/`). - - [[websocket-authorization-notes-destinations]] - ===== WebSocket Authorization on Destinations - --It is also is important to understand how destinations are transformed. -+You should also understand how destinations are transformed. - --Consider a chat application. -+Consider a chat application: - --* Users can send messages to a specific user by sending a message to the destination of "/app/chat". --* The application sees the message, ensures that the "from" attribute is specified as the current user (we cannot trust the client). --* The application then sends the message to the recipient using `SimpMessageSendingOperations.convertAndSendToUser("toUser", "/queue/messages", message)`. --* The message gets turned into the destination of "/queue/user/messages-" -+* Users can send messages to a specific user by sending a message to the `/app/chat` destination. -+* The application sees the message, ensures that the `from` attribute is specified as the current user (we cannot trust the client). -+* The application then sends the message to the recipient by using `SimpMessageSendingOperations.convertAndSendToUser("toUser", "/queue/messages", message)`. -+* The message gets turned into the destination of `/queue/user/messages-`. - --With the application above, we want to allow our client to listen to "/user/queue" which is transformed into "/queue/user/messages-". --However, we do not want the client to be able to listen to "/queue/*" because that would allow the client to see messages for every user. -+With this chat application, we want to let our client to listen `/user/queue`, which is transformed into `/queue/user/messages-`. -+However, we do not want the client to be able to listen to `/queue/*`, because that would let the client see messages for every user. - --In general, it is common for applications to deny any SUBSCRIBE sent to a message 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/"). --Of course we may provide exceptions to account for things like -+In general, it is common for applications to deny any `SUBSCRIBE` sent to a message that starts with the https://docs.spring.io/spring/docs/current/spring-framework-reference/html/websocket.html#websocket-stomp[broker prefix] (`/topic/` or `/queue/`). -+We may provide exceptions to account for things like -+//FIXME: Like what? - - [[websocket-authorization-notes-outbound]] - ==== 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`. -+The Spring Framework reference documentation 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. -+Note that Spring Security secures only the `clientInboundChannel`. - Spring Security does not attempt to secure the `clientOutboundChannel`. - - The most important reason for this is performance. --For every message that goes in, there are typically many more that go out. -+For every message that goes in, typically many more go out. - Instead of securing the outbound messages, we encourage securing the subscription to the endpoints. - - [[websocket-sameorigin]] - === 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. -+Note 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? - - Consider the following scenario. --A user visits bank.com and authenticates to their account. --The same user opens another tab in their browser and visits evil.com. --The Same Origin Policy ensures that evil.com cannot read or write data to bank.com. -+A user visits `bank.com` and authenticates to their account. -+The same user opens another tab in their browser and visits `evil.com`. -+The Same Origin Policy ensures that `evil.com` cannot read data from or write data to `bank.com`. - --With WebSockets the Same Origin Policy does not apply. --In fact, unless bank.com explicitly forbids it, evil.com can read and write data on behalf of the user. --This means that anything the user can do over the webSocket (i.e. transfer money), evil.com can do on that users behalf. -+With WebSockets, the Same Origin Policy does not apply. -+In fact, unless `bank.com` explicitly forbids it, `evil.com` can read and write data on behalf of the user. -+This means that anything the user can do over the webSocket (such as transferring money), `evil.com` can do on that user's behalf. - --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. -+Since SockJS tries to emulate WebSockets, it also bypasses the Same Origin Policy. -+This means that developers need to explicitly protect their applications from external domains when they use SockJS. - - [[websocket-sameorigin-spring]] - ==== 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_%2528computing%2529[defence in depth]. -+Spring Security adds an additional layer of protection to provide https://en.wikipedia.org/wiki/Defence_in_depth_(non-military)#Information_security[defense in depth]. - - [[websocket-sameorigin-csrf]] - ==== Adding CSRF to Stomp Headers - --By default Spring Security requires the <> in any CONNECT message type. -+By default, Spring Security requires the <> in any `CONNECT` message type. - This ensures that only a site that has access to the CSRF token can connect. --Since only the *Same Origin* can access the CSRF token, external domains are not allowed to make a connection. -+Since only the *same origin* can access the CSRF token, external domains are not allowed to make a connection. - - Typically we need to include the CSRF token in an HTTP header or an HTTP parameter. - However, SockJS does not allow for these options. --Instead, we must include the token in the Stomp headers -+Instead, we must include the token in the Stomp headers. - --Applications can <> by accessing the request attribute named _csrf. --For example, the following will allow accessing the `CsrfToken` in a JSP: -+Applications can <> by accessing the request attribute named `_csrf`. -+For example, the following allows accessing the `CsrfToken` in a JSP: - -+==== - [source,javascript] - ---- - var headerName = "${_csrf.headerName}"; - var token = "${_csrf.token}"; - ---- -+==== - --If you are using static HTML, you can expose the `CsrfToken` on a REST endpoint. --For example, the following would expose the `CsrfToken` on the URL /csrf -+If you use static HTML, you can expose the `CsrfToken` on a REST endpoint. -+For example, the following would expose the `CsrfToken` on the `/csrf` URL: - -+==== - [source,java] - ---- - @RestController -@@ -243,29 +241,30 @@ public class CsrfController { - } - } - ---- -+==== - --The JavaScript can make a REST call to the endpoint and use the response to populate the headerName and the token. -+The JavaScript can make a REST call to the endpoint and use the response to populate the `headerName` and the token. - --We can now include the token in our Stomp client. --For example: -+We can now include the token in our Stomp client: - -+==== - [source,javascript] - ---- --... - var headers = {}; - headers[headerName] = token; - stompClient.connect(headers, function(frame) { - ... -- --} -+}) - ---- -+==== - - [[websocket-sameorigin-disable]] - ==== 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: -+If you want to let other domains access your site, you can disable Spring Security's protection. -+For example, in Java configuration you can use the following: - -+==== - [source,java] - ---- - @Configuration -@@ -279,24 +278,25 @@ public class WebSocketSecurityConfig extends AbstractSecurityWebSocketMessageBro - } - } - ---- -- -+==== - - [[websocket-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. -+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 may use an https://github.com/sockjs/sockjs-client/tree/v0.3.4[transport that leverages an iframe]. --By default Spring Security will <> the site from being framed to prevent Clickjacking attacks. --To allow SockJS frame based transports to work, we need to configure Spring Security to allow the same origin to frame the content. -+SockJS may use a https://github.com/sockjs/sockjs-client/tree/v0.3.4[transport that leverages an iframe]. -+By default, Spring Security <> the site from being framed to prevent clickjacking attacks. -+To allow SockJS frame-based transports to work, we need to configure Spring Security to let the same origin frame the content. - --You can customize X-Frame-Options with the <> element. --For example, the following will instruct Spring Security to use "X-Frame-Options: SAMEORIGIN" which allows iframes within the same domain: -+You can customize `X-Frame-Options` with the <> element. -+For example, the following instructs Spring Security to use `X-Frame-Options: SAMEORIGIN`, which allows iframes within the same domain: - -+==== - [source,xml] - ---- - -@@ -308,9 +308,11 @@ For example, the following will instruct Spring Security to use "X-Frame-Options - - - ---- -+==== - --Similarly, you can customize frame options to use the same origin within Java Configuration using the following: -+Similarly, you can customize frame options to use the same origin within Java Configuration by using the following: - -+==== - [source,java] - ---- - @EnableWebSecurity -@@ -329,24 +331,26 @@ public class WebSecurityConfig extends - } - } - ---- -+==== - - [[websocket-sockjs-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. -+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. - However, SockJS does not allow for these options. - Instead, we must include the token in the Stomp headers as described in <>. - --It also means we need to relax our CSRF protection with the web layer. -+It also means that we need to relax our CSRF protection with the web layer. - Specifically, we want to disable CSRF protection for our connect URLs. - We do NOT want to disable CSRF protection for every URL. --Otherwise our site will be vulnerable to CSRF attacks. -+Otherwise, our site is vulnerable to CSRF attacks. - --We can easily achieve this by providing a CSRF RequestMatcher. --Our Java Configuration makes this extremely easy. --For example, if our stomp endpoint is "/chat" we can disable CSRF protection for only URLs that start with "/chat/" using the following configuration: -+We can easily achieve this by providing a CSRF `RequestMatcher`. -+Our Java configuration makes this easy. -+For example, if our stomp endpoint is `/chat`, we can disable CSRF protection only for URLs that start with `/chat/` by using the following configuration: - -+==== - [source,java] - ---- - @Configuration -@@ -371,11 +375,14 @@ public class WebSecurityConfig - ... - ) - ... -+ } -+ } - ---- -+==== - --If we are using XML based configuration, we can use the <>. --For example: -+If we use XML-based configuration, we can use the <>: - -+==== - [source,xml] - ---- - -@@ -400,3 +407,4 @@ For example: - - - ---- -+==== -diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/java-configuration/index.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/java-configuration/index.adoc -index 3ba5432ddc..56cff5437a 100644 ---- a/docs/manual/src/docs/asciidoc/_includes/servlet/java-configuration/index.adoc -+++ b/docs/manual/src/docs/asciidoc/_includes/servlet/java-configuration/index.adoc -@@ -1,21 +1,21 @@ -- - [[jc]] - = Java Configuration - --General support for https://docs.spring.io/spring/docs/3.1.x/spring-framework-reference/html/beans.html#beans-java[Java Configuration] was added to Spring Framework in Spring 3.1. --Since Spring Security 3.2 there has been Spring Security Java Configuration support which enables users to easily configure Spring Security without the use of any XML. -+General support for https://docs.spring.io/spring/docs/3.1.x/spring-framework-reference/html/beans.html#beans-java[Java configuration] was added to Spring Framework in Spring 3.1. -+Spring Security 3.2 introduced Java configuration to let users configure Spring Security without the use of any XML. - --If you are familiar with the <> then you should find quite a few similarities between it and the Security Java Configuration support. -+If you are familiar with the <>, you should find quite a few similarities between it and Spring Security Java configuration. - - NOTE: Spring Security provides https://github.com/spring-projects/spring-security-samples/tree/main/servlet/java-configuration[lots of sample applications] which demonstrate the use of Spring Security Java Configuration. - - == Hello Web Security Java Configuration - - The first step is to create our Spring Security Java Configuration. --The configuration creates a Servlet Filter known as the `springSecurityFilterChain` which is responsible for all the security (protecting the application URLs, validating submitted username and passwords, redirecting to the log in form, etc) within your application. --You can find the most basic example of a Spring Security Java Configuration below: -+The configuration creates a Servlet Filter known as the `springSecurityFilterChain`, which is responsible for all the security (protecting the application URLs, validating submitted username and passwords, redirecting to the log in form, and so on) within your application. -+The following example shows the most basic example of a Spring Security Java Configuration: - - [[jc-hello-wsca]] -+==== - [source,java] - ---- - import org.springframework.beans.factory.annotation.Autowired; -@@ -35,44 +35,44 @@ public class WebSecurityConfig { - } - } - ---- -+==== - --There really isn't much to this configuration, but it does a lot. --You can find a summary of the features below: -+This configuration is not complex or extensive, but it does a lot: - - * Require authentication to every URL in your application - * Generate a login form for you --* Allow the user with the *Username* _user_ and the *Password* _password_ to authenticate with form based authentication --* Allow the user to logout -+* Let the user with a *Username* of `user` and a *Password* of `password` authenticate with form based authentication -+* Let the user logout - * https://en.wikipedia.org/wiki/Cross-site_request_forgery[CSRF attack] prevention - * https://en.wikipedia.org/wiki/Session_fixation[Session Fixation] protection --* Security Header integration -+* Security Header integration: - ** https://en.wikipedia.org/wiki/HTTP_Strict_Transport_Security[HTTP Strict Transport Security] for secure requests - ** https://msdn.microsoft.com/en-us/library/ie/gg622941(v=vs.85).aspx[X-Content-Type-Options] integration --** Cache Control (can be overridden later by your application to allow caching of your static resources) -+** Cache Control (which you can override later in your application to allow caching of your static resources) - ** https://msdn.microsoft.com/en-us/library/dd565647(v=vs.85).aspx[X-XSS-Protection] integration - ** X-Frame-Options integration to help prevent https://en.wikipedia.org/wiki/Clickjacking[Clickjacking] --* Integrate with the following Servlet API methods --** https://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletRequest.html#getRemoteUser()[HttpServletRequest#getRemoteUser()] --** https://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletRequest.html#getUserPrincipal()[HttpServletRequest#getUserPrincipal()] --** https://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletRequest.html#isUserInRole(java.lang.String)[HttpServletRequest#isUserInRole(java.lang.String)] --** https://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletRequest.html#login(java.lang.String,%20java.lang.String)[HttpServletRequest#login(java.lang.String, java.lang.String)] --** https://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletRequest.html#logout()[HttpServletRequest#logout()] -+* Integration with the following Servlet API methods: -+** https://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletRequest.html#getRemoteUser()[`HttpServletRequest#getRemoteUser()`] -+** https://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletRequest.html#getUserPrincipal()[`HttpServletRequest#getUserPrincipal()`] -+** https://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletRequest.html#isUserInRole(java.lang.String)[`HttpServletRequest#isUserInRole(java.lang.String)`] -+** https://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletRequest.html#login(java.lang.String,%20java.lang.String)[`HttpServletRequest#login(java.lang.String, java.lang.String)`] -+** https://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletRequest.html#logout()[`HttpServletRequest#logout()`] - - === AbstractSecurityWebApplicationInitializer - --The next step is to register the `springSecurityFilterChain` with the war. --This can be done in Java Configuration with https://docs.spring.io/spring/docs/3.2.x/spring-framework-reference/html/mvc.html#mvc-container-config[Spring's WebApplicationInitializer support] in a Servlet 3.0+ environment. --Not suprisingly, Spring Security provides a base class `AbstractSecurityWebApplicationInitializer` that will ensure the `springSecurityFilterChain` gets registered for you. -+The next step is to register the `springSecurityFilterChain` with the WAR file. -+You can do so in Java configuration with https://docs.spring.io/spring/docs/3.2.x/spring-framework-reference/html/mvc.html#mvc-container-config[Spring's `WebApplicationInitializer` support] in a Servlet 3.0+ environment. -+Not surprisingly, Spring Security provides a base class (`AbstractSecurityWebApplicationInitializer`) to ensure that the `springSecurityFilterChain` gets registered for you. - The way in which we use `AbstractSecurityWebApplicationInitializer` differs depending on if we are already using Spring or if Spring Security is the only Spring component in our application. - --* <> - Use these instructions if you are not using Spring already -+* <> - Use these instructions if you are not already using Spring - * <> - Use these instructions if you are already using Spring - - === AbstractSecurityWebApplicationInitializer without Existing Spring - --If you are not using Spring or Spring MVC, you will need to pass in the `WebSecurityConfig` into the superclass to ensure the configuration is picked up. --You can find an example below: -+If you are not using Spring or Spring MVC, you need to pass the `WebSecurityConfig` to the superclass to ensure the configuration is picked up: - -+==== - [source,java] - ---- - import org.springframework.security.web.context.*; -@@ -85,19 +85,21 @@ public class SecurityWebApplicationInitializer - } - } - ---- -+==== - --The `SecurityWebApplicationInitializer` will do the following things: -+The `SecurityWebApplicationInitializer`: - --* Automatically register the springSecurityFilterChain Filter for every URL in your application --* Add a ContextLoaderListener that loads the <>. -+* Automatically registers the `springSecurityFilterChain` Filter for every URL in your application. -+* Add a `ContextLoaderListener` that loads the <>. - - === AbstractSecurityWebApplicationInitializer with Spring MVC - --If we were using Spring elsewhere in our application we probably already had a `WebApplicationInitializer` that is loading our Spring Configuration. --If we use the previous configuration we would get an error. -+If we use Spring elsewhere in our application, we probably already have a `WebApplicationInitializer` that is loading our Spring Configuration. -+If we use the previous configuration, we would get an error. - Instead, we should register Spring Security with the existing `ApplicationContext`. --For example, if we were using Spring MVC our `SecurityWebApplicationInitializer` would look something like the following: -+For example, if we use Spring MVC, our `SecurityWebApplicationInitializer` could look something like the following: - -+==== - [source,java] - ---- - import org.springframework.security.web.context.*; -@@ -107,12 +109,14 @@ public class SecurityWebApplicationInitializer - - } - ---- -+==== - --This would simply only register the springSecurityFilterChain Filter for every URL in your application. --After that we would ensure that `WebSecurityConfig` was loaded in our existing ApplicationInitializer. --For example, if we were using Spring MVC it would be added in the `getRootConfigClasses()` -+This onlys register the `springSecurityFilterChain` for every URL in your application. -+After that, we need to ensure that `WebSecurityConfig` was loaded in our existing `ApplicationInitializer`. -+For example, if we use Spring MVC it is added in the `getRootConfigClasses()`: - - [[message-web-application-inititializer-java]] -+==== - [source,java] - ---- - public class MvcWebApplicationInitializer extends -@@ -126,16 +130,18 @@ public class MvcWebApplicationInitializer extends - // ... other overrides ... - } - ---- -+==== - - [[jc-httpsecurity]] - == HttpSecurity - --Thus far our <> only contains information about how to authenticate our users. -+Thus far, our <> contains only information about how to authenticate our users. - How does Spring Security know that we want to require all users to be authenticated? --How does Spring Security know we want to support form based authentication? --Actually, there is a configuration class that is being invoked behind the scenes called `WebSecurityConfigurerAdapter`. -+How does Spring Security know we want to support form-based authentication? -+Actually, there is a configuration class (called `WebSecurityConfigurerAdapter`) that is being invoked behind the scenes. - It has a method called `configure` with the following default implementation: - -+==== - [source,java] - ---- - protected void configure(HttpSecurity http) throws Exception { -@@ -147,15 +153,17 @@ protected void configure(HttpSecurity http) throws Exception { - .httpBasic(withDefaults()); - } - ---- -+==== - --The default configuration above: -+The default configuration (shown in the preceding example): - - * Ensures that any request to our application requires the user to be authenticated --* Allows users to authenticate with form based login --* Allows users to authenticate with HTTP Basic authentication -+* Lets users authenticate with form based login -+* Lets users authenticate with HTTP Basic authentication - --You will notice that this configuration is quite similar the XML Namespace configuration: -+Note that this configuration is parallels the XML Namespace configuration: - -+==== - [source,xml] - ---- - -@@ -164,13 +172,15 @@ You will notice that this configuration is quite similar the XML Namespace confi - - - ---- -+==== - --== Multiple HttpSecurity -+== Multiple HttpSecurity Instances - --We can configure multiple HttpSecurity instances just as we can have multiple `` blocks. -+We can configure multiple `HttpSecurity` instances just as we can have multiple `` blocks in XML. - The key is to extend the `WebSecurityConfigurerAdapter` multiple times. --For example, the following is an example of having a different configuration for URL's that start with `/api/`. -+The following example has a different configuration for URL's that start with `/api/`. - -+==== - [source,java] - ---- - @EnableWebSecurity -@@ -213,19 +223,20 @@ public class MultiHttpSecurityConfig { - } - ---- - --<1> Configure Authentication as normal -+<1> Configure Authentication as usual. - <2> Create an instance of `WebSecurityConfigurerAdapter` that contains `@Order` to specify which `WebSecurityConfigurerAdapter` should be considered first. --<3> The `http.antMatcher` states that this `HttpSecurity` will only be applicable to URLs that start with `/api/` -+<3> The `http.antMatcher` states that this `HttpSecurity` is applicable only to URLs that start with `/api/`. - <4> Create another instance of `WebSecurityConfigurerAdapter`. --If the URL does not start with `/api/` this configuration will be used. --This configuration is considered after `ApiWebSecurityConfigurationAdapter` since it has an `@Order` value after `1` (no `@Order` defaults to last). -+If the URL does not start with `/api/`, this configuration is used. -+This configuration is considered after `ApiWebSecurityConfigurationAdapter`, since it has an `@Order` value after `1` (no `@Order` defaults to last). -+==== - - [[jc-custom-dsls]] - == Custom DSLs - --You can provide your own custom DSLs in Spring Security. --For example, you might have something that looks like this: -+You can provide your own custom DSLs in Spring Security: - -+==== - [source,java] - ---- - public class MyCustomDsl extends AbstractHttpConfigurer { -@@ -258,11 +269,13 @@ public class MyCustomDsl extends AbstractHttpConfigurer -@@ -43,14 +46,17 @@ You will notice that this configuration is quite similar the XML Namespace confi - - - ---- -+==== - --== Multiple HttpSecurity -+== Multiple HttpSecurity Instances - --We can configure multiple HttpSecurity instances just as we can have multiple `` blocks. -+We can configure multiple HttpSecurity instances, just as we can have multiple `` blocks. - The key is to extend the `WebSecurityConfigurerAdapter` multiple times. --For example, the following is an example of having a different configuration for URL's that start with `/api/`. -+The following example has a different configuration for URL's that start with `/api/`: - --[source,kotlin] -+// The source is Kotlin, but we specify Java to get code formatting. At present, Asciidoctor doesnt' have a Kotlin formatter. -+==== -+[source,java] - ---- - @EnableWebSecurity - class MultiHttpSecurityConfig { -@@ -91,9 +97,10 @@ class MultiHttpSecurityConfig { - } - ---- - --<1> Configure Authentication as normal -+<1> Configure Authentication as usual. - <2> Create an instance of `WebSecurityConfigurerAdapter` that contains `@Order` to specify which `WebSecurityConfigurerAdapter` should be considered first. --<3> The `http.antMatcher` states that this `HttpSecurity` will only be applicable to URLs that start with `/api/` -+<3> The `http.antMatcher` states that this `HttpSecurity` is applicable only to URLs that start with `/api/` - <4> Create another instance of `WebSecurityConfigurerAdapter`. --If the URL does not start with `/api/` this configuration will be used. --This configuration is considered after `ApiWebSecurityConfigurationAdapter` since it has an `@Order` value after `1` (no `@Order` defaults to last). -+If the URL does not start with `/api/`, this configuration is used. -+This configuration is considered after `ApiWebSecurityConfigurationAdapter`, since it has an `@Order` value after `1` (no `@Order` defaults to last). -+==== -diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/namespace/index.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/namespace/index.adoc -index 58c7687cc9..fc427d14cc 100644 ---- a/docs/manual/src/docs/asciidoc/_includes/servlet/namespace/index.adoc -+++ b/docs/manual/src/docs/asciidoc/_includes/servlet/namespace/index.adoc -@@ -2,30 +2,30 @@ - [[ns-config]] - = Security Namespace Configuration - -- --== Introduction - Namespace configuration has been available since version 2.0 of the Spring Framework. --It allows you to supplement the traditional Spring beans application context syntax with elements from additional XML schema. -+It lets you supplement the traditional Spring beans application context syntax with elements from additional XML schema. - You can find more information in the Spring https://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/[Reference Documentation]. --A namespace element can be used simply to allow a more concise way of configuring an individual bean or, more powerfully, to define an alternative configuration syntax which more closely matches the problem domain and hides the underlying complexity from the user. --A simple element may conceal the fact that multiple beans and processing steps are being added to the application context. --For example, adding the following element from the security namespace to an application context will start up an embedded LDAP server for testing use within the application: -+You can use a namespace element to more concisely configure an individual bean or, more powerfully, to define an alternative configuration syntax that more closely matches the problem domain and hides the underlying complexity from the user. -+A simple element can conceal the fact that multiple beans and processing steps are being added to the application context. -+For example, adding the following element from the `security` namespace to an application context starts up an embedded LDAP server for testing use within the application: - -+==== - [source,xml] - ---- - - ---- -+==== - - This is much simpler than wiring up the equivalent Apache Directory Server beans. --The most common alternative configuration requirements are supported by attributes on the `ldap-server` element and the user is isolated from worrying about which beans they need to create and what the bean property names are. --footnote:[You can find out more about the use of the `ldap-server` element in the chapter on pass:specialcharacters,macros[<>].]. --Use of a good XML editor while editing the application context file should provide information on the attributes and elements that are available. --We would recommend that you try out the https://spring.io/tools/sts[Spring Tool Suite] as it has special features for working with standard Spring namespaces. -+The most common alternative configuration requirements are supported by attributes on the `ldap-server` element, and the user is isolated from worrying about which beans they need to create and what the bean property names are. -+You can find out more about the use of the `ldap-server` element in the chapter on <>. -+A good XML editor while editing the application context file should provide information on the attributes and elements that are available. -+We recommend that you try the https://spring.io/tools/sts[Spring Tool Suite], as it has special features for working with standard Spring namespaces. - -+To start using the `security` namespace in your application context, add the `spring-security-config` jar to your classpath. -+Then, all you need to do is add the schema declaration to your application context file: - --To start using the security namespace in your application context, you need to have the `spring-security-config` jar on your classpath. --Then all you need to do is add the schema declaration to your application context file: -- -+==== - [source,xml] - ---- - ` element. -+Once you have added this bean to your `web.xml`, you are ready to start editing your application context file. -+Web security services are configured by the `` element. - - [[ns-minimal]] - === A Minimal Configuration --All you need to enable web security to begin with is - -+To enable web security, you need the following configuration: -+ -+==== - [source,xml] - ---- - -@@ -123,31 +130,33 @@ All you need to enable web security to begin with is - - - ---- -+==== -+ -+That listing says that we want: -+ -+* All URLs within our application to be secured, requiring the role `ROLE_USER` to access them -+* To log in to the application using a form with username and password -+* A logout URL registered which will allow us to log out of the application - --Which says that we want all URLs within our application to be secured, requiring the role `ROLE_USER` to access them, we want to log in to the application using a form with username and password, and that we want a logout URL registered which will allow us to log out of the application. --`` element is the parent for all web-related namespace functionality. --The `` element defines a `pattern` which is matched against the URLs of incoming requests using an ant path style syntax footnote:[See the section on pass:specialcharacters,macros[<>] for more details on how matches are actually performed.]. -+The `` element is the parent for all web-related namespace functionality. -+The `` element defines a `pattern`, which is matched against the URLs of incoming requests using Ant path syntax. See the section on <> for more details on how matches are actually performed. - You can also use regular-expression matching as an alternative (see the namespace appendix for more details). --The `access` attribute defines the access requirements for requests matching the given pattern. -+The `access` attribute defines the access requirements for requests that match the given pattern. - With the default configuration, this is typically a comma-separated list of roles, one of which a user must have to be allowed to make the request. --The prefix "ROLE_" is a marker which indicates that a simple comparison with the user's authorities should be made. -+The `ROLE_` prefix is a marker that indicates that a simple comparison with the user's authorities should be made. - In other words, a normal role-based check should be used. - Access-control in Spring Security is not limited to the use of simple roles (hence the use of the prefix to differentiate between different types of security attributes). --We'll see later how the interpretation can vary footnote:[The interpretation of the comma-separated values in the `access` attribute depends on the implementation of the <> which is used.]. --In Spring Security 3.0, the attribute can also be populated with an <>. -+We see later how the interpretation can vary. The interpretation of the comma-separated values in the `access` attribute depends on the which implementation of the <> is used. -+Since Spring Security 3.0, you can also populate the attribute with an <>. - - --[NOTE] --==== -- --You can use multiple `` elements to define different access requirements for different sets of URLs, but they will be evaluated in the order listed and the first match will be used. -+NOTE: You can use multiple `` elements to define different access requirements for different sets of URLs, but they are evaluated in the order listed and the first match is used. - So you must put the most specific matches at the top. --You can also add a `method` attribute to limit the match to a particular HTTP method (`GET`, `POST`, `PUT` etc.). -- --==== -+You can also add a `method` attribute to limit the match to a particular HTTP method (`GET`, `POST`, `PUT`, and so on). - --To add some users, you can define a set of test data directly in the namespace: -+To add users, you can define a set of test data directly in the namespace: - -+==== - [source,xml,attrs="-attributes"] - ---- - -@@ -162,10 +171,12 @@ To add some users, you can define a set of test data directly in the namespace: - - - ---- -+==== - --This is an example of a secure way of storing the same passwords. -+The preceding listing shows an example of a secure way to store the same passwords. - The password is prefixed with `+{bcrypt}+` to instruct `DelegatingPasswordEncoder`, which supports any configured `PasswordEncoder` for matching, that the passwords are hashed using BCrypt: - -+==== - [source,xml,attrs="-attributes"] - ---- - -@@ -181,37 +192,36 @@ The password is prefixed with `+{bcrypt}+` to instruct `DelegatingPasswordEncode - - - ---- -- -- -+==== - - [subs="quotes"] - **** --If you are familiar with pre-namespace versions of the framework, you can probably already guess roughly what's going on here. --The `` element is responsible for creating a `FilterChainProxy` and the filter beans which it uses. --Common problems like incorrect filter ordering are no longer an issue as the filter positions are predefined. -+The `` element is responsible for creating a `FilterChainProxy` and the filter beans that it uses. -+Previously common problems, such as incorrect filter ordering, are no longer an issue, as the filter positions are predefined. - --The `` element creates a `DaoAuthenticationProvider` bean and the `` element creates an `InMemoryDaoImpl`. -+The `` element creates a `DaoAuthenticationProvider` bean, and the `` element creates an `InMemoryDaoImpl`. - All `authentication-provider` elements must be children of the `` element, which creates a `ProviderManager` and registers the authentication providers with it. - You can find more detailed information on the beans that are created in the <>. --It's worth cross-checking this if you want to start understanding what the important classes in the framework are and how they are used, particularly if you want to customise things later. -+You should cross-check this appendix if you want to start understanding what the important classes in the framework are and how they are used, particularly if you want to customize things later. - **** - --The configuration above defines two users, their passwords and their roles within the application (which will be used for access control). --It is also possible to load user information from a standard properties file using the `properties` attribute on `user-service`. -+The preceding configuration defines two users, their passwords, and their roles within the application (which are used for access control). -+You can also possible load user information from a standard properties file by setting the `properties` attribute on the `user-service` element. - See the section on <> for more details on the file format. --Using the `` element means that the user information will be used by the authentication manager to process authentication requests. --You can have multiple `` elements to define different authentication sources and each will be consulted in turn. -+Using the `` element means that the user information is used by the authentication manager to process authentication requests. -+You can have multiple `` elements to define different authentication sources. Each is consulted in turn. - --At this point you should be able to start up your application and you will be required to log in to proceed. --Try it out, or try experimenting with the "tutorial" sample application that comes with the project. -+At this point, you should be able to start up your application, and you should be required to log in to proceed. -+Try it out, or try experimenting with the "`tutorial`" sample application that comes with the project. - - [[ns-form-target]] - ==== Setting a Default Post-Login Destination --If a form login isn't prompted by an attempt to access a protected resource, the `default-target-url` option comes into play. --This is the URL the user will be taken to after successfully logging in, and defaults to "/". --You can also configure things so that the user __always__ ends up at this page (regardless of whether the login was "on-demand" or they explicitly chose to log in) by setting the `always-use-default-target` attribute to "true". --This is useful if your application always requires that the user starts at a "home" page, for example: -+If a form login is not prompted by an attempt to access a protected resource, the `default-target-url` option comes into play. -+This is the URL to which the user is taken after successfully logging in. it defaults to `/`. -+You can also configure things so that the user _always_ ends up at this page (regardless of whether the login was "`on-demand`" or they explicitly chose to log in) by setting the `always-use-default-target` attribute to `true`. -+This is useful if your application always requires that the user starts at a "`home`" page, for example: - -+==== - [source,xml] - ---- - -@@ -221,6 +231,7 @@ This is useful if your application always requires that the user starts at a "ho - always-use-default-target='true' /> - - ---- -+==== - - For even more control over the destination, you can use the `authentication-success-handler-ref` attribute as an alternative to `default-target-url`. - The referenced bean should be an instance of `AuthenticationSuccessHandler`. -@@ -228,25 +239,24 @@ The referenced bean should be an instance of `AuthenticationSuccessHandler`. - [[ns-web-advanced]] - == Advanced Web Features - -+This section covers various features that go beyond the basics. -+ - [[ns-custom-filters]] --=== Adding in Your Own Filters --If you've used Spring Security before, you'll know that the framework maintains a chain of filters in order to apply its services. --You may want to add your own filters to the stack at particular locations or use a Spring Security filter for which there isn't currently a namespace configuration option (CAS, for example). --Or you might want to use a customized version of a standard namespace filter, such as the `UsernamePasswordAuthenticationFilter` which is created by the `` element, taking advantage of some of the extra configuration options which are available by using the bean explicitly. -+=== Adding Your Own Filters -+If you have used Spring Security before, you know that the framework maintains a chain of filters that it uses to apply its services. -+You may want to add your own filters to the stack at particular locations or use a Spring Security filter for which there is not currently a namespace configuration option (CAS, for example). -+// FIXME: Is it still true that there is no CAS filter? -+Alternatively, you might want to use a customized version of a standard namespace filter, such as the `UsernamePasswordAuthenticationFilter` (which is created by the `` element) to take advantage of some of the extra configuration options that are available when you use the bean explicitly. - How can you do this with namespace configuration, since the filter chain is not directly exposed? - --The order of the filters is always strictly enforced when using the namespace. --When the application context is being created, the filter beans are sorted by the namespace handling code and the standard Spring Security filters each have an alias in the namespace and a well-known position. -+The order of the filters is always strictly enforced when you use the namespace. -+When the application context is being created, the filter beans are sorted by the namespace handling code, and the standard Spring Security filters each have an alias in the namespace and a well-known position. - --[NOTE] --==== --In previous versions, the sorting took place after the filter instances had been created, during post-processing of the application context. --In version 3.0+ the sorting is now done at the bean metadata level, before the classes have been instantiated. --This has implications for how you add your own filters to the stack as the entire filter list must be known during the parsing of the `` element, so the syntax has changed slightly in 3.0. --==== -+NOTE: In previous versions, the sorting took place after the filter instances had been created, during post-processing of the application context. -+In version 3.0+, the sorting is now done at the bean metadata level, before the classes have been instantiated. -+This has implications for how you add your own filters to the stack, as the entire filter list must be known during the parsing of the `` element. As a result, the syntax changed slightly in version 3.0. - --The filters, aliases and namespace elements/attributes which create the filters are shown in <>. --The filters are listed in the order in which they occur in the filter chain. -+The filters, aliases, and namespace elements and attributes that create the filters are shown in the following table, in the order in which they occur in the filter chain: - - [[filter-stack]] - .Standard Filter Aliases and Ordering -@@ -330,8 +340,9 @@ The filters are listed in the order in which they occur in the filter chain. - | N/A - |=== - --You can add your own filter to the stack, using the `custom-filter` element and one of these names to specify the position your filter should appear at: -+You can add your own filter to the stack by using the `custom-filter` element and one of these names to specify the position at which your filter should appear: - -+==== - [source,xml] - ---- - -@@ -340,40 +351,39 @@ You can add your own filter to the stack, using the `custom-filter` element and - - - ---- -+==== - - You can also use the `after` or `before` attributes if you want your filter to be inserted before or after another filter in the stack. --The names "FIRST" and "LAST" can be used with the `position` attribute to indicate that you want your filter to appear before or after the entire stack, respectively. -+You can use `FIRST` and `LAST` with the `position` attribute to indicate that you want your filter to appear before or after the entire stack, respectively. - - .Avoiding filter position conflicts - [TIP] - ==== -+If you insert a custom filter that may occupy the same position as one of the standard filters created by the namespace, you should not include the namespace versions by mistake. -+Remove any elements that create filters whose functionality you want to replace. - --If you are inserting a custom filter which may occupy the same position as one of the standard filters created by the namespace then it's important that you don't include the namespace versions by mistake. --Remove any elements which create filters whose functionality you want to replace. -- --Note that you can't replace filters which are created by the use of the `` element itself - `SecurityContextPersistenceFilter`, `ExceptionTranslationFilter` or `FilterSecurityInterceptor`. -+Note that you cannot replace filters that are created by the use of the `` element itself: `SecurityContextPersistenceFilter`, `ExceptionTranslationFilter`, or `FilterSecurityInterceptor`. - Some other filters are added by default, but you can disable them. --An `AnonymousAuthenticationFilter` is added by default and unless you have <> disabled, a `SessionManagementFilter` will also be added to the filter chain. -+By default, an `AnonymousAuthenticationFilter` is added and unless you have <> disabled, a `SessionManagementFilter` is also added to the filter chain. - - ==== - --If you're replacing a namespace filter which requires an authentication entry point (i.e. where the authentication process is triggered by an attempt by an unauthenticated user to access to a secured resource), you will need to add a custom entry point bean too. -- -+If you replace a namespace filter that requires an authentication entry point (that is, where the authentication process is triggered by an unauthenticated user's attempt to access to a secured resource), you need to add a custom entry-point bean too. - - - [[ns-method-security]] - == Method Security --From version 2.0 onwards Spring Security has improved support substantially for adding security to your service layer methods. -+Since version 2.0, Spring Security has substantial support 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 <>. --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. -+Since version 3.0, you can also make use of <>. -+You can apply security to a single bean (by 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. - - [[ns-access-manager]] - == The Default AccessDecisionManager --This section assumes you have some knowledge of the underlying architecture for access-control within Spring Security. --If you don't you can skip it and come back to it later, as this section is only really relevant for people who need to do some customization in order to use more than simple role-based security. -+This section assumes that you have some knowledge of the underlying architecture for access-control within Spring Security. -+If you do not, you can skip it and come back to it later, as this section is relevant only for people who need to do some customization to use more than simple role-based security. - --When you use a namespace configuration, a default instance of `AccessDecisionManager` is automatically registered for you and will be used for making access decisions for method invocations and web URL access, based on the access attributes you specify in your `intercept-url` and `protect-pointcut` declarations (and in annotations if you are using annotation secured methods). -+When you use a namespace configuration, a default instance of `AccessDecisionManager` is automatically registered for you and is used to make access decisions for method invocations and web URL access, based on the access attributes you specify in your `intercept-url` and `protect-pointcut` declarations (and in annotations, if you use annotations to secure methods). - - The default strategy is to use an `AffirmativeBased` `AccessDecisionManager` with a `RoleVoter` and an `AuthenticatedVoter`. - You can find out more about these in the chapter on <>. -@@ -381,22 +391,26 @@ You can find out more about these in the chapter on <> - - [[ns-custom-access-mgr]] - === Customizing the AccessDecisionManager --If you need to use a more complicated access control strategy then it is easy to set an alternative for both method and web security. -+If you need to use a more complicated access control strategy, you can set an alternative for both method and web security. - --For method security, you do this by setting the `access-decision-manager-ref` attribute on `global-method-security` to the `id` of the appropriate `AccessDecisionManager` bean in the application context: -+For method security, you do so by setting the `access-decision-manager-ref` attribute on `global-method-security` to the `id` of the appropriate `AccessDecisionManager` bean in the application context: - -+==== - [source,xml] - ---- - - ... - - ---- -+==== - --The syntax for web security is the same, but on the `http` element: -+The syntax for web security is the same, but the attribute is on the `http` element: - -+==== - [source,xml] - ---- - - ... - - ---- -+==== -diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/oauth2/index.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/oauth2/index.adoc -index 99ed0947d9..a26601205d 100644 ---- a/docs/manual/src/docs/asciidoc/_includes/servlet/oauth2/index.adoc -+++ b/docs/manual/src/docs/asciidoc/_includes/servlet/oauth2/index.adoc -@@ -1,5 +1,7 @@ - = OAuth2 - -+This section describes how Spring Security enables OAuth2. -+ - include::oauth2-login.adoc[] - - include::oauth2-client.adoc[] -diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/oauth2/oauth2-client.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/oauth2/oauth2-client.adoc -index 8b1a61f71d..ab5f8c0d61 100644 ---- a/docs/manual/src/docs/asciidoc/_includes/servlet/oauth2/oauth2-client.adoc -+++ b/docs/manual/src/docs/asciidoc/_includes/servlet/oauth2/oauth2-client.adoc -@@ -91,7 +91,7 @@ The following code shows the complete configuration options available in the <> --** <> --** <> --** <> --** <> --** <> -+** <> -+** <> -+** <> -+** <> -+** <> - * <> --** <> --** <> --** <> --** <> -+** <> -+** <> -+** <> -+** <> - * <> --** <> -+** <> - * <> - - - [[oauth2Client-core-interface-class]] --=== Core Interfaces / Classes -+=== Core Interfaces and Classes -+ -+This section describes the OAuth2 core interfaces and classes that Spring Security offers. - - - [[oauth2Client-client-registration]] -@@ -167,10 +169,11 @@ The following sections will go into more detail on the core components used by O - - `ClientRegistration` is a representation of a client registered with an OAuth 2.0 or OpenID Connect 1.0 Provider. - --A client registration holds information, such as client id, client secret, authorization grant type, redirect URI, scope(s), authorization URI, token URI, and other details. -+A `ClientRegistration` object holds information, such as client id, client secret, authorization grant type, redirect URI, scope(s), authorization URI, token URI, and other details. - - `ClientRegistration` and its properties are defined as follows: - -+==== - [source,java] - ---- - public final class ClientRegistration { -@@ -205,29 +208,30 @@ public final class ClientRegistration { - <2> `clientId`: The client identifier. - <3> `clientSecret`: The client secret. - <4> `clientAuthenticationMethod`: The method used to authenticate the Client with the Provider. --The supported values are *client_secret_basic*, *client_secret_post* and *none* https://tools.ietf.org/html/rfc6749#section-2.1[(public clients)]. -+The supported values are *client_secret_basic*, *client_secret_post*, and *none* https://tools.ietf.org/html/rfc6749#section-2.1[(public clients)]. - <5> `authorizationGrantType`: The OAuth 2.0 Authorization Framework defines four https://tools.ietf.org/html/rfc6749#section-1.3[Authorization Grant] types. -- The supported values are `authorization_code`, `client_credentials` and `password`. --<6> `redirectUri`: The client's registered redirect URI that the _Authorization Server_ redirects the end-user's user-agent -- to after the end-user has authenticated and authorized access to the client. -+Spring Security support `authorization_code`, `client_credentials` and `password`. -+<6> `redirectUri`: The client's registered redirect URI to which the _Authorization Server_ redirects the end-user's user-agent -+after the end-user has authenticated and authorized access to the client. - <7> `scopes`: The scope(s) requested by the client during the Authorization Request flow, such as openid, email, or profile. - <8> `clientName`: A descriptive name used for the client. - The name may be used in certain scenarios, such as when displaying the name of the client in the auto-generated login page. - <9> `authorizationUri`: The Authorization Endpoint URI for the Authorization Server. - <10> `tokenUri`: The Token Endpoint URI for the Authorization Server. - <11> `jwkSetUri`: The URI used to retrieve the https://tools.ietf.org/html/rfc7517[JSON Web Key (JWK)] Set from the Authorization Server, -- which contains the cryptographic key(s) used to verify the https://tools.ietf.org/html/rfc7515[JSON Web Signature (JWS)] of the ID Token and optionally the UserInfo Response. --<12> `issuerUri`: Returns the issuer identifier uri for the OpenID Connect 1.0 provider or the OAuth 2.0 Authorization Server. -+which contains the cryptographic key(s) used to verify the https://tools.ietf.org/html/rfc7515[JSON Web Signature (JWS)] of the ID Token and (optionally) the UserInfo Response. -+<12> `issuerUri`: Returns the issuer identifier URI for the OpenID Connect 1.0 provider or the OAuth 2.0 Authorization Server. - <13> `configurationMetadata`: The https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfig[OpenID Provider Configuration Information]. -- This information will only be available if the Spring Boot 2.x property `spring.security.oauth2.client.provider.[providerId].issuerUri` is configured. --<14> `(userInfoEndpoint)uri`: The UserInfo Endpoint URI used to access the claims/attributes of the authenticated end-user. -+ This information is available only if the Spring Boot 2.x property `spring.security.oauth2.client.provider.[providerId].issuerUri` is configured. -+<14> `(userInfoEndpoint)uri`: The UserInfo Endpoint URI used to access the claims and attributes of the authenticated end-user. - <15> `(userInfoEndpoint)authenticationMethod`: The authentication method used when sending the access token to the UserInfo Endpoint. --The supported values are *header*, *form* and *query*. -+The supported values are *header*, *form*, and *query*. - <16> `userNameAttributeName`: The name of the attribute returned in the UserInfo Response that references the Name or Identifier of the end-user. -+==== - --A `ClientRegistration` can be initially configured using discovery of an OpenID Connect Provider's https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfig[Configuration endpoint] or an Authorization Server's https://tools.ietf.org/html/rfc8414#section-3[Metadata endpoint]. -+You can initially configure a `ClientRegistration` by using discovery of an OpenID Connect Provider's https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfig[Configuration endpoint] or an Authorization Server's https://tools.ietf.org/html/rfc8414#section-3[Metadata endpoint]. - --`ClientRegistrations` provides convenience methods for configuring a `ClientRegistration` in this way, as can be seen in the following example: -+`ClientRegistrations` provides convenience methods for configuring a `ClientRegistration` in this way, as follows: - - ==== - .Java -@@ -244,25 +248,23 @@ val clientRegistration = ClientRegistrations.fromIssuerLocation("https://idp.exa - ---- - ==== - --The above code will query in series `https://idp.example.com/issuer/.well-known/openid-configuration`, and then `https://idp.example.com/.well-known/openid-configuration/issuer`, and finally `https://idp.example.com/.well-known/oauth-authorization-server/issuer`, stopping at the first to return a 200 response. -+The preceding code queries, in series, `https://idp.example.com/issuer/.well-known/openid-configuration`, `https://idp.example.com/.well-known/openid-configuration/issuer`, and `https://idp.example.com/.well-known/oauth-authorization-server/issuer`, stopping at the first to return a 200 response. - --As an alternative, you can use `ClientRegistrations.fromOidcIssuerLocation()` to only query the OpenID Connect Provider's Configuration endpoint. -+As an alternative, you can use `ClientRegistrations.fromOidcIssuerLocation()` to query only the OpenID Connect Provider's Configuration endpoint. - - [[oauth2Client-client-registration-repo]] - ==== ClientRegistrationRepository - - The `ClientRegistrationRepository` serves as a repository for OAuth 2.0 / OpenID Connect 1.0 `ClientRegistration`(s). - --[NOTE] --Client registration information is ultimately stored and owned by the associated Authorization Server. --This repository provides the ability to retrieve a sub-set of the primary client registration information, which is stored with the Authorization Server. -+NOTE: Client registration information is ultimately stored and owned by the associated Authorization Server. -+This repository provides the ability to retrieve a subset of the primary client registration information, which is stored with the Authorization Server. - - Spring Boot 2.x auto-configuration binds each of the properties under `spring.security.oauth2.client.registration._[registrationId]_` to an instance of `ClientRegistration` and then composes each of the `ClientRegistration` instance(s) within a `ClientRegistrationRepository`. - --[NOTE] --The default implementation of `ClientRegistrationRepository` is `InMemoryClientRegistrationRepository`. -+NOTE: The default implementation of `ClientRegistrationRepository` is `InMemoryClientRegistrationRepository`. - --The auto-configuration also registers the `ClientRegistrationRepository` as a `@Bean` in the `ApplicationContext` so that it is available for dependency-injection, if needed by the application. -+The auto-configuration also registers the `ClientRegistrationRepository` as a `@Bean` in the `ApplicationContext` so that it is available for dependency injection, if needed by the application. - - The following listing shows an example: - -@@ -314,18 +316,18 @@ class OAuth2ClientController { - ==== OAuth2AuthorizedClient - - `OAuth2AuthorizedClient` is a representation of an Authorized Client. --A client is considered to be authorized when the end-user (Resource Owner) has granted authorization to the client to access its protected resources. -+A client is considered to be authorized when the end-user (the Resource Owner) has granted authorization to the client to access its protected resources. - - `OAuth2AuthorizedClient` serves the purpose of associating an `OAuth2AccessToken` (and optional `OAuth2RefreshToken`) to a `ClientRegistration` (client) and resource owner, who is the `Principal` end-user that granted the authorization. - - - [[oauth2Client-authorized-repo-service]] --==== OAuth2AuthorizedClientRepository / OAuth2AuthorizedClientService -+==== OAuth2AuthorizedClientRepository and OAuth2AuthorizedClientService - --`OAuth2AuthorizedClientRepository` is responsible for persisting `OAuth2AuthorizedClient`(s) between web requests. --Whereas, the primary role of `OAuth2AuthorizedClientService` is to manage `OAuth2AuthorizedClient`(s) at the application-level. -+`OAuth2AuthorizedClientRepository` is responsible for persisting `OAuth2AuthorizedClient`(s) between web requests, -+whereas the primary role of `OAuth2AuthorizedClientService` is to manage `OAuth2AuthorizedClient`(s) at the application-level. - --From a developer perspective, the `OAuth2AuthorizedClientRepository` or `OAuth2AuthorizedClientService` provides the capability to lookup an `OAuth2AccessToken` associated with a client so that it may be used to initiate a protected resource request. -+From a developer perspective, the `OAuth2AuthorizedClientRepository` or `OAuth2AuthorizedClientService` provides the ability to look up an `OAuth2AccessToken` associated with a client so that it can be used to initiate a protected resource request. - - The following listing shows an example: - -@@ -376,37 +378,35 @@ class OAuth2ClientController { - ---- - ==== - --[NOTE] --Spring Boot 2.x auto-configuration registers an `OAuth2AuthorizedClientRepository` and/or `OAuth2AuthorizedClientService` `@Bean` in the `ApplicationContext`. --However, the application may choose to override and register a custom `OAuth2AuthorizedClientRepository` or `OAuth2AuthorizedClientService` `@Bean`. -+NOTE: Spring Boot 2.x auto-configuration registers an `OAuth2AuthorizedClientRepository` or an `OAuth2AuthorizedClientService` `@Bean` in the `ApplicationContext`. -+However, the application can override and register a custom `OAuth2AuthorizedClientRepository` or `OAuth2AuthorizedClientService` `@Bean`. - --The default implementation of `OAuth2AuthorizedClientService` is `InMemoryOAuth2AuthorizedClientService`, which stores `OAuth2AuthorizedClient`(s) in-memory. -+The default implementation of `OAuth2AuthorizedClientService` is `InMemoryOAuth2AuthorizedClientService`, which stores `OAuth2AuthorizedClient` objects in-memory. - --Alternatively, the JDBC implementation `JdbcOAuth2AuthorizedClientService` may be configured for persisting `OAuth2AuthorizedClient`(s) in a database. -+Alternatively, you can configure the JDBC implementation `JdbcOAuth2AuthorizedClientService` to persist `OAuth2AuthorizedClient` instances in a database. - --[NOTE] --`JdbcOAuth2AuthorizedClientService` depends on the table definition described in <>. -+NOTE: `JdbcOAuth2AuthorizedClientService` depends on the table definition described in <>. - - - [[oauth2Client-authorized-manager-provider]] --==== OAuth2AuthorizedClientManager / OAuth2AuthorizedClientProvider -+==== OAuth2AuthorizedClientManager and OAuth2AuthorizedClientProvider - - The `OAuth2AuthorizedClientManager` is responsible for the overall management of `OAuth2AuthorizedClient`(s). - - The primary responsibilities include: - --* Authorizing (or re-authorizing) an OAuth 2.0 Client, using an `OAuth2AuthorizedClientProvider`. --* Delegating the persistence of an `OAuth2AuthorizedClient`, typically using an `OAuth2AuthorizedClientService` or `OAuth2AuthorizedClientRepository`. -+* Authorizing (or re-authorizing) an OAuth 2.0 Client, by using an `OAuth2AuthorizedClientProvider`. -+* Delegating the persistence of an `OAuth2AuthorizedClient`, typically by using an `OAuth2AuthorizedClientService` or `OAuth2AuthorizedClientRepository`. - * Delegating to an `OAuth2AuthorizationSuccessHandler` when an OAuth 2.0 Client has been successfully authorized (or re-authorized). - * Delegating to an `OAuth2AuthorizationFailureHandler` when an OAuth 2.0 Client fails to authorize (or re-authorize). - - An `OAuth2AuthorizedClientProvider` implements a strategy for authorizing (or re-authorizing) an OAuth 2.0 Client. --Implementations will typically implement an authorization grant type, eg. `authorization_code`, `client_credentials`, etc. -+Implementations typically implement an authorization grant type, such as `authorization_code`, `client_credentials`, and others. - - The default implementation of `OAuth2AuthorizedClientManager` is `DefaultOAuth2AuthorizedClientManager`, which is associated with an `OAuth2AuthorizedClientProvider` that may support multiple authorization grant types using a delegation-based composite. --The `OAuth2AuthorizedClientProviderBuilder` may be used to configure and build the delegation-based composite. -+You can use `OAuth2AuthorizedClientProviderBuilder` to configure and build the delegation-based composite. - --The following code shows an example of how to configure and build an `OAuth2AuthorizedClientProvider` composite that provides support for the `authorization_code`, `refresh_token`, `client_credentials` and `password` authorization grant types: -+The following code shows an example of how to configure and build an `OAuth2AuthorizedClientProvider` composite that provides support for the `authorization_code`, `refresh_token`, `client_credentials`, and `password` authorization grant types: - - ==== - .Java -@@ -455,12 +455,12 @@ fun authorizedClientManager( - ---- - ==== - --When an authorization attempt succeeds, the `DefaultOAuth2AuthorizedClientManager` will delegate to the `OAuth2AuthorizationSuccessHandler`, which (by default) will save the `OAuth2AuthorizedClient` via the `OAuth2AuthorizedClientRepository`. --In the case of a re-authorization failure, eg. a refresh token is no longer valid, the previously saved `OAuth2AuthorizedClient` will be removed from the `OAuth2AuthorizedClientRepository` via the `RemoveAuthorizedClientOAuth2AuthorizationFailureHandler`. --The default behaviour may be customized via `setAuthorizationSuccessHandler(OAuth2AuthorizationSuccessHandler)` and `setAuthorizationFailureHandler(OAuth2AuthorizationFailureHandler)`. -+When an authorization attempt succeeds, the `DefaultOAuth2AuthorizedClientManager` delegates to the `OAuth2AuthorizationSuccessHandler`, which (by default) saves the `OAuth2AuthorizedClient` through the `OAuth2AuthorizedClientRepository`. -+In the case of a re-authorization failure (for example, a refresh token is no longer valid), the previously saved `OAuth2AuthorizedClient` is removed from the `OAuth2AuthorizedClientRepository` through the `RemoveAuthorizedClientOAuth2AuthorizationFailureHandler`. -+You can customize the default behavior through `setAuthorizationSuccessHandler(OAuth2AuthorizationSuccessHandler)` and `setAuthorizationFailureHandler(OAuth2AuthorizationFailureHandler)`. - - The `DefaultOAuth2AuthorizedClientManager` is also associated with a `contextAttributesMapper` of type `Function>`, which is responsible for mapping attribute(s) from the `OAuth2AuthorizeRequest` to a `Map` of attributes to be associated to the `OAuth2AuthorizationContext`. --This can be useful when you need to supply an `OAuth2AuthorizedClientProvider` with required (supported) attribute(s), eg. the `PasswordOAuth2AuthorizedClientProvider` requires the resource owner's `username` and `password` to be available in `OAuth2AuthorizationContext.getAttributes()`. -+This can be useful when you need to supply an `OAuth2AuthorizedClientProvider` with required (supported) attribute(s). For example, the `PasswordOAuth2AuthorizedClientProvider` requires the resource owner's `username` and `password` to be available in `OAuth2AuthorizationContext.getAttributes()`. - - The following code shows an example of the `contextAttributesMapper`: - -@@ -549,10 +549,10 @@ private fun contextAttributesMapper(): Function>. --This ensures that the `X-Forwarded-*` headers are used when expanding the `redirect-uri`. -+Doing so ensures that the `X-Forwarded-*` headers are used when expanding the `redirect-uri`. - - ===== Customizing the Authorization Request - -@@ -705,8 +709,7 @@ One of the primary use cases an `OAuth2AuthorizationRequestResolver` can realize - For example, OpenID Connect defines additional OAuth 2.0 request parameters for the https://openid.net/specs/openid-connect-core-1_0.html#AuthRequest[Authorization Code Flow] extending from the standard parameters defined in the https://tools.ietf.org/html/rfc6749#section-4.1.1[OAuth 2.0 Authorization Framework]. - One of those extended parameters is the `prompt` parameter. - --[NOTE] --OPTIONAL. Space delimited, case sensitive list of ASCII string values that specifies whether the Authorization Server prompts the End-User for reauthentication and consent. The defined values are: none, login, consent, select_account -+NOTE: The `prompt` parameter is optional. Space delimited, case sensitive list of ASCII string values that specifies whether the Authorization Server prompts the End-User for re-authentication and consent. The defined values are: `none`, `login`, `consent`, and `select_account`. - - The following example shows how to configure the `DefaultOAuth2AuthorizationRequestResolver` with a `Consumer` that customizes the Authorization Request for `oauth2Login()`, by including the request parameter `prompt=consent`. - -@@ -795,10 +798,11 @@ class SecurityConfig : WebSecurityConfigurerAdapter() { - ---- - ==== - --For the simple use case, where the additional request parameter is always the same for a specific provider, it may be added directly in the `authorization-uri` property. -+For the simple use case where the additional request parameter is always the same for a specific provider, you can add it directly in the `authorization-uri` property. - --For example, if the value for the request parameter `prompt` is always `consent` for the provider `okta`, than simply configure as follows: -+For example, if the value for the request parameter `prompt` is always `consent` for the provider `okta`, you can configure it as follows: - -+==== - [source,yaml] - ---- - spring: -@@ -809,14 +813,14 @@ spring: - okta: - authorization-uri: https://dev-1234.oktapreview.com/oauth2/v1/authorize?prompt=consent - ---- -+==== - - The preceding example shows the common use case of adding a custom parameter on top of the standard parameters. --Alternatively, if your requirements are more advanced, you can take full control in building the Authorization Request URI by simply overriding the `OAuth2AuthorizationRequest.authorizationRequestUri` property. -+Alternatively, if your requirements are more advanced, you can take full control in building the Authorization Request URI by overriding the `OAuth2AuthorizationRequest.authorizationRequestUri` property. - --[TIP] --`OAuth2AuthorizationRequest.Builder.build()` constructs the `OAuth2AuthorizationRequest.authorizationRequestUri`, which represents the Authorization Request URI including all query parameters using the `application/x-www-form-urlencoded` format. -+TIP: `OAuth2AuthorizationRequest.Builder.build()` constructs the `OAuth2AuthorizationRequest.authorizationRequestUri`, which represents the Authorization Request URI that includes all query parameters that use the `application/x-www-form-urlencoded` format. - --The following example shows a variation of `authorizationRequestCustomizer()` from the preceding example, and instead overrides the `OAuth2AuthorizationRequest.authorizationRequestUri` property. -+The following example shows a variation of `authorizationRequestCustomizer()` from the preceding example and instead overrides the `OAuth2AuthorizationRequest.authorizationRequestUri` property: - - ==== - .Java -@@ -849,12 +853,11 @@ private fun authorizationRequestCustomizer(): Consumer>`. --The default implementation `OAuth2AuthorizationCodeGrantRequestEntityConverter` builds a `RequestEntity` representation of a standard https://tools.ietf.org/html/rfc6749#section-4.1.3[OAuth 2.0 Access Token Request]. --However, providing a custom `Converter`, would allow you to extend the standard Token Request and add custom parameter(s). -+The default implementation (`OAuth2AuthorizationCodeGrantRequestEntityConverter`) builds a `RequestEntity` representation of a standard https://tools.ietf.org/html/rfc6749#section-4.1.3[OAuth 2.0 Access Token Request]. -+However, providing a custom `Converter` would let you extend the standard Token Request and add custom parameter(s). - - IMPORTANT: The custom `Converter` must return a valid `RequestEntity` representation of an OAuth 2.0 Access Token Request that is understood by the intended OAuth 2.0 Provider. - - - ===== Customizing the Access Token Response - --On the other end, if you need to customize the post-handling of the Token Response, you will need to provide `DefaultAuthorizationCodeTokenResponseClient.setRestOperations()` with a custom configured `RestOperations`. -+On the other end, if you need to customize the post-handling of the Token Response, you need to provide `DefaultAuthorizationCodeTokenResponseClient.setRestOperations()` with a custom configured `RestOperations`. - The default `RestOperations` is configured as follows: - - ==== -@@ -952,15 +954,15 @@ restTemplate.errorHandler = OAuth2ErrorResponseErrorHandler() - ---- - ==== - --TIP: Spring MVC `FormHttpMessageConverter` is required as it's used when sending the OAuth 2.0 Access Token Request. -+TIP: Spring MVC `FormHttpMessageConverter` is required, as it is used when sending the OAuth 2.0 Access Token Request. - --`OAuth2AccessTokenResponseHttpMessageConverter` is a `HttpMessageConverter` for an OAuth 2.0 Access Token Response. -+`OAuth2AccessTokenResponseHttpMessageConverter` is an `HttpMessageConverter` for an OAuth 2.0 Access Token Response. - You can provide `OAuth2AccessTokenResponseHttpMessageConverter.setTokenResponseConverter()` with a custom `Converter, OAuth2AccessTokenResponse>` that is used for converting the OAuth 2.0 Access Token Response parameters to an `OAuth2AccessTokenResponse`. - --`OAuth2ErrorResponseErrorHandler` is a `ResponseErrorHandler` that can handle an OAuth 2.0 Error, eg. 400 Bad Request. -+`OAuth2ErrorResponseErrorHandler` is a `ResponseErrorHandler` that can handle an OAuth 2.0 Error, such as `400 Bad Request`. - It uses an `OAuth2ErrorHttpMessageConverter` for converting the OAuth 2.0 Error parameters to an `OAuth2Error`. - --Whether you customize `DefaultAuthorizationCodeTokenResponseClient` or provide your own implementation of `OAuth2AccessTokenResponseClient`, you'll need to configure it as shown in the following example: -+Whether you customize `DefaultAuthorizationCodeTokenResponseClient` or provide your own implementation of `OAuth2AccessTokenResponseClient`, you need to configure it as follows: - - .Access Token Response Configuration - ==== -@@ -1016,32 +1018,30 @@ class OAuth2ClientSecurityConfig : WebSecurityConfigurerAdapter() { - [[oauth2Client-refresh-token-grant]] - ==== Refresh Token - --[NOTE] --Please refer to the OAuth 2.0 Authorization Framework for further details on the https://tools.ietf.org/html/rfc6749#section-1.5[Refresh Token]. -+NOTE: See the OAuth 2.0 Authorization Framework for further details on the https://tools.ietf.org/html/rfc6749#section-1.5[Refresh Token]. - - - ===== Refreshing an Access Token - --[NOTE] --Please refer to the https://tools.ietf.org/html/rfc6749#section-6[Access Token Request/Response] protocol flow for the Refresh Token grant. -+NOTE: See the https://tools.ietf.org/html/rfc6749#section-6[Access Token Request/Response] protocol flow for the Refresh Token grant. - - The default implementation of `OAuth2AccessTokenResponseClient` for the Refresh Token grant is `DefaultRefreshTokenTokenResponseClient`, which uses a `RestOperations` when refreshing an access token at the Authorization Server’s Token Endpoint. - --The `DefaultRefreshTokenTokenResponseClient` is quite flexible as it allows you to customize the pre-processing of the Token Request and/or post-handling of the Token Response. -+The `DefaultRefreshTokenTokenResponseClient` is flexible, as it lets you customize the pre-processing of the Token Request or post-handling of the Token Response. - - - ===== Customizing the Access Token Request - - If you need to customize the pre-processing of the Token Request, you can provide `DefaultRefreshTokenTokenResponseClient.setRequestEntityConverter()` with a custom `Converter>`. --The default implementation `OAuth2RefreshTokenGrantRequestEntityConverter` builds a `RequestEntity` representation of a standard https://tools.ietf.org/html/rfc6749#section-6[OAuth 2.0 Access Token Request]. --However, providing a custom `Converter`, would allow you to extend the standard Token Request and add custom parameter(s). -+The default implementation (`OAuth2RefreshTokenGrantRequestEntityConverter`) builds a `RequestEntity` representation of a standard https://tools.ietf.org/html/rfc6749#section-6[OAuth 2.0 Access Token Request]. -+However, providing a custom `Converter` would let you extend the standard Token Request and add custom parameter(s). - - IMPORTANT: The custom `Converter` must return a valid `RequestEntity` representation of an OAuth 2.0 Access Token Request that is understood by the intended OAuth 2.0 Provider. - - - ===== Customizing the Access Token Response - --On the other end, if you need to customize the post-handling of the Token Response, you will need to provide `DefaultRefreshTokenTokenResponseClient.setRestOperations()` with a custom configured `RestOperations`. -+On the other end, if you need to customize the post-handling of the Token Response, you need to provide `DefaultRefreshTokenTokenResponseClient.setRestOperations()` with a custom configured `RestOperations`. - The default `RestOperations` is configured as follows: - - ==== -@@ -1066,15 +1066,15 @@ restTemplate.errorHandler = OAuth2ErrorResponseErrorHandler() - ---- - ==== - --TIP: Spring MVC `FormHttpMessageConverter` is required as it's used when sending the OAuth 2.0 Access Token Request. -+TIP: Spring MVC `FormHttpMessageConverter` is required, as it is used when sending the OAuth 2.0 Access Token Request. - - `OAuth2AccessTokenResponseHttpMessageConverter` is a `HttpMessageConverter` for an OAuth 2.0 Access Token Response. - You can provide `OAuth2AccessTokenResponseHttpMessageConverter.setTokenResponseConverter()` with a custom `Converter, OAuth2AccessTokenResponse>` that is used for converting the OAuth 2.0 Access Token Response parameters to an `OAuth2AccessTokenResponse`. - --`OAuth2ErrorResponseErrorHandler` is a `ResponseErrorHandler` that can handle an OAuth 2.0 Error, eg. 400 Bad Request. -+`OAuth2ErrorResponseErrorHandler` is a `ResponseErrorHandler` that can handle an OAuth 2.0 Error, such as `400 Bad Request`. - It uses an `OAuth2ErrorHttpMessageConverter` for converting the OAuth 2.0 Error parameters to an `OAuth2Error`. - --Whether you customize `DefaultRefreshTokenTokenResponseClient` or provide your own implementation of `OAuth2AccessTokenResponseClient`, you'll need to configure it as shown in the following example: -+Whether you customize `DefaultRefreshTokenTokenResponseClient` or provide your own implementation of `OAuth2AccessTokenResponseClient`, you need to configure it as follows: - - ==== - .Java -@@ -1115,39 +1115,37 @@ authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider) - `OAuth2AuthorizedClientProviderBuilder.builder().refreshToken()` configures a `RefreshTokenOAuth2AuthorizedClientProvider`, - which is an implementation of an `OAuth2AuthorizedClientProvider` for the Refresh Token grant. - --The `OAuth2RefreshToken` may optionally be returned in the Access Token Response for the `authorization_code` and `password` grant types. --If the `OAuth2AuthorizedClient.getRefreshToken()` is available and the `OAuth2AuthorizedClient.getAccessToken()` is expired, it will automatically be refreshed by the `RefreshTokenOAuth2AuthorizedClientProvider`. -+The `OAuth2RefreshToken` can optionally be returned in the Access Token Response for the `authorization_code` and `password` grant types. -+If the `OAuth2AuthorizedClient.getRefreshToken()` is available and the `OAuth2AuthorizedClient.getAccessToken()` is expired, it is automatically refreshed by the `RefreshTokenOAuth2AuthorizedClientProvider`. - - - [[oauth2Client-client-creds-grant]] - ==== Client Credentials - --[NOTE] --Please refer to the OAuth 2.0 Authorization Framework for further details on the https://tools.ietf.org/html/rfc6749#section-1.3.4[Client Credentials] grant. -+NOTE: See the OAuth 2.0 Authorization Framework for further details on the https://tools.ietf.org/html/rfc6749#section-1.3.4[Client Credentials] grant. - - - ===== Requesting an Access Token - --[NOTE] --Please refer to the https://tools.ietf.org/html/rfc6749#section-4.4.2[Access Token Request/Response] protocol flow for the Client Credentials grant. -+NOTE: See the https://tools.ietf.org/html/rfc6749#section-4.4.2[Access Token Request/Response] protocol flow for the Client Credentials grant. - - The default implementation of `OAuth2AccessTokenResponseClient` for the Client Credentials grant is `DefaultClientCredentialsTokenResponseClient`, which uses a `RestOperations` when requesting an access token at the Authorization Server’s Token Endpoint. - --The `DefaultClientCredentialsTokenResponseClient` is quite flexible as it allows you to customize the pre-processing of the Token Request and/or post-handling of the Token Response. -+The `DefaultClientCredentialsTokenResponseClient` is flexible, as it lets you customize the pre-processing of the Token Request or post-handling of the Token Response. - - - ===== Customizing the Access Token Request - - If you need to customize the pre-processing of the Token Request, you can provide `DefaultClientCredentialsTokenResponseClient.setRequestEntityConverter()` with a custom `Converter>`. --The default implementation `OAuth2ClientCredentialsGrantRequestEntityConverter` builds a `RequestEntity` representation of a standard https://tools.ietf.org/html/rfc6749#section-4.4.2[OAuth 2.0 Access Token Request]. --However, providing a custom `Converter`, would allow you to extend the standard Token Request and add custom parameter(s). -+The default implementation (`OAuth2ClientCredentialsGrantRequestEntityConverter`) builds a `RequestEntity` representation of a standard https://tools.ietf.org/html/rfc6749#section-4.4.2[OAuth 2.0 Access Token Request]. -+However, providing a custom `Converter` would let you extend the standard Token Request and add custom parameter(s). - - IMPORTANT: The custom `Converter` must return a valid `RequestEntity` representation of an OAuth 2.0 Access Token Request that is understood by the intended OAuth 2.0 Provider. - - - ===== Customizing the Access Token Response - --On the other end, if you need to customize the post-handling of the Token Response, you will need to provide `DefaultClientCredentialsTokenResponseClient.setRestOperations()` with a custom configured `RestOperations`. -+On the other end, if you need to customize the post-handling of the Token Response, you need to provide `DefaultClientCredentialsTokenResponseClient.setRestOperations()` with a custom configured `RestOperations`. - The default `RestOperations` is configured as follows: - - ==== -@@ -1172,15 +1170,15 @@ restTemplate.errorHandler = OAuth2ErrorResponseErrorHandler() - ---- - ==== - --TIP: Spring MVC `FormHttpMessageConverter` is required as it's used when sending the OAuth 2.0 Access Token Request. -+TIP: Spring MVC `FormHttpMessageConverter` is required, as it is used when sending the OAuth 2.0 Access Token Request. - - `OAuth2AccessTokenResponseHttpMessageConverter` is a `HttpMessageConverter` for an OAuth 2.0 Access Token Response. - You can provide `OAuth2AccessTokenResponseHttpMessageConverter.setTokenResponseConverter()` with a custom `Converter, OAuth2AccessTokenResponse>` that is used for converting the OAuth 2.0 Access Token Response parameters to an `OAuth2AccessTokenResponse`. - --`OAuth2ErrorResponseErrorHandler` is a `ResponseErrorHandler` that can handle an OAuth 2.0 Error, eg. 400 Bad Request. --It uses an `OAuth2ErrorHttpMessageConverter` for converting the OAuth 2.0 Error parameters to an `OAuth2Error`. -+`OAuth2ErrorResponseErrorHandler` is a `ResponseErrorHandler` that can handle an OAuth 2.0 Error, such as `400 Bad Request`. -+It uses an `OAuth2ErrorHttpMessageConverter` to convert the OAuth 2.0 Error parameters to an `OAuth2Error`. - --Whether you customize `DefaultClientCredentialsTokenResponseClient` or provide your own implementation of `OAuth2AccessTokenResponseClient`, you'll need to configure it as shown in the following example: -+Whether you customize `DefaultClientCredentialsTokenResponseClient` or provide your own implementation of `OAuth2AccessTokenResponseClient`, you need to configure it as follows: - - ==== - .Java -@@ -1215,14 +1213,14 @@ authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider) - ---- - ==== - --[NOTE] --`OAuth2AuthorizedClientProviderBuilder.builder().clientCredentials()` configures a `ClientCredentialsOAuth2AuthorizedClientProvider`, -+NOTE: `OAuth2AuthorizedClientProviderBuilder.builder().clientCredentials()` configures a `ClientCredentialsOAuth2AuthorizedClientProvider`, - which is an implementation of an `OAuth2AuthorizedClientProvider` for the Client Credentials grant. - - ===== Using the Access Token - --Given the following Spring Boot 2.x properties for an OAuth 2.0 Client registration: -+Consider the following Spring Boot 2.x properties for an OAuth 2.0 Client registration: - -+==== - [source,yaml] - ---- - spring: -@@ -1239,8 +1237,9 @@ spring: - okta: - token-uri: https://dev-1234.oktapreview.com/oauth2/v1/token - ---- -+==== - --...and the `OAuth2AuthorizedClientManager` `@Bean`: -+Further consider the following `OAuth2AuthorizedClientManager` `@Bean`: - - ==== - .Java -@@ -1283,7 +1282,7 @@ fun authorizedClientManager( - ---- - ==== - --You may obtain the `OAuth2AccessToken` as follows: -+Given the preceding properties and bean, you can obtain the `OAuth2AccessToken` as follows: - - ==== - .Java -@@ -1348,40 +1347,37 @@ class OAuth2ClientController { - ---- - ==== - --[NOTE] --`HttpServletRequest` and `HttpServletResponse` are both OPTIONAL attributes. --If not provided, it will default to `ServletRequestAttributes` using `RequestContextHolder.getRequestAttributes()`. -+NOTE: `HttpServletRequest` and `HttpServletResponse` are both OPTIONAL attributes. -+If not provided, they default to `ServletRequestAttributes` by using `RequestContextHolder.getRequestAttributes()`. - - - [[oauth2Client-password-grant]] - ==== Resource Owner Password Credentials - --[NOTE] --Please refer to the OAuth 2.0 Authorization Framework for further details on the https://tools.ietf.org/html/rfc6749#section-1.3.3[Resource Owner Password Credentials] grant. -+NOTE: See the OAuth 2.0 Authorization Framework for further details on the https://tools.ietf.org/html/rfc6749#section-1.3.3[Resource Owner Password Credentials] grant. - - - ===== Requesting an Access Token - --[NOTE] --Please refer to the https://tools.ietf.org/html/rfc6749#section-4.3.2[Access Token Request/Response] protocol flow for the Resource Owner Password Credentials grant. -+NOTE: See the https://tools.ietf.org/html/rfc6749#section-4.3.2[Access Token Request/Response] protocol flow for the Resource Owner Password Credentials grant. - - The default implementation of `OAuth2AccessTokenResponseClient` for the Resource Owner Password Credentials grant is `DefaultPasswordTokenResponseClient`, which uses a `RestOperations` when requesting an access token at the Authorization Server’s Token Endpoint. - --The `DefaultPasswordTokenResponseClient` is quite flexible as it allows you to customize the pre-processing of the Token Request and/or post-handling of the Token Response. -+The `DefaultPasswordTokenResponseClient` is flexible, as it lets you customize the pre-processing of the Token Request or post-handling of the Token Response. - - - ===== Customizing the Access Token Request - - If you need to customize the pre-processing of the Token Request, you can provide `DefaultPasswordTokenResponseClient.setRequestEntityConverter()` with a custom `Converter>`. --The default implementation `OAuth2PasswordGrantRequestEntityConverter` builds a `RequestEntity` representation of a standard https://tools.ietf.org/html/rfc6749#section-4.3.2[OAuth 2.0 Access Token Request]. --However, providing a custom `Converter`, would allow you to extend the standard Token Request and add custom parameter(s). -+The default implementation (`OAuth2PasswordGrantRequestEntityConverter`) builds a `RequestEntity` representation of a standard https://tools.ietf.org/html/rfc6749#section-4.3.2[OAuth 2.0 Access Token Request]. -+However, providing a custom `Converter` would let you extend the standard Token Request and add custom parameter(s). - - IMPORTANT: The custom `Converter` must return a valid `RequestEntity` representation of an OAuth 2.0 Access Token Request that is understood by the intended OAuth 2.0 Provider. - - - ===== Customizing the Access Token Response - --On the other end, if you need to customize the post-handling of the Token Response, you will need to provide `DefaultPasswordTokenResponseClient.setRestOperations()` with a custom configured `RestOperations`. -+On the other end, if you need to customize the post-handling of the Token Response, you need to provide `DefaultPasswordTokenResponseClient.setRestOperations()` with a custom configured `RestOperations`. - The default `RestOperations` is configured as follows: - - ==== -@@ -1406,15 +1402,15 @@ restTemplate.errorHandler = OAuth2ErrorResponseErrorHandler() - ---- - ==== - --TIP: Spring MVC `FormHttpMessageConverter` is required as it's used when sending the OAuth 2.0 Access Token Request. -+TIP: Spring MVC `FormHttpMessageConverter` is required, as it is used when sending the OAuth 2.0 Access Token Request. - - `OAuth2AccessTokenResponseHttpMessageConverter` is a `HttpMessageConverter` for an OAuth 2.0 Access Token Response. --You can provide `OAuth2AccessTokenResponseHttpMessageConverter.setTokenResponseConverter()` with a custom `Converter, OAuth2AccessTokenResponse>` that is used for converting the OAuth 2.0 Access Token Response parameters to an `OAuth2AccessTokenResponse`. -+You can provide `OAuth2AccessTokenResponseHttpMessageConverter.setTokenResponseConverter()` with a custom `Converter, OAuth2AccessTokenResponse>` that is used to convert the OAuth 2.0 Access Token Response parameters to an `OAuth2AccessTokenResponse`. - --`OAuth2ErrorResponseErrorHandler` is a `ResponseErrorHandler` that can handle an OAuth 2.0 Error, eg. 400 Bad Request. --It uses an `OAuth2ErrorHttpMessageConverter` for converting the OAuth 2.0 Error parameters to an `OAuth2Error`. -+`OAuth2ErrorResponseErrorHandler` is a `ResponseErrorHandler` that can handle an OAuth 2.0 Error, such as `400 Bad Request`. -+It uses an `OAuth2ErrorHttpMessageConverter` to convert the OAuth 2.0 Error parameters to an `OAuth2Error`. - --Whether you customize `DefaultPasswordTokenResponseClient` or provide your own implementation of `OAuth2AccessTokenResponseClient`, you'll need to configure it as shown in the following example: -+Whether you customize `DefaultPasswordTokenResponseClient` or provide your own implementation of `OAuth2AccessTokenResponseClient`, you need to configure it as follows: - - ==== - .Java -@@ -1456,7 +1452,7 @@ which is an implementation of an `OAuth2AuthorizedClientProvider` for the Resour - - ===== Using the Access Token - --Given the following Spring Boot 2.x properties for an OAuth 2.0 Client registration: -+Consider the following Spring Boot 2.x properties for an OAuth 2.0 Client registration: - - [source,yaml] - ---- -@@ -1475,7 +1471,7 @@ spring: - token-uri: https://dev-1234.oktapreview.com/oauth2/v1/token - ---- - --...and the `OAuth2AuthorizedClientManager` `@Bean`: -+Further consider the `OAuth2AuthorizedClientManager` `@Bean`: - - ==== - .Java -@@ -1561,7 +1557,7 @@ private fun contextAttributesMapper(): Function> and therefore inherits it's capabilities. -+The `@RegisteredOAuth2AuthorizedClient` annotation is handled by `OAuth2AuthorizedClientArgumentResolver`, which directly uses an <> and, therefore, inherits its capabilities. - - - [[oauth2Client-webclient-servlet]] --=== WebClient integration for Servlet Environments -+=== WebClient Integration for Servlet Environments - --The OAuth 2.0 Client support integrates with `WebClient` using an `ExchangeFilterFunction`. -+The OAuth 2.0 Client support integrates with `WebClient` by using an `ExchangeFilterFunction`. - --The `ServletOAuth2AuthorizedClientExchangeFilterFunction` provides a simple mechanism for requesting protected resources by using an `OAuth2AuthorizedClient` and including the associated `OAuth2AccessToken` as a Bearer Token. --It directly uses an <> and therefore inherits the following capabilities: -+The `ServletOAuth2AuthorizedClientExchangeFilterFunction` provides a mechanism for requesting protected resources by using an `OAuth2AuthorizedClient` and including the associated `OAuth2AccessToken` as a Bearer Token. -+It directly uses an <> and, therefore, inherits the following capabilities: - --* An `OAuth2AccessToken` will be requested if the client has not yet been authorized. --** `authorization_code` - triggers the Authorization Request redirect to initiate the flow --** `client_credentials` - the access token is obtained directly from the Token Endpoint --** `password` - the access token is obtained directly from the Token Endpoint --* If the `OAuth2AccessToken` is expired, it will be refreshed (or renewed) if an `OAuth2AuthorizedClientProvider` is available to perform the authorization -+* An `OAuth2AccessToken` is requested if the client has not yet been authorized. -+** `authorization_code`: Triggers the Authorization Request redirect to initiate the flow. -+** `client_credentials`: The access token is obtained directly from the Token Endpoint. -+** `password`: The access token is obtained directly from the Token Endpoint. -+* If the `OAuth2AccessToken` is expired, it is refreshed (or renewed) if an `OAuth2AuthorizedClientProvider` is available to perform the authorization - - The following code shows an example of how to configure `WebClient` with OAuth 2.0 Client support: - -@@ -1769,9 +1767,8 @@ fun index(@RegisteredOAuth2AuthorizedClient("okta") authorizedClient: OAuth2Auth - return "index" - } - ---- --==== -- - <1> `oauth2AuthorizedClient()` is a `static` method in `ServletOAuth2AuthorizedClientExchangeFilterFunction`. -+==== - - The following code shows how to set the `ClientRegistration.getRegistrationId()` as a request attribute: - -@@ -1817,15 +1814,14 @@ fun index(): String { - return "index" - } - ---- --==== - <1> `clientRegistrationId()` is a `static` method in `ServletOAuth2AuthorizedClientExchangeFilterFunction`. -- -+==== - - ==== Defaulting the Authorized Client - --If neither `OAuth2AuthorizedClient` or `ClientRegistration.getRegistrationId()` is provided as a request attribute, the `ServletOAuth2AuthorizedClientExchangeFilterFunction` can determine the _default_ client to use depending on it's configuration. -+If neither `OAuth2AuthorizedClient` or `ClientRegistration.getRegistrationId()` is provided as a request attribute, the `ServletOAuth2AuthorizedClientExchangeFilterFunction` can determine the _default_ client to use, depending on its configuration. - --If `setDefaultOAuth2AuthorizedClient(true)` is configured and the user has authenticated using `HttpSecurity.oauth2Login()`, the `OAuth2AccessToken` associated with the current `OAuth2AuthenticationToken` is used. -+If `setDefaultOAuth2AuthorizedClient(true)` is configured and the user has authenticated by using `HttpSecurity.oauth2Login()`, the `OAuth2AccessToken` associated with the current `OAuth2AuthenticationToken` is used. - - The following code shows the specific configuration: - -@@ -1858,8 +1854,7 @@ fun webClient(authorizedClientManager: OAuth2AuthorizedClientManager?): WebClien - ---- - ==== - --[WARNING] --It is recommended to be cautious with this feature since all HTTP requests will receive the access token. -+WARNING: Be cautious with this feature, since all HTTP requests receive the access token. - - Alternatively, if `setDefaultClientRegistrationId("okta")` is configured with a valid `ClientRegistration`, the `OAuth2AccessToken` associated with the `OAuth2AuthorizedClient` is used. - -@@ -1894,5 +1889,4 @@ fun webClient(authorizedClientManager: OAuth2AuthorizedClientManager?): WebClien - ---- - ==== - --[WARNING] --It is recommended to be cautious with this feature since all HTTP requests will receive the access token. -+WARNING: Be cautious with this feature, since all HTTP requests receive the access token. -diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/oauth2/oauth2-login.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/oauth2/oauth2-login.adoc -index 24cac1e45b..b8fc76df6e 100644 ---- a/docs/manual/src/docs/asciidoc/_includes/servlet/oauth2/oauth2-login.adoc -+++ b/docs/manual/src/docs/asciidoc/_includes/servlet/oauth2/oauth2-login.adoc -@@ -1,8 +1,8 @@ - [[oauth2login]] - == OAuth 2.0 Login - --The OAuth 2.0 Login feature provides an application with the capability to have users log in to the application by using their existing account at an OAuth 2.0 Provider (e.g. GitHub) or OpenID Connect 1.0 Provider (such as Google). --OAuth 2.0 Login implements the use cases: "Login with Google" or "Login with GitHub". -+The OAuth 2.0 Login feature lets an application have users log in to the application by using their existing account at an OAuth 2.0 Provider (such as GitHub) or OpenID Connect 1.0 Provider (such as Google). -+OAuth 2.0 Login implements two use cases: "`Login with Google`" or "`Login with GitHub`". - - NOTE: OAuth 2.0 Login is implemented by using the *Authorization Code Grant*, as specified in the https://tools.ietf.org/html/rfc6749#section-4.1[OAuth 2.0 Authorization Framework] and https://openid.net/specs/openid-connect-core-1_0.html#CodeFlowAuth[OpenID Connect Core 1.0]. - -@@ -12,38 +12,38 @@ NOTE: OAuth 2.0 Login is implemented by using the *Authorization Code Grant*, as - - Spring Boot 2.x brings full auto-configuration capabilities for OAuth 2.0 Login. - --This section shows how to configure the {gh-samples-url}/boot/oauth2login[*OAuth 2.0 Login sample*] using _Google_ as the _Authentication Provider_ and covers the following topics: -+This section shows how to configure the {gh-samples-url}/boot/oauth2login[*OAuth 2.0 Login sample*] by using _Google_ as the _Authentication Provider_ and covers the following topics: - --* <> --* <> --* <> --* <> -+* <> -+* <> -+* <> -+* <> - - - [[oauth2login-sample-initial-setup]] --==== Initial setup -+==== Initial Setup - - To use Google's OAuth 2.0 authentication system for login, you must set up a project in the Google API Console to obtain OAuth 2.0 credentials. - --NOTE: https://developers.google.com/identity/protocols/OpenIDConnect[Google's OAuth 2.0 implementation] for authentication conforms to the https://openid.net/connect/[OpenID Connect 1.0] specification and is https://openid.net/certification/[OpenID Certified]. -+NOTE: https://developers.google.com/identity/protocols/OpenIDConnect[Google's OAuth 2.0 implementation] for authentication conforms to the https://openid.net/connect/[OpenID Connect 1.0] specification and is https://openid.net/certification/[OpenID certified]. - --Follow the instructions on the https://developers.google.com/identity/protocols/OpenIDConnect[OpenID Connect] page, starting in the section, "Setting up OAuth 2.0". -+Follow the instructions on the https://developers.google.com/identity/protocols/OpenIDConnect[OpenID Connect] page, starting in the "`Setting up OAuth 2.0`" section. - --After completing the "Obtain OAuth 2.0 credentials" instructions, you should have a new OAuth Client with credentials consisting of a Client ID and a Client Secret. -+After completing the "`Obtain OAuth 2.0 credentials`" instructions, you should have new OAuth Client with credentials consisting of a Client ID and a Client Secret. - - - [[oauth2login-sample-redirect-uri]] --==== Setting the redirect URI -+==== Setting the Redirect URI - --The redirect URI is the path in the application that the end-user's user-agent is redirected back to after they have authenticated with Google and have granted access to the OAuth Client _(<>)_ on the Consent page. -+The redirect URI is the path in the application that the end-user's user-agent is redirected back to after they have authenticated with Google and have granted access to the OAuth Client (<>) on the Consent page. - --In the "Set a redirect URI" sub-section, ensure that the *Authorized redirect URIs* field is set to `http://localhost:8080/login/oauth2/code/google`. -+In the "`Set a redirect URI`" subsection, ensure that the *Authorized redirect URIs* field is set to `http://localhost:8080/login/oauth2/code/google`. - - TIP: The default redirect URI template is `+{baseUrl}/login/oauth2/code/{registrationId}+`. --The *_registrationId_* is a unique identifier for the <>. -+The `registrationId` is a unique identifier for the <>. - --IMPORTANT: If the OAuth Client is running behind a proxy server, it is recommended to check <> to ensure the application is correctly configured. --Also, see the supported <> for `redirect-uri`. -+IMPORTANT: If the OAuth Client runs behind a proxy server, you should check the <> to ensure the application is correctly configured. -+Also, see the supported <> for `redirect-uri`. - - - [[oauth2login-sample-application-config]] -@@ -69,21 +69,21 @@ spring: - .OAuth Client properties - ==== - <1> `spring.security.oauth2.client.registration` is the base property prefix for OAuth Client properties. --<2> Following the base property prefix is the ID for the <>, such as google. -+<2> Following the base property prefix is the ID for the <>, such as Google. - ==== - - . Replace the values in the `client-id` and `client-secret` property with the OAuth 2.0 credentials you created earlier. - - - [[oauth2login-sample-boot-application]] --==== Boot up the application -+==== Boot up the Application - - Launch the Spring Boot 2.x sample and go to `http://localhost:8080`. - You are then redirected to the default _auto-generated_ login page, which displays a link for Google. - - Click on the Google link, and you are then redirected to Google for authentication. - --After authenticating with your Google account credentials, the next page presented to you is the Consent screen. -+After authenticating with your Google account credentials, you see the Consent screen. - The Consent screen asks you to either allow or deny access to the OAuth Client you created earlier. - Click *Allow* to authorize the OAuth Client to access your email address and basic profile information. - -@@ -144,8 +144,7 @@ The following table outlines the mapping of the Spring Boot 2.x OAuth Client pro - |`providerDetails.userInfoEndpoint.userNameAttributeName` - |=== - --[TIP] --A `ClientRegistration` can be initially configured using discovery of an OpenID Connect Provider's https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfig[Configuration endpoint] or an Authorization Server's https://tools.ietf.org/html/rfc8414#section-3[Metadata endpoint], by specifying the `spring.security.oauth2.client.provider._[providerId]_.issuer-uri` property. -+TIP: You can initially configure a `ClientRegistration` by using discovery of an OpenID Connect Provider's https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfig[Configuration endpoint] or an Authorization Server's https://tools.ietf.org/html/rfc8414#section-3[Metadata endpoint], by specifying the `spring.security.oauth2.client.provider._[providerId]_.issuer-uri` property. - - - [[oauth2login-common-oauth2-provider]] -@@ -153,13 +152,14 @@ A `ClientRegistration` can be initially configured using discovery of an OpenID - - `CommonOAuth2Provider` pre-defines a set of default client properties for a number of well known providers: Google, GitHub, Facebook, and Okta. - --For example, the `authorization-uri`, `token-uri`, and `user-info-uri` do not change often for a Provider. --Therefore, it makes sense to provide default values in order to reduce the required configuration. -+For example, the `authorization-uri`, `token-uri`, and `user-info-uri` do not change often for a provider. -+Therefore, it makes sense to provide default values, to reduce the required configuration. - - As demonstrated previously, when we <>, only the `client-id` and `client-secret` properties are required. - - The following listing shows an example: - -+==== - [source,yaml] - ---- - spring: -@@ -171,6 +171,7 @@ spring: - client-id: google-client-id - client-secret: google-client-secret - ---- -+==== - - [TIP] - The auto-defaulting of client properties works seamlessly here because the `registrationId` (`google`) matches the `GOOGLE` `enum` (case-insensitive) in `CommonOAuth2Provider`. -@@ -179,6 +180,7 @@ For cases where you may want to specify a different `registrationId`, such as `g - - The following listing shows an example: - -+==== - [source,yaml] - ---- - spring: -@@ -192,8 +194,8 @@ spring: - client-secret: google-client-secret - ---- - <1> The `registrationId` is set to `google-login`. --<2> The `provider` property is set to `google`, which will leverage the auto-defaulting of client properties set in `CommonOAuth2Provider.GOOGLE.getBuilder()`. -- -+<2> The `provider` property is set to `google`, which uses the auto-defaulting of client properties set in `CommonOAuth2Provider.GOOGLE.getBuilder()`. -+==== - - [[oauth2login-custom-provider-properties]] - === Configuring Custom Provider Properties -@@ -206,6 +208,7 @@ For these cases, Spring Boot 2.x provides the following base property for config - - The following listing shows an example: - -+==== - [source,yaml] - ---- - spring: -@@ -224,9 +227,8 @@ spring: - user-name-attribute: sub - jwk-set-uri: https://your-subdomain.oktapreview.com/oauth2/v1/keys - ---- -- - <1> The base property (`spring.security.oauth2.client.provider.okta`) allows for custom configuration of protocol endpoint locations. -- -+==== - - [[oauth2login-override-boot-autoconfig]] - === Overriding Spring Boot 2.x Auto-configuration -@@ -240,9 +242,9 @@ It performs the following tasks: - - If you need to override the auto-configuration based on your specific requirements, you may do so in the following ways: - --* <> --* <> --* <> -+* <> -+* <> -+* <> - - - [[oauth2login-register-clientregistrationrepository-bean]] -@@ -600,14 +602,14 @@ The main goal of the `oauth2Login()` DSL was to closely align with the naming, a - - The OAuth 2.0 Authorization Framework defines the https://tools.ietf.org/html/rfc6749#section-3[Protocol Endpoints] as follows: - --The authorization process utilizes two authorization server endpoints (HTTP resources): -+The authorization process uses two authorization server endpoints (HTTP resources): - --* Authorization Endpoint: Used by the client to obtain authorization from the resource owner via user-agent redirection. -+* Authorization Endpoint: Used by the client to obtain authorization from the resource owner through user-agent redirection. - * Token Endpoint: Used by the client to exchange an authorization grant for an access token, typically with client authentication. - --As well as one client endpoint: -+The authorization process also uses one client endpoint: - --* Redirection Endpoint: Used by the authorization server to return responses containing authorization credentials to the client via the resource owner user-agent. -+* Redirection Endpoint: Used by the authorization server to return responses that contain authorization credentials to the client through the resource owner user-agent. - - The OpenID Connect Core 1.0 specification defines the https://openid.net/specs/openid-connect-core-1_0.html#UserInfo[UserInfo Endpoint] as follows: - -@@ -719,9 +721,9 @@ The following code shows the complete configuration options available in the <> --* <> --* <> -+* <> -+* <> -+* <> - - - [[oauth2login-advanced-login-page]] -@@ -730,8 +732,7 @@ The following sections go into more detail on each of the configuration options - By default, the OAuth 2.0 Login Page is auto-generated by the `DefaultLoginPageGeneratingFilter`. - The default login page shows each configured OAuth Client with its `ClientRegistration.clientName` as a link, which is capable of initiating the Authorization Request (or OAuth 2.0 Login). - --[NOTE] --In order for `DefaultLoginPageGeneratingFilter` to show links for configured OAuth Clients, the registered `ClientRegistrationRepository` needs to also implement `Iterable`. -+NOTE: For `DefaultLoginPageGeneratingFilter` to show links for configured OAuth Clients, the registered `ClientRegistrationRepository` needs to also implement `Iterable`. - See `InMemoryClientRegistrationRepository` for reference. - - The link's destination for each OAuth Client defaults to the following: -@@ -740,10 +741,12 @@ The link's destination for each OAuth Client defaults to the following: - - The following line shows an example: - -+==== - [source,html] - ---- - Google - ---- -+==== - - To override the default login page, configure `oauth2Login().loginPage()` and (optionally) `oauth2Login().authorizationEndpoint().baseUri()`. - -@@ -802,35 +805,35 @@ class OAuth2LoginSecurityConfig : WebSecurityConfigurerAdapter() { - ---- - ==== - --[IMPORTANT] --You need to provide a `@Controller` with a `@RequestMapping("/login/oauth2")` that is capable of rendering the custom login page. -+IMPORTANT: You need to provide a `@Controller` with a `@RequestMapping("/login/oauth2")` that is capable of rendering the custom login page. - - [TIP] --==== -+===== - As noted earlier, configuring `oauth2Login().authorizationEndpoint().baseUri()` is optional. - However, if you choose to customize it, ensure the link to each OAuth Client matches the `authorizationEndpoint().baseUri()`. - - The following line shows an example: - -+==== - [source,html] - ---- - Google - ---- - ==== -+===== - - - [[oauth2login-advanced-redirection-endpoint]] - ==== Redirection Endpoint - --The Redirection Endpoint is used by the Authorization Server for returning the Authorization Response (which contains the authorization credentials) to the client via the Resource Owner user-agent. -+The Redirection Endpoint is used by the Authorization Server for returning the Authorization Response (which contains the authorization credentials) to the client through the Resource Owner user-agent. - --[TIP] --OAuth 2.0 Login leverages the Authorization Code Grant. -+TIP: OAuth 2.0 Login leverages the Authorization Code Grant. - Therefore, the authorization credential is the authorization code. - - The default Authorization Response `baseUri` (redirection endpoint) is `*/login/oauth2/code/**`, which is defined in `OAuth2LoginAuthenticationFilter.DEFAULT_FILTER_PROCESSES_URI`. - --If you would like to customize the Authorization Response `baseUri`, configure it as shown in the following example: -+If you would like to customize the Authorization Response `baseUri`, configure it as follows: - - .Redirection Endpoint Configuration - ==== -@@ -883,11 +886,12 @@ class OAuth2LoginSecurityConfig : WebSecurityConfigurerAdapter() { - ==== - - [IMPORTANT] --==== -+===== - You also need to ensure the `ClientRegistration.redirectUri` matches the custom Authorization Response `baseUri`. - - The following listing shows an example: - -+==== - .Java - [source,java,role="primary",attrs="-attributes"] - ---- -@@ -908,36 +912,36 @@ return CommonOAuth2Provider.GOOGLE.getBuilder("google") - .build() - ---- - ==== -- -+===== - - [[oauth2login-advanced-userinfo-endpoint]] - ==== UserInfo Endpoint - - The UserInfo Endpoint includes a number of configuration options, as described in the following sub-sections: - --* <> --* <> --* <> -+* <> -+* <> -+* <> - - - [[oauth2login-advanced-map-authorities]] - ===== Mapping User Authorities - --After the user successfully authenticates with the OAuth 2.0 Provider, the `OAuth2User.getAuthorities()` (or `OidcUser.getAuthorities()`) may be mapped to a new set of `GrantedAuthority` instances, which will be supplied to `OAuth2AuthenticationToken` when completing the authentication. -+After the user successfully authenticates with the OAuth 2.0 Provider, the `OAuth2User.getAuthorities()` (or `OidcUser.getAuthorities()`) can be mapped to a new set of `GrantedAuthority` instances, which are supplied to `OAuth2AuthenticationToken` when completing the authentication. - - [TIP] - `OAuth2AuthenticationToken.getAuthorities()` is used for authorizing requests, such as in `hasRole('USER')` or `hasRole('ADMIN')`. - - There are a couple of options to choose from when mapping user authorities: - --* <> --* <> -+* <> -+* <> - - - [[oauth2login-advanced-map-authorities-grantedauthoritiesmapper]] - ====== Using a GrantedAuthoritiesMapper - --Provide an implementation of `GrantedAuthoritiesMapper` and configure it as shown in the following example: -+Provide an implementation of `GrantedAuthoritiesMapper` and configure it, as follows: - - .Granted Authorities Mapper Configuration - ==== -@@ -1037,7 +1041,7 @@ class OAuth2LoginSecurityConfig : WebSecurityConfigurerAdapter() { - ---- - ==== - --Alternatively, you may register a `GrantedAuthoritiesMapper` `@Bean` to have it automatically applied to the configuration, as shown in the following example: -+Alternatively, you can register a `GrantedAuthoritiesMapper` `@Bean` to have it automatically applied to the configuration, as follows: - - .Granted Authorities Mapper Bean Configuration - ==== -@@ -1081,11 +1085,11 @@ class OAuth2LoginSecurityConfig : WebSecurityConfigurerAdapter() { - ==== - - [[oauth2login-advanced-map-authorities-oauth2userservice]] --====== Delegation-based strategy with OAuth2UserService -+====== Delegation-based Strategy with OAuth2UserService - --This strategy is advanced compared to using a `GrantedAuthoritiesMapper`, however, it's also more flexible as it gives you access to the `OAuth2UserRequest` and `OAuth2User` (when using an OAuth 2.0 UserService) or `OidcUserRequest` and `OidcUser` (when using an OpenID Connect 1.0 UserService). -+This strategy is advanced compared to using a `GrantedAuthoritiesMapper`. However, it is also more flexible, as it gives you access to the `OAuth2UserRequest` and `OAuth2User` (when using an OAuth 2.0 UserService) or `OidcUserRequest` and `OidcUser` (when using an OpenID Connect 1.0 UserService). - --The `OAuth2UserRequest` (and `OidcUserRequest`) provides you access to the associated `OAuth2AccessToken`, which is very useful in the cases where the _delegator_ needs to fetch authority information from a protected resource before it can map the custom authorities for the user. -+The `OAuth2UserRequest` (and `OidcUserRequest`) provides you access to the associated `OAuth2AccessToken`, which is very useful in cases where the _delegator_ needs to fetch authority information from a protected resource before it can map the custom authorities for the user. - - The following example shows how to implement and configure a delegation-based strategy using an OpenID Connect 1.0 UserService: - -@@ -1187,27 +1191,28 @@ class OAuth2LoginSecurityConfig : WebSecurityConfigurerAdapter() { - - `DefaultOAuth2UserService` is an implementation of an `OAuth2UserService` that supports standard OAuth 2.0 Provider's. - --[NOTE] --`OAuth2UserService` obtains the user attributes of the end-user (the resource owner) from the UserInfo Endpoint (by using the access token granted to the client during the authorization flow) and returns an `AuthenticatedPrincipal` in the form of an `OAuth2User`. -+NOTE: `OAuth2UserService` obtains the user attributes of the end-user (the resource owner) from the UserInfo Endpoint (by using the access token granted to the client during the authorization flow) and returns an `AuthenticatedPrincipal` in the form of an `OAuth2User`. - --`DefaultOAuth2UserService` uses a `RestOperations` when requesting the user attributes at the UserInfo Endpoint. -+`DefaultOAuth2UserService` uses a `RestOperations` instance when requesting the user attributes at the UserInfo Endpoint. - - If you need to customize the pre-processing of the UserInfo Request, you can provide `DefaultOAuth2UserService.setRequestEntityConverter()` with a custom `Converter>`. - The default implementation `OAuth2UserRequestEntityConverter` builds a `RequestEntity` representation of a UserInfo Request that sets the `OAuth2AccessToken` in the `Authorization` header by default. - --On the other end, if you need to customize the post-handling of the UserInfo Response, you will need to provide `DefaultOAuth2UserService.setRestOperations()` with a custom configured `RestOperations`. -+On the other end, if you need to customize the post-handling of the UserInfo Response, you need to provide `DefaultOAuth2UserService.setRestOperations()` with a custom configured `RestOperations`. - The default `RestOperations` is configured as follows: - -+==== - [source,java] - ---- - RestTemplate restTemplate = new RestTemplate(); - restTemplate.setErrorHandler(new OAuth2ErrorResponseErrorHandler()); - ---- -+==== - - `OAuth2ErrorResponseErrorHandler` is a `ResponseErrorHandler` that can handle an OAuth 2.0 Error (400 Bad Request). - It uses an `OAuth2ErrorHttpMessageConverter` for converting the OAuth 2.0 Error parameters to an `OAuth2Error`. - --Whether you customize `DefaultOAuth2UserService` or provide your own implementation of `OAuth2UserService`, you'll need to configure it as shown in the following example: -+Whether you customize `DefaultOAuth2UserService` or provide your own implementation of `OAuth2UserService`, you need to configure it as follows: - - ==== - .Java -@@ -1265,9 +1270,9 @@ class OAuth2LoginSecurityConfig : WebSecurityConfigurerAdapter() { - - The `OidcUserService` leverages the `DefaultOAuth2UserService` when requesting the user attributes at the UserInfo Endpoint. - --If you need to customize the pre-processing of the UserInfo Request and/or the post-handling of the UserInfo Response, you will need to provide `OidcUserService.setOauth2UserService()` with a custom configured `DefaultOAuth2UserService`. -+If you need to customize the pre-processing of the UserInfo Request or the post-handling of the UserInfo Response, you need to provide `OidcUserService.setOauth2UserService()` with a custom configured `DefaultOAuth2UserService`. - --Whether you customize `OidcUserService` or provide your own implementation of `OAuth2UserService` for OpenID Connect 1.0 Provider's, you'll need to configure it as shown in the following example: -+Whether you customize `OidcUserService` or provide your own implementation of `OAuth2UserService` for OpenID Connect 1.0 Provider's, you need to configure it as follows: - - ==== - .Java -@@ -1323,14 +1328,14 @@ class OAuth2LoginSecurityConfig : WebSecurityConfigurerAdapter() { - - OpenID Connect 1.0 Authentication introduces the https://openid.net/specs/openid-connect-core-1_0.html#IDToken[ID Token], which is a security token that contains Claims about the Authentication of an End-User by an Authorization Server when used by a Client. - --The ID Token is represented as a https://tools.ietf.org/html/rfc7519[JSON Web Token] (JWT) and MUST be signed using https://tools.ietf.org/html/rfc7515[JSON Web Signature] (JWS). -+The ID Token is represented as a https://tools.ietf.org/html/rfc7519[JSON Web Token] (JWT) and MUST be signed by using https://tools.ietf.org/html/rfc7515[JSON Web Signature] (JWS). - - The `OidcIdTokenDecoderFactory` provides a `JwtDecoder` used for `OidcIdToken` signature verification. The default algorithm is `RS256` but may be different when assigned during client registration. --For these cases, a resolver may be configured to return the expected JWS algorithm assigned for a specific client. -+For these cases, you can configure a resolver to return the expected JWS algorithm assigned for a specific client. - --The JWS algorithm resolver is a `Function` that accepts a `ClientRegistration` and returns the expected `JwsAlgorithm` for the client, eg. `SignatureAlgorithm.RS256` or `MacAlgorithm.HS256` -+The JWS algorithm resolver is a `Function` that accepts a `ClientRegistration` and returns the expected `JwsAlgorithm` for the client, such as `SignatureAlgorithm.RS256` or `MacAlgorithm.HS256` - --The following code shows how to configure the `OidcIdTokenDecoderFactory` `@Bean` to default to `MacAlgorithm.HS256` for all `ClientRegistration`: -+The following code shows how to configure the `OidcIdTokenDecoderFactory` `@Bean` to default to `MacAlgorithm.HS256` for all `ClientRegistration` instances: - - ==== - .Java -@@ -1356,22 +1361,21 @@ fun idTokenDecoderFactory(): JwtDecoderFactory { - ---- - ==== - --[NOTE] --For MAC based algorithms such as `HS256`, `HS384` or `HS512`, the `client-secret` corresponding to the `client-id` is used as the symmetric key for signature verification. -+NOTE: For MAC-based algorithms (such as `HS256`, `HS384`, or `HS512`), the `client-secret` that corresponds to the `client-id` is used as the symmetric key for signature verification. - --[TIP] --If more than one `ClientRegistration` is configured for OpenID Connect 1.0 Authentication, the JWS algorithm resolver may evaluate the provided `ClientRegistration` to determine which algorithm to return. -+TIP: If more than one `ClientRegistration` is configured for OpenID Connect 1.0 Authentication, the JWS algorithm resolver may evaluate the provided `ClientRegistration` to determine which algorithm to return. - - - [[oauth2login-advanced-oidc-logout]] - ==== OpenID Connect 1.0 Logout - --OpenID Connect Session Management 1.0 allows the ability to log out the End-User at the Provider using the Client. -+OpenID Connect Session Management 1.0 allows the ability to log out the end user at the Provider by using the Client. - One of the strategies available is https://openid.net/specs/openid-connect-session-1_0.html#RPLogout[RP-Initiated Logout]. - --If the OpenID Provider supports both Session Management and https://openid.net/specs/openid-connect-discovery-1_0.html[Discovery], the client may obtain the `end_session_endpoint` `URL` from the OpenID Provider's https://openid.net/specs/openid-connect-session-1_0.html#OPMetadata[Discovery Metadata]. --This can be achieved by configuring the `ClientRegistration` with the `issuer-uri`, as in the following example: -+If the OpenID Provider supports both Session Management and https://openid.net/specs/openid-connect-discovery-1_0.html[Discovery], the client can obtain the `end_session_endpoint` `URL` from the OpenID Provider's https://openid.net/specs/openid-connect-session-1_0.html#OPMetadata[Discovery Metadata]. -+You can do so by configuring the `ClientRegistration` with the `issuer-uri`, as follows: - -+==== - [source,yaml] - ---- - spring: -@@ -1387,8 +1391,9 @@ spring: - okta: - issuer-uri: https://dev-1234.oktapreview.com - ---- -+==== - --...and the `OidcClientInitiatedLogoutSuccessHandler`, which implements RP-Initiated Logout, may be configured as follows: -+Also, you can configure `OidcClientInitiatedLogoutSuccessHandler`, which implements RP-Initiated Logout, as follows: - - ==== - .Java -@@ -1424,10 +1429,11 @@ public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter { - } - } - --NOTE: `OidcClientInitiatedLogoutSuccessHandler` supports the `{baseUrl}` placeholder. --If used, the application's base URL, like `https://app.example.org`, will replace it at request time. - ---- - -+NOTE: `OidcClientInitiatedLogoutSuccessHandler` supports the `{baseUrl}` placeholder. -+If used, the application's base URL, such as `https://app.example.org`, replaces it at request time. -+ - .Kotlin - [source,kotlin,role="secondary"] - ---- -@@ -1458,7 +1464,7 @@ class OAuth2LoginSecurityConfig : WebSecurityConfigurerAdapter() { - } - } - --NOTE: `OidcClientInitiatedLogoutSuccessHandler` supports the `{baseUrl}` placeholder. --If used, the application's base URL, like `https://app.example.org`, will replace it at request time. - ---- -+NOTE: `OidcClientInitiatedLogoutSuccessHandler` supports the `{baseUrl}` placeholder. -+If used, the application's base URL, such as `https://app.example.org`, replaces it at request time. - ==== -diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/oauth2/oauth2-resourceserver.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/oauth2/oauth2-resourceserver.adoc -index b4e520c767..43502bc971 100644 ---- a/docs/manual/src/docs/asciidoc/_includes/servlet/oauth2/oauth2-resourceserver.adoc -+++ b/docs/manual/src/docs/asciidoc/_includes/servlet/oauth2/oauth2-resourceserver.adoc -@@ -1,9 +1,9 @@ --[[oauth2resourceserver]] -+NML.[[oauth2resourceserver]] - == OAuth 2.0 Resource Server - :figures: images/servlet/oauth2 - :icondir: images/icons - --Spring Security supports protecting endpoints using two forms of OAuth 2.0 https://tools.ietf.org/html/rfc6750.html[Bearer Tokens]: -+Spring Security supports protecting endpoints BY using two forms of OAuth 2.0 https://tools.ietf.org/html/rfc6750.html[Bearer Tokens]: - - * https://tools.ietf.org/html/rfc7519[JWT] - * Opaque Tokens -@@ -11,42 +11,37 @@ Spring Security supports protecting endpoints using two forms of OAuth 2.0 https - This is handy in circumstances where an application has delegated its authority management to an https://tools.ietf.org/html/rfc6749[authorization server] (for example, Okta or Ping Identity). - This authorization server can be consulted by resource servers to authorize requests. - --This section provides details on how Spring Security provides support for OAuth 2.0 https://tools.ietf.org/html/rfc6750.html[Bearer Tokens]. -+This section details how Spring Security provides support for OAuth 2.0 https://tools.ietf.org/html/rfc6750.html[Bearer Tokens]. - --[NOTE] --==== --Working samples for both {gh-samples-url}/boot/oauth2resourceserver[JWTs] and {gh-samples-url}/boot/oauth2resourceserver-opaque[Opaque Tokens] are available in the {gh-samples-url}[Spring Security repository]. --==== -+NOTE: Working samples for both {gh-samples-url}/boot/oauth2resourceserver[JWTs] and {gh-samples-url}/boot/oauth2resourceserver-opaque[Opaque Tokens] are available in the {gh-samples-url}[Spring Security repository]. - --Let's take a look at how Bearer Token Authentication works within Spring Security. --First, we see that, like <>, the https://tools.ietf.org/html/rfc7235#section-4.1[WWW-Authenticate] header is sent back to an unauthenticated client. -+Now we can consider how Bearer Token Authentication works within Spring Security. -+First, we see that, as with <>, the https://tools.ietf.org/html/rfc7235#section-4.1[WWW-Authenticate] header is sent back to an unauthenticated client: - - .Sending WWW-Authenticate Header - image::{figures}/bearerauthenticationentrypoint.png[] - --The figure above builds off our <> diagram. -+image:{icondir}/number_1.png[] First, a user makes an unauthenticated request to the `/private` resource for which the user is not authorized. - --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 <> indicates that the unauthenticated request is _Denied_ by throwing an `AccessDeniedException`. - --image:{icondir}/number_2.png[] Spring Security's <> indicates that the unauthenticated request is __Denied__ by throwing an `AccessDeniedException`. -+image:{icondir}/number_3.png[] Since the user is not authenticated, <> initiates _Start Authentication_. -+The configured <> is an instance of {security-api-url}org/springframework/security/oauth2/server/resource/authentication/BearerTokenAuthenticationEntryPoint.html[`BearerTokenAuthenticationEntryPoint`], which sends a `WWW-Authenticate` header. -+The `RequestCache` is typically a `NullRequestCache` that does not save the request, since the client is capable of replaying the requests it originally requested. - --image:{icondir}/number_3.png[] Since the user is not authenticated, <> initiates __Start Authentication__. --The configured <> is an instance of {security-api-url}org/springframework/security/oauth2/server/resource/authentication/BearerTokenAuthenticationEntryPoint.html[`BearerTokenAuthenticationEntryPoint`] which sends a WWW-Authenticate header. --The `RequestCache` is typically a `NullRequestCache` that does not save the request since the client is capable of replaying the requests it originally requested. -+NOTE: The preceding figure builds off of our <> diagram. - - When a client receives the `WWW-Authenticate: Bearer` header, it knows it should retry with a bearer token. --Below is the flow for the bearer token being processed. -+The following image shows the flow for the bearer token being processed: - - [[oauth2resourceserver-authentication-bearertokenauthenticationfilter]] - .Authenticating Bearer Token - image::{figures}/bearertokenauthenticationfilter.png[] - --The figure builds off our <> diagram. -- --image:{icondir}/number_1.png[] When the user submits their bearer token, the `BearerTokenAuthenticationFilter` creates a `BearerTokenAuthenticationToken` which is a type of <> by extracting the token from the `HttpServletRequest`. -+image:{icondir}/number_1.png[] When the user submits their bearer token, the `BearerTokenAuthenticationFilter` creates a `BearerTokenAuthenticationToken`, which is a type of <>, by extracting the token from the `HttpServletRequest`. - - image:{icondir}/number_2.png[] Next, the `HttpServletRequest` is passed to the `AuthenticationManagerResolver`, which selects the `AuthenticationManager`. The `BearerTokenAuthenticationToken` is passed into the `AuthenticationManager` to be authenticated. --The details of what `AuthenticationManager` looks like depends on whether you're configured for <> or <>. -+The details of what `AuthenticationManager` looks like depends on whether you configured for <> or an <>. - - image:{icondir}/number_3.png[] If authentication fails, then __Failure__ - -@@ -58,22 +53,27 @@ image:{icondir}/number_4.png[] If authentication is successful, then __Success__ - * The <> is set on the <>. - * The `BearerTokenAuthenticationFilter` invokes `FilterChain.doFilter(request,response)` to continue with the rest of the application logic. - -+NOTE: The preceding figure builds off our <> diagram. -+ - [[oauth2resourceserver-jwt-minimaldependencies]] - === Minimal Dependencies for JWT - - Most Resource Server support is collected into `spring-security-oauth2-resource-server`. --However, the support for decoding and verifying JWTs is in `spring-security-oauth2-jose`, meaning that both are necessary in order to have a working resource server that supports JWT-encoded Bearer Tokens. -+However, the support for decoding and verifying JWTs is in `spring-security-oauth2-jose`, meaning that both are necessary to have a working resource server that supports JWT-encoded Bearer Tokens. - - [[oauth2resourceserver-jwt-minimalconfiguration]] - === Minimal Configuration for JWTs - - When using https://spring.io/projects/spring-boot[Spring Boot], configuring an application as a resource server consists of two basic steps. --First, include the needed dependencies and second, indicate the location of the authorization server. -+ -+. Include the needed dependencies. -+. Indicate the location of the authorization server. - - ==== Specifying the Authorization Server - --In a Spring Boot application, to specify which authorization server to use, simply do: -+In a Spring Boot application, to specify which authorization server to use, you can use a YAML file similar to the following: - -+==== - [source,yml] - ---- - spring: -@@ -81,94 +81,93 @@ spring: - oauth2: - resourceserver: - jwt: -- issuer-uri: https://idp.example.com/issuer -+ issuer-uri: https://idp.example.com/issuer <1> - ---- -+<1> `https://idp.example.com/issuer` is the value contained in the `iss` claim for JWT tokens that the authorization server issues. -+==== - --Where `https://idp.example.com/issuer` is the value contained in the `iss` claim for JWT tokens that the authorization server will issue. --Resource Server will use this property to further self-configure, discover the authorization server's public keys, and subsequently validate incoming JWTs. -+Resource Server uses this property to further self-configure, discover the authorization server's public keys, and, subsequently, validate incoming JWTs. - --[NOTE] --To use the `issuer-uri` property, it must also be true that one of `https://idp.example.com/issuer/.well-known/openid-configuration`, `https://idp.example.com/.well-known/openid-configuration/issuer`, or `https://idp.example.com/.well-known/oauth-authorization-server/issuer` is a supported endpoint for the authorization server. -+NOTE: To use the `issuer-uri` property, it must also be true that one of `https://idp.example.com/issuer/.well-known/openid-configuration`, `https://idp.example.com/.well-known/openid-configuration/issuer`, or `https://idp.example.com/.well-known/oauth-authorization-server/issuer` is a supported endpoint for the authorization server. - This endpoint is referred to as a https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfig[Provider Configuration] endpoint or a https://tools.ietf.org/html/rfc8414#section-3[Authorization Server Metadata] endpoint. - --And that's it! -- - ==== Startup Expectations - --When this property and these dependencies are used, Resource Server will automatically configure itself to validate JWT-encoded Bearer Tokens. -+When this property and these dependencies are used, Resource Server automatically configures itself to validate JWT-encoded Bearer Tokens. - - It achieves this through a deterministic startup process: - --1. Query the Provider Configuration or Authorization Server Metadata endpoint for the `jwks_url` property --2. Query the `jwks_url` endpoint for supported algorithms --3. Configure the validation strategy to query `jwks_url` for valid public keys of the algorithms found --4. Configure the validation strategy to validate each JWTs `iss` claim against `https://idp.example.com`. -+. Query the Provider Configuration or Authorization Server Metadata endpoint for the `jwks_url` property. -+. Query the `jwks_url` endpoint for supported algorithms. -+. Configure the validation strategy to query `jwks_url` for valid public keys of the algorithms found. -+. Configure the validation strategy to validate each JWTs `iss` claim against `https://idp.example.com`. - --A consequence of this process is that the authorization server must be up and receiving requests in order for Resource Server to successfully start up. -+A consequence of this process is that the authorization server must be up and receiving requests for Resource Server to successfully start up. - --[NOTE] --If the authorization server is down when Resource Server queries it (given appropriate timeouts), then startup will fail. -+NOTE: If the authorization server is down when Resource Server queries it (given appropriate timeouts), startup fails. - - ==== Runtime Expectations - --Once the application is started up, Resource Server will attempt to process any request containing an `Authorization: Bearer` header: -+Once the application has started, Resource Server tries to process any request containing an `Authorization: Bearer` header: - -+==== - [source,html] - ---- - GET / HTTP/1.1 - Authorization: Bearer some-token-value # Resource Server will process this - ---- -+==== - --So long as this scheme is indicated, Resource Server will attempt to process the request according to the Bearer Token specification. -+So long as this scheme is indicated, Resource Server tries to process the request, according to the Bearer Token specification. - --Given a well-formed JWT, Resource Server will: -+Given a well-formed JWT, Resource Server: - --1. Validate its signature against a public key obtained from the `jwks_url` endpoint during startup and matched against the JWT --2. Validate the JWT's `exp` and `nbf` timestamps and the JWT's `iss` claim, and --3. Map each scope to an authority with the prefix `SCOPE_`. -+. Validates its signature against a public key obtained from the `jwks_url` endpoint during startup and matched against the JWT. -+. Validates the JWT's `exp` and `nbf` timestamps and the JWT's `iss` claim. -+. Maps each scope to an authority with the prefix `SCOPE_`. - --[NOTE] --As the authorization server makes available new keys, Spring Security will automatically rotate the keys used to validate JWTs. -+NOTE: As the authorization server makes available new keys, Spring Security automatically rotates the keys used to validate JWTs. - - The resulting `Authentication#getPrincipal`, by default, is a Spring Security `Jwt` object, and `Authentication#getName` maps to the JWT's `sub` property, if one is present. - - From here, consider jumping to: - --* <> -+* <> - * <> - * <> - - [[oauth2resourceserver-jwt-architecture]] - === How JWT Authentication Works - --Next, let's see the architectural components that Spring Security uses to support https://tools.ietf.org/html/rfc7519[JWT] Authentication in servlet-based applications, like the one we just saw. -+Next, we consider the architectural components that Spring Security uses to support https://tools.ietf.org/html/rfc7519[JWT] Authentication in servlet-based applications, like the one we just saw. - --{security-api-url}org/springframework/security/oauth2/server/resource/authentication/JwtAuthenticationProvider.html[`JwtAuthenticationProvider`] is an <> implementation that leverages a <> and <> to authenticate a JWT. -+{security-api-url}org/springframework/security/oauth2/server/resource/authentication/JwtAuthenticationProvider.html[`JwtAuthenticationProvider`] is an <> implementation that uses a <> and <> to authenticate a JWT. - --Let's take a look at how `JwtAuthenticationProvider` works within Spring Security. --The figure explains details of how the <> in figures from <> works. -+Now we can examine how `JwtAuthenticationProvider` works within Spring Security. -+The following figure details how the <> in other figures (from <>) works. - - .`JwtAuthenticationProvider` Usage - image::{figures}/jwtauthenticationprovider.png[] - --image:{icondir}/number_1.png[] The authentication `Filter` from <> passes a `BearerTokenAuthenticationToken` to the `AuthenticationManager` which is implemented by <>. -+image:{icondir}/number_1.png[] The authentication `Filter` from <> passes a `BearerTokenAuthenticationToken` to the `AuthenticationManager`, which is implemented by <>. - - image:{icondir}/number_2.png[] The `ProviderManager` is configured to use an <> of type `JwtAuthenticationProvider`. - - [[oauth2resourceserver-jwt-architecture-jwtdecoder]] --image:{icondir}/number_3.png[] `JwtAuthenticationProvider` decodes, verifies, and validates the `Jwt` using a <>. -+image:{icondir}/number_3.png[] `JwtAuthenticationProvider` decodes, verifies, and validates the `Jwt` by using a <>. - - [[oauth2resourceserver-jwt-architecture-jwtauthenticationconverter]] - image:{icondir}/number_4.png[] `JwtAuthenticationProvider` then uses the <> to convert the `Jwt` into a `Collection` of granted authorities. - - image:{icondir}/number_5.png[] When authentication is successful, the <> that is returned is of type `JwtAuthenticationToken` and has a principal that is the `Jwt` returned by the configured `JwtDecoder`. --Ultimately, the returned `JwtAuthenticationToken` will be set on the <> by the authentication `Filter`. -+Ultimately, the returned `JwtAuthenticationToken` is set on the <> by the authentication `Filter`. - - [[oauth2resourceserver-jwt-jwkseturi]] - === Specifying the Authorization Server JWK Set Uri Directly - --If the authorization server doesn't support any configuration endpoints, or if Resource Server must be able to start up independently from the authorization server, then the `jwk-set-uri` can be supplied as well: -+If the authorization server does not support any configuration endpoints or if Resource Server must be able to start up independently from the authorization server, you can supply the `jwk-set-uri` as well: - -+==== - [source,yaml] - ---- - spring: -@@ -179,22 +178,21 @@ spring: - issuer-uri: https://idp.example.com - jwk-set-uri: https://idp.example.com/.well-known/jwks.json - ---- -+==== - --[NOTE] --The JWK Set uri is not standardized, but can typically be found in the authorization server's documentation -+NOTE: The JWK Set URI is not standardized, but you can typically find it in the authorization server's documentation. - --Consequently, Resource Server will not ping the authorization server at startup. -+Consequently, Resource Server does not ping the authorization server at startup. - We still specify the `issuer-uri` so that Resource Server still validates the `iss` claim on incoming JWTs. - --[NOTE] --This property can also be supplied directly on the <>. -+NOTE: You can also supply this property directly on the <>. - - [[oauth2resourceserver-jwt-sansboot]] - === Overriding or Replacing Boot Auto Configuration - --There are two `@Bean` s that Spring Boot generates on Resource Server's behalf. -+There are two `@Bean` instances that Spring Boot generates on Resource Server's behalf. - --The first is a `WebSecurityConfigurerAdapter` that configures the app as a resource server. When including `spring-security-oauth2-jose`, this `WebSecurityConfigurerAdapter` looks like: -+The first is a `WebSecurityConfigurerAdapter` that configures the application as a resource server. When you include `spring-security-oauth2-jose`, this `WebSecurityConfigurerAdapter` looks like: - - .Default JWT Configuration - ==== -@@ -226,7 +224,7 @@ fun configure(http: HttpSecurity) { - ---- - ==== - --If the application doesn't expose a `WebSecurityConfigurerAdapter` bean, then Spring Boot will expose the above default one. -+If the application does not expose a `WebSecurityConfigurerAdapter` bean, Spring Boot exposes the preceding default one. - - Replacing this is as simple as exposing the bean within the application: - -@@ -274,9 +272,9 @@ class MyCustomSecurityConfiguration : WebSecurityConfigurerAdapter() { - ---- - ==== - --The above requires the scope of `message:read` for any URL that starts with `/messages/`. -+The preceding exmaple requires the scope of `message:read` for any URL that starts with `/messages/`. - --Methods on the `oauth2ResourceServer` DSL will also override or replace auto configuration. -+Methods on the `oauth2ResourceServer` DSL also override or replace auto-configuration. - - [[oauth2resourceserver-jwt-decoder]] - For example, the second `@Bean` Spring Boot creates is a `JwtDecoder`, which <>: -@@ -302,16 +300,15 @@ fun jwtDecoder(): JwtDecoder { - ---- - ==== - --[NOTE] --Calling `{security-api-url}org/springframework/security/oauth2/jwt/JwtDecoders.html#fromIssuerLocation-java.lang.String-[JwtDecoders#fromIssuerLocation]` is what invokes the Provider Configuration or Authorization Server Metadata endpoint in order to derive the JWK Set Uri. -+NOTE: Calling `{security-api-url}org/springframework/security/oauth2/jwt/JwtDecoders.html#fromIssuerLocation-java.lang.String-[JwtDecoders#fromIssuerLocation]` invokes the Provider Configuration or Authorization Server Metadata endpoint, to derive the JWK Set URI. - --If the application doesn't expose a `JwtDecoder` bean, then Spring Boot will expose the above default one. -+If the application does not expose a `JwtDecoder` bean, Spring Boot exposes the earlier default one. - --And its configuration can be overridden using `jwkSetUri()` or replaced using `decoder()`. -+You can override its configuration by using `jwkSetUri()` or replaced using `decoder()`. - --Or, if you're not using Spring Boot at all, then both of these components - the filter chain and a `JwtDecoder` can be specified in XML. -+Alternatively, if you do not use Spring Boot at all, you can specify both of these components (the filter chain and a `JwtDecoder`) in XML. - --The filter chain is specified like so: -+The filter chain is specified as follows: - - .Default JWT Configuration - ==== -@@ -327,7 +324,7 @@ The filter chain is specified like so: - ---- - ==== - --And the `JwtDecoder` like so: -+The `JwtDecoder` is specified as follows: - - .JWT Decoder - ==== -@@ -345,7 +342,7 @@ And the `JwtDecoder` like so: - [[oauth2resourceserver-jwt-jwkseturi-dsl]] - ==== Using `jwkSetUri()` - --An authorization server's JWK Set Uri can be configured <> or it can be supplied in the DSL: -+You can configure an authorization server's JWK Set URI <>, or you can supply it in the DSL: - - .JWK Set Uri Configuration - ==== -@@ -405,7 +402,7 @@ Using `jwkSetUri()` takes precedence over any configuration property. - [[oauth2resourceserver-jwt-decoder-dsl]] - ==== Using `decoder()` - --More powerful than `jwkSetUri()` is `decoder()`, which will completely replace any Boot auto configuration of <>: -+More powerful than `jwkSetUri()` is `decoder()`, which completely replaces any Boot auto configuration of <>: - - .JWT Decoder Configuration - ==== -@@ -460,12 +457,12 @@ class DirectlyConfiguredJwtDecoder : WebSecurityConfigurerAdapter() { - ---- - ==== - --This is handy when deeper configuration, like <>, <>, or <>, is necessary. -+This is handy when deeper configuration (such as <>, <>, or <>) is necessary. - - [[oauth2resourceserver-jwt-decoder-bean]] - ==== Exposing a `JwtDecoder` `@Bean` - --Or, exposing a <> `@Bean` has the same effect as `decoder()`: -+Alternatively, exposing a <> `@Bean` has the same effect as `decoder()`: - - ==== - .Java -@@ -490,15 +487,16 @@ fun jwtDecoder(): JwtDecoder { - [[oauth2resourceserver-jwt-decoder-algorithm]] - === Configuring Trusted Algorithms - --By default, `NimbusJwtDecoder`, and hence Resource Server, will only trust and verify tokens using `RS256`. -+By default, `NimbusJwtDecoder` and, hence, Resource Server, trust and verify tokens only that use `RS256`. - --You can customize this via <>, <>, or from the <>. -+You can customize this through <> or <> or from the <>. - - [[oauth2resourceserver-jwt-boot-algorithm]] - ==== Via Spring Boot - - The simplest way to set the algorithm is as a property: - -+==== - [source,yaml] - ---- - spring: -@@ -509,6 +507,7 @@ spring: - jws-algorithm: RS512 - jwk-set-uri: https://idp.example.org/.well-known/jwks.json - ---- -+==== - - [[oauth2resourceserver-jwt-decoder-builder]] - ==== Using a Builder -@@ -537,7 +536,7 @@ fun jwtDecoder(): JwtDecoder { - ---- - ==== - --Calling `jwsAlgorithm` more than once will configure `NimbusJwtDecoder` to trust more than one algorithm, like so: -+Calling `jwsAlgorithm` more than once configures `NimbusJwtDecoder` to trust more than one algorithm, as follows: - - ==== - .Java -@@ -561,7 +560,7 @@ fun jwtDecoder(): JwtDecoder { - ---- - ==== - --Or, you can call `jwsAlgorithms`: -+Alternatively, you can call `jwsAlgorithms`: - - ==== - .Java -@@ -594,10 +593,10 @@ fun jwtDecoder(): JwtDecoder { - [[oauth2resourceserver-jwt-decoder-jwk-response]] - ==== From JWK Set response - --Since Spring Security's JWT support is based off of Nimbus, you can use all it's great features as well. -+Since Spring Security's JWT support is based off of Nimbus, you can use all its great features as well. - --For example, Nimbus has a `JWSKeySelector` implementation that will select the set of algorithms based on the JWK Set URI response. --You can use it to generate a `NimbusJwtDecoder` like so: -+For example, Nimbus has a `JWSKeySelector` implementation that selects the set of algorithms, based on the JWK Set URI response. -+You can use it to generate a `NimbusJwtDecoder`, as follows: - - ==== - .Java -@@ -634,15 +633,16 @@ fun jwtDecoder(): JwtDecoder { - [[oauth2resourceserver-jwt-decoder-public-key]] - === Trusting a Single Asymmetric Key - --Simpler than backing a Resource Server with a JWK Set endpoint is to hard-code an RSA public key. --The public key can be provided via <> or by <>. -+Simpler than backing a Resource Server with a JWK Set endpoint is to hard code an RSA public key. -+The public key can be provided through <> or by <>. - - [[oauth2resourceserver-jwt-decoder-public-key-boot]] --==== Via Spring Boot -+==== Providing a Public Key through Spring Boot - --Specifying a key via Spring Boot is quite simple. --The key's location can be specified like so: -+With Spring Boot, -+you can specify the key's location: - -+==== - [source,yaml] - ---- - spring: -@@ -652,8 +652,9 @@ spring: - jwt: - public-key-location: classpath:my-key.pub - ---- -+==== - --Or, to allow for a more sophisticated lookup, you can post-process the `RsaKeyConversionServicePostProcessor`: -+Alternatively, to allow for a more sophisticated lookup, you can post-process the `RsaKeyConversionServicePostProcessor`: - - ==== - .Java -@@ -680,13 +681,16 @@ fun conversionServiceCustomizer(): BeanFactoryPostProcessor { - ---- - ==== - --Specify your key's location: -+To specify your key's location: - --```yaml -+==== -+[source,yaml] -+---- - key.location: hfds://my-key.pub --``` -+---- -+==== - --And then autowire the value: -+Then autowire the value: - - ==== - .Java -@@ -705,9 +709,9 @@ val key: RSAPublicKey? = null - ==== - - [[oauth2resourceserver-jwt-decoder-public-key-builder]] --==== Using a Builder -+==== Using a Builder to Provide a Public Key - --To wire an `RSAPublicKey` directly, you can simply use the appropriate `NimbusJwtDecoder` builder, like so: -+To wire an `RSAPublicKey` directly, you can use the appropriate `NimbusJwtDecoder` builder: - - ==== - .Java -@@ -732,8 +736,7 @@ fun jwtDecoder(): JwtDecoder { - [[oauth2resourceserver-jwt-decoder-secret-key]] - === Trusting a Single Symmetric Key - --Using a single symmetric key is also simple. --You can simply load in your `SecretKey` and use the appropriate `NimbusJwtDecoder` builder, like so: -+To use a single symmetric key, you can load in your `SecretKey` and use the appropriate `NimbusJwtDecoder` builder: - - ==== - .Java -@@ -758,13 +761,13 @@ fun jwtDecoder(): JwtDecoder { - [[oauth2resourceserver-jwt-authorization]] - === Configuring Authorization - --A JWT that is issued from an OAuth 2.0 Authorization Server will typically either have a `scope` or `scp` attribute, indicating the scopes (or authorities) it's been granted, for example: -+A JWT that is issued from an OAuth 2.0 Authorization Server typically have either a `scope` or an `scp` attribute, indicating the scopes (or authorities) it has been granted -- for example: - - `{ ..., "scope" : "messages contacts"}` - --When this is the case, Resource Server will attempt to coerce these scopes into a list of granted authorities, prefixing each scope with the string "SCOPE_". -+When this is the case, Resource Server tries to coerce these scopes into a list of granted authorities, prefixing each scope with the string, `SCOPE_`. - --This means that to protect an endpoint or method with a scope derived from a JWT, the corresponding expressions should include this prefix: -+This means that, to protect an endpoint or method with a scope derived from a JWT, the corresponding expressions should include this prefix: - - .Authorization Configuration - ==== -@@ -818,28 +821,30 @@ class DirectlyConfiguredJwkSetUri : WebSecurityConfigurerAdapter() { - ---- - ==== - --Or similarly with method security: -+A similar arrangement applies to method security: - -+==== - [source,java] - ---- - @PreAuthorize("hasAuthority('SCOPE_messages')") - public List getMessages(...) {} - ---- -+==== - - [[oauth2resourceserver-jwt-authorization-extraction]] - ==== Extracting Authorities Manually - - However, there are a number of circumstances where this default is insufficient. --For example, some authorization servers don't use the `scope` attribute, but instead have their own custom attribute. --Or, at other times, the resource server may need to adapt the attribute or a composition of attributes into internalized authorities. -+For example, some authorization servers do not use the `scope` attribute but, instead, have their own custom attribute. -+At other times, the resource server may need to adapt the attribute or a composition of attributes into internalized authorities. - - To this end, Spring Security ships with `JwtAuthenticationConverter`, which is responsible for <>. --By default, Spring Security will wire the `JwtAuthenticationProvider` with a default instance of `JwtAuthenticationConverter`. -+By default, Spring Security wires the `JwtAuthenticationProvider` with a default instance of `JwtAuthenticationConverter`. - - As part of configuring a `JwtAuthenticationConverter`, you can supply a subsidiary converter to go from `Jwt` to a `Collection` of granted authorities. - --Let's say that that your authorization server communicates authorities in a custom claim called `authorities`. --In that case, you can configure the claim that <> should inspect, like so: -+Suppose your authorization server communicates authorities in a custom claim called `authorities`. -+In that case, you can configure the claim that <> should inspect: - - .Authorities Claim Configuration - ==== -@@ -896,7 +901,7 @@ fun jwtAuthenticationConverter(): JwtAuthenticationConverter { - ==== - - You can also configure the authority prefix to be different as well. --Instead of prefixing each authority with `SCOPE_`, you can change it to `ROLE_` like so: -+Instead of prefixing each authority with `SCOPE_`, you can change it to `ROLE_`: - - .Authorities Prefix Configuration - ==== -@@ -952,7 +957,7 @@ fun jwtAuthenticationConverter(): JwtAuthenticationConverter { - ---- - ==== - --Or, you can remove the prefix altogether by calling `JwtGrantedAuthoritiesConverter#setAuthorityPrefix("")`. -+Alternatively, you can remove the prefix altogether by calling `JwtGrantedAuthoritiesConverter#setAuthorityPrefix("")`. - - For more flexibility, the DSL supports entirely replacing the converter with any class that implements `Converter`: - -@@ -1016,7 +1021,7 @@ class CustomAuthenticationConverterConfig : WebSecurityConfigurerAdapter() { - [[oauth2resourceserver-jwt-validation]] - === Configuring Validation - --Using <>, indicating the authorization server's issuer uri, Resource Server will default to verifying the `iss` claim as well as the `exp` and `nbf` timestamp claims. -+Using <> and indicating the authorization server's issuer URI, Resource Server defaults to verifying the `iss` claim as well as the `exp` and `nbf` timestamp claims. - - In circumstances where validation needs to be customized, Resource Server ships with two standard validators and also accepts custom `OAuth2TokenValidator` instances. - -@@ -1025,10 +1030,10 @@ In circumstances where validation needs to be customized, Resource Server ships - - JWT's typically have a window of validity, with the start of the window indicated in the `nbf` claim and the end indicated in the `exp` claim. - --However, every server can experience clock drift, which can cause tokens to appear expired to one server, but not to another. -+However, every server can experience clock drift, which can cause tokens to appear to be expired to one server but not to another. - This can cause some implementation heartburn as the number of collaborating servers increases in a distributed system. - --Resource Server uses `JwtTimestampValidator` to verify a token's validity window, and it can be configured with a `clockSkew` to alleviate the above problem: -+Resource Server uses `JwtTimestampValidator` to verify a token's validity window, and you can configure it with a `clockSkew` to alleviate the problem of clock drift: - - ==== - .Java -@@ -1067,13 +1072,12 @@ fun jwtDecoder(): JwtDecoder { - ---- - ==== - --[NOTE] --By default, Resource Server configures a clock skew of 30 seconds. -+NOTE: By default, Resource Server configures a clock skew of 30 seconds. - - [[oauth2resourceserver-jwt-validation-custom]] - ==== Configuring a Custom Validator - --Adding a check for the `aud` claim is simple with the `OAuth2TokenValidator` API: -+You can use the `OAuth2TokenValidator` API to add a check for the `aud` claim: - - ==== - .Java -@@ -1093,7 +1097,7 @@ fun audienceValidator(): OAuth2TokenValidator { - ---- - ==== - --Or, for more control you can implement your own `OAuth2TokenValidator`: -+Alternatively, for more control, you can implement your own `OAuth2TokenValidator`: - - ==== - .Java -@@ -1142,7 +1146,7 @@ fun audienceValidator(): OAuth2TokenValidator { - ---- - ==== - --Then, to add into a resource server, it's a matter of specifying the <> instance: -+Then, to add into a resource server, you can specify the <> instance: - - ==== - .Java -@@ -1184,21 +1188,21 @@ fun jwtDecoder(): JwtDecoder { - [[oauth2resourceserver-jwt-claimsetmapping]] - === Configuring Claim Set Mapping - --Spring Security uses the https://bitbucket.org/connect2id/nimbus-jose-jwt/wiki/Home[Nimbus] library for parsing JWTs and validating their signatures. -+Spring Security uses the https://bitbucket.org/connect2id/nimbus-jose-jwt/wiki/Home[Nimbus] library to parse JWTs and validate their signatures. - Consequently, Spring Security is subject to Nimbus's interpretation of each field value and how to coerce each into a Java type. - --For example, because Nimbus remains Java 7 compatible, it doesn't use `Instant` to represent timestamp fields. -+For example, because Nimbus remains Java 7 compatible, it does not use `Instant` to represent timestamp fields. - --And it's entirely possible to use a different library or for JWT processing, which may make its own coercion decisions that need adjustment. -+Also, it is entirely possible to use a different library or for JWT processing, which may make its own coercion decisions that need adjustment. - --Or, quite simply, a resource server may want to add or remove claims from a JWT for domain-specific reasons. -+Put differently, a resource server may want to add or remove claims from a JWT for domain-specific reasons. - - For these purposes, Resource Server supports mapping the JWT claim set with `MappedJwtClaimSetConverter`. - - [[oauth2resourceserver-jwt-claimsetmapping-singleclaim]] - ==== Customizing the Conversion of a Single Claim - --By default, `MappedJwtClaimSetConverter` will attempt to coerce claims into the following types: -+By default, `MappedJwtClaimSetConverter` tries to coerce claims into the following types: - - |============ - | Claim | Java Type -@@ -1211,7 +1215,7 @@ By default, `MappedJwtClaimSetConverter` will attempt to coerce claims into the - | `sub` | `String` - |============ - --An individual claim's conversion strategy can be configured using `MappedJwtClaimSetConverter.withDefaults`: -+You can configure an individual claim's conversion strategy by using `MappedJwtClaimSetConverter.withDefaults`: - - ==== - .Java -@@ -1244,12 +1248,13 @@ fun jwtDecoder(): JwtDecoder { - } - ---- - ==== --This will keep all the defaults, except it will override the default claim converter for `sub`. -+ -+This approach keeps all the defaults, except that it overrides the default claim converter for `sub`. - - [[oauth2resourceserver-jwt-claimsetmapping-add]] - ==== Adding a Claim - --`MappedJwtClaimSetConverter` can also be used to add a custom claim, for example, to adapt to an existing system: -+`MappedJwtClaimSetConverter` can also be used to add a custom claim -- for example, to adapt to an existing system: - - ==== - .Java -@@ -1268,7 +1273,7 @@ MappedJwtClaimSetConverter.withDefaults(mapOf("custom" to Converter - [[oauth2resourceserver-jwt-claimsetmapping-remove]] - ==== Removing a Claim - --And removing a claim is also simple, using the same API: -+And removing a claim is also simple, by using the same API: - - ==== - .Java -@@ -1323,7 +1328,7 @@ class UsernameSubClaimAdapter : Converter, Map> - ---- - ==== - --And then, the instance can be supplied like normal: -+Then you can supply the instance in the normal way: - - ==== - .Java -@@ -1355,7 +1360,7 @@ fun jwtDecoder(): JwtDecoder { - By default, Resource Server uses connection and socket timeouts of 30 seconds each for coordinating with the authorization server. - - This may be too short in some scenarios. --Further, it doesn't take into account more sophisticated patterns like back-off and discovery. -+Further, it does not take into account more sophisticated patterns like back-off and discovery. - - To adjust the way in which Resource Server connects to the authorization server, `NimbusJwtDecoder` accepts an instance of `RestOperations`: - -@@ -1389,8 +1394,8 @@ fun jwtDecoder(builder: RestTemplateBuilder): JwtDecoder { - ---- - ==== - --Also by default, Resource Server caches in-memory the authorization server's JWK set for 5 minutes, which you may want to adjust. --Further, it doesn't take into account more sophisticated caching patterns like eviction or using a shared cache. -+Also, by default, Resource Server caches (in memory) the authorization server's JWK set for 5 minutes, which you may want to adjust. -+Further, it does not take into account more sophisticated caching patterns, such as eviction or using a shared cache. - - To adjust the way in which Resource Server caches the JWK set, `NimbusJwtDecoder` accepts an instance of `Cache`: - -@@ -1418,34 +1423,37 @@ fun jwtDecoder(cacheManager: CacheManager): JwtDecoder { - ---- - ==== - --When given a `Cache`, Resource Server will use the JWK Set Uri as the key and the JWK Set JSON as the value. -+When given a `Cache`, Resource Server uses the JWK Set URI as the key and the JWK Set JSON as the value. - --NOTE: Spring isn't a cache provider, so you'll need to make sure to include the appropriate dependencies, like `spring-boot-starter-cache` and your favorite caching provider. -+NOTE: Spring is not a cache provider, so you need to make sure to include the appropriate dependencies, such as `spring-boot-starter-cache` and your favorite caching provider. - --NOTE: Whether it's socket or cache timeouts, you may instead want to work with Nimbus directly. -+NOTE: Whether it is socket or cache timeouts, you may instead want to work with Nimbus directly. - To do so, remember that `NimbusJwtDecoder` ships with a constructor that takes Nimbus's `JWTProcessor`. - - [[oauth2resourceserver-opaque-minimaldependencies]] - === Minimal Dependencies for Introspection - As described in <> most of Resource Server support is collected in `spring-security-oauth2-resource-server`. --However unless a custom <> is provided, the Resource Server will fallback to NimbusOpaqueTokenIntrospector. --Meaning that both `spring-security-oauth2-resource-server` and `oauth2-oidc-sdk` are necessary in order to have a working minimal Resource Server that supports opaque Bearer Tokens. --Please refer to `spring-security-oauth2-resource-server` in order to determin the correct version for `oauth2-oidc-sdk`. -+However, unless a custom <> is provided, Resource Server falls back to NimbusOpaqueTokenIntrospector. -+This means that both `spring-security-oauth2-resource-server` and `oauth2-oidc-sdk` are necessary to have a working minimal Resource Server that supports opaque Bearer Tokens. -+See `spring-security-oauth2-resource-server` to determine the correct version for `oauth2-oidc-sdk`. - - [[oauth2resourceserver-opaque-minimalconfiguration]] - === Minimal Configuration for Introspection - --Typically, an opaque token can be verified via an https://tools.ietf.org/html/rfc7662[OAuth 2.0 Introspection Endpoint], hosted by the authorization server. -+Typically, you can verify an opaque token through an https://tools.ietf.org/html/rfc7662[OAuth 2.0 Introspection Endpoint], hosted by the authorization server. - This can be handy when revocation is a requirement. - --When using https://spring.io/projects/spring-boot[Spring Boot], configuring an application as a resource server that uses introspection consists of two basic steps. --First, include the needed dependencies and second, indicate the introspection endpoint details. -+When you use https://spring.io/projects/spring-boot[Spring Boot], configuring an application as a resource server that uses introspection consists of two basic steps: -+ -+. Include the needed dependencies. -+. Indicate the introspection endpoint details. - - [[oauth2resourceserver-opaque-introspectionuri]] - ==== Specifying the Authorization Server - --To specify where the introspection endpoint is, simply do: -+The following exmaple specifies where the introspection endpoint is: - -+==== - [source,yaml] - ---- - security: -@@ -1456,39 +1464,40 @@ security: - client-id: client - client-secret: secret - ---- -+==== - - Where `https://idp.example.com/introspect` is the introspection endpoint hosted by your authorization server and `client-id` and `client-secret` are the credentials needed to hit that endpoint. - --Resource Server will use these properties to further self-configure and subsequently validate incoming JWTs. -- --[NOTE] --When using introspection, the authorization server's word is the law. --If the authorization server responses that the token is valid, then it is. -+Resource Server uses these properties to further self-configure and subsequently validate incoming JWTs. - --And that's it! -+NOTE: When using introspection, the authorization server's word is law. -+If the authorization server responsed that the token is valid, it is. - - ==== Startup Expectations - --When this property and these dependencies are used, Resource Server will automatically configure itself to validate Opaque Bearer Tokens. -+When this property and these dependencies are used, Resource Server automatically configures itself to validate Opaque Bearer Tokens. - --This startup process is quite a bit simpler than for JWTs since no endpoints need to be discovered and no additional validation rules get added. -+This startup process is quite a bit simpler than for JWTs, since no endpoints need to be discovered and no additional validation rules get added. - - ==== Runtime Expectations - --Once the application is started up, Resource Server will attempt to process any request containing an `Authorization: Bearer` header: -+Once the application has started, Resource Server tries to process any request containing an `Authorization: Bearer` header: - --```http -+==== -+[source,text] -+---- - GET / HTTP/1.1 - Authorization: Bearer some-token-value # Resource Server will process this --``` -+---- -+==== - --So long as this scheme is indicated, Resource Server will attempt to process the request according to the Bearer Token specification. -+So long as this scheme is indicated, Resource Server tries to process the request according to the Bearer Token specification. - --Given an Opaque Token, Resource Server will -+Given an Opaque Token, Resource Server: - --1. Query the provided introspection endpoint using the provided credentials and the token --2. Inspect the response for an `{ 'active' : true }` attribute --3. Map each scope to an authority with the prefix `SCOPE_` -+1. Queries the provided introspection endpoint by using the provided credentials and the token. -+2. Inspects the response for an `{ 'active' : true }` attribute. -+3. Maps each scope to an authority with a prefix of `SCOPE_`. - - The resulting `Authentication#getPrincipal`, by default, is a Spring Security `{security-api-url}org/springframework/security/oauth2/core/OAuth2AuthenticatedPrincipal.html[OAuth2AuthenticatedPrincipal]` object, and `Authentication#getName` maps to the token's `sub` property, if one is present. - -@@ -1502,12 +1511,12 @@ From here, you may want to jump to: - [[oauth2resourceserver-opaque-architecture]] - === How Opaque Token Authentication Works - --Next, let's see the architectural components that Spring Security uses to support https://tools.ietf.org/html/rfc7662[opaque token] Authentication in servlet-based applications, like the one we just saw. -+Next, let's see the architectural components that Spring Security uses to support https://tools.ietf.org/html/rfc7662[opaque token] authentication in servlet-based applications, such as the one we examined earlier in this chapter. - - {security-api-url}org/springframework/security/oauth2/server/resource/authentication/OpaqueTokenAuthenticationProvider.html[`OpaqueTokenAuthenticationProvider`] is an <> implementation that leverages a <> to authenticate an opaque token. - --Let's take a look at how `OpaqueTokenAuthenticationProvider` works within Spring Security. --The figure explains details of how the <> in figures from <> works. -+Now we examine how `OpaqueTokenAuthenticationProvider` works within Spring Security. -+The figure details how the <> in figures from <> works. - - .`OpaqueTokenAuthenticationProvider` Usage - image::{figures}/opaquetokenauthenticationprovider.png[] -@@ -1517,16 +1526,16 @@ image:{icondir}/number_1.png[] The authentication `Filter` from <> of type `OpaqueTokenAuthenticationProvider`. - - [[oauth2resourceserver-opaque-architecture-introspector]] --image:{icondir}/number_3.png[] `OpaqueTokenAuthenticationProvider` introspects the opaque token and adds granted authorities using an <>. -+image:{icondir}/number_3.png[] `OpaqueTokenAuthenticationProvider` introspects the opaque token and adds granted authorities by using an <>. - When authentication is successful, the <> that is returned is of type `BearerTokenAuthentication` and has a principal that is the `OAuth2AuthenticatedPrincipal` returned by the configured <>. --Ultimately, the returned `BearerTokenAuthentication` will be set on the <> by the authentication `Filter`. -+Ultimately, the returned `BearerTokenAuthentication` is set on the <> by the authentication `Filter`. - - [[oauth2resourceserver-opaque-attributes]] - === Looking Up Attributes Post-Authentication - - Once a token is authenticated, an instance of `BearerTokenAuthentication` is set in the `SecurityContext`. - --This means that it's available in `@Controller` methods when using `@EnableWebMvc` in your configuration: -+This means that it is available in `@Controller` methods when you use `@EnableWebMvc` in your configuration: - - ==== - .Java -@@ -1548,7 +1557,7 @@ fun foo(authentication: BearerTokenAuthentication): String { - ---- - ==== - --Since `BearerTokenAuthentication` holds an `OAuth2AuthenticatedPrincipal`, that also means that it's available to controller methods, too: -+Since `BearerTokenAuthentication` holds an `OAuth2AuthenticatedPrincipal`, that also means that it is available to controller methods, too: - - ==== - .Java -@@ -1570,11 +1579,11 @@ fun foo(@AuthenticationPrincipal principal: OAuth2AuthenticatedPrincipal): Strin - ---- - ==== - --==== Looking Up Attributes Via SpEL -+==== Looking Up Attributes with SpEL - --Of course, this also means that attributes can be accessed via SpEL. -+Of course, this also means that attributes can be accessed with SpEL (Spring Expression Language). - --For example, if using `@EnableGlobalMethodSecurity` so that you can use `@PreAuthorize` annotations, you can do: -+For example, if you use `@EnableGlobalMethodSecurity` so that you can use `@PreAuthorize` annotations, you can use: - - ==== - .Java -@@ -1599,10 +1608,10 @@ fun forFoosEyesOnly(): String { - [[oauth2resourceserver-opaque-sansboot]] - === Overriding or Replacing Boot Auto Configuration - --There are two `@Bean` s that Spring Boot generates on Resource Server's behalf. -+There are two `@Bean` instances that Spring Boot generates on Resource Server's behalf. - --The first is a `WebSecurityConfigurerAdapter` that configures the app as a resource server. --When use Opaque Token, this `WebSecurityConfigurerAdapter` looks like: -+The first is a `WebSecurityConfigurerAdapter` that configures the application as a resource server. -+When you use Opaque Token, this `WebSecurityConfigurerAdapter` looks like: - - .Default Opaque Token Configuration - ==== -@@ -1634,9 +1643,9 @@ override fun configure(http: HttpSecurity) { - ---- - ==== - --If the application doesn't expose a `WebSecurityConfigurerAdapter` bean, then Spring Boot will expose the above default one. -+If the application does not expose a `WebSecurityConfigurerAdapter` bean, Spring Boot exposes the preceding default one. - --Replacing this is as simple as exposing the bean within the application: -+Replacing this involves exposing the bean within the application: - - .Custom Opaque Token Configuration - ==== -@@ -1682,12 +1691,12 @@ class MyCustomSecurityConfiguration : WebSecurityConfigurerAdapter() { - ---- - ==== - --The above requires the scope of `message:read` for any URL that starts with `/messages/`. -+The preceding example requires the scope of `message:read` for any URL that starts with `/messages/`. - --Methods on the `oauth2ResourceServer` DSL will also override or replace auto configuration. -+Methods on the `oauth2ResourceServer` DSL also override or replace auto configuration. - - [[oauth2resourceserver-opaque-introspector]] --For example, the second `@Bean` Spring Boot creates is an `OpaqueTokenIntrospector`, <>: -+For example, the second `@Bean` that Spring Boot creates is an `OpaqueTokenIntrospector`, <>: - - ==== - .Java -@@ -1709,11 +1718,11 @@ fun introspector(): OpaqueTokenIntrospector { - ---- - ==== - --If the application doesn't expose a <> bean, then Spring Boot will expose the above default one. -+If the application does not expose a <> bean, Spring Boot exposes the preceding default one. - --And its configuration can be overridden using `introspectionUri()` and `introspectionClientCredentials()` or replaced using `introspector()`. -+You can override its configuration by using `introspectionUri()` and `introspectionClientCredentials()` or replace it by using `introspector()`. - --Or, if you're not using Spring Boot at all, then both of these components - the filter chain and a <> can be specified in XML. -+Alternatively, if you do not use Spring Boot at all, you can specify both of these components (the filter chain and a <>) in XML. - - The filter chain is specified like so: - -@@ -1750,7 +1759,7 @@ And the <> or it can be supplied in the DSL: -+You can configure an authorization server's introspection URI <> or supply it in the DSL: - - .Introspection URI Configuration - ==== -@@ -1812,7 +1821,7 @@ Using `introspectionUri()` takes precedence over any configuration property. - [[oauth2resourceserver-opaque-introspector-dsl]] - ==== Using `introspector()` - --More powerful than `introspectionUri()` is `introspector()`, which will completely replace any Boot auto configuration of <>: -+More powerful than `introspectionUri()` is `introspector()`, which completely replaces any Boot auto-configuration of <>: - - .Introspector Configuration - ==== -@@ -1867,13 +1876,14 @@ class DirectlyConfiguredIntrospector : WebSecurityConfigurerAdapter() { - ---- - ==== - --This is handy when deeper configuration, like <>, <>, or <>, is necessary. -+This is handy when deeper configuration (such as <>, <>, or <>) is necessary. - - [[oauth2resourceserver-opaque-introspector-bean]] - ==== Exposing a `OpaqueTokenIntrospector` `@Bean` - --Or, exposing a <> `@Bean` has the same effect as `introspector()`: -+Alternatively, exposing an <> `@Bean` has the same effect as `introspector()`: - -+==== - [source,java] - ---- - @Bean -@@ -1881,17 +1891,18 @@ public OpaqueTokenIntrospector introspector() { - return new NimbusOpaqueTokenIntrospector(introspectionUri, clientId, clientSecret); - } - ---- -+==== - - [[oauth2resourceserver-opaque-authorization]] - === Configuring Authorization - --An OAuth 2.0 Introspection endpoint will typically return a `scope` attribute, indicating the scopes (or authorities) it's been granted, for example: -+An OAuth 2.0 Introspection endpoint typically returns a `scope` attribute, indicating the scopes (or authorities) it has been granted -- for example: - - `{ ..., "scope" : "messages contacts"}` - --When this is the case, Resource Server will attempt to coerce these scopes into a list of granted authorities, prefixing each scope with the string "SCOPE_". -+When this is the case, Resource Server tries to coerce these scopes into a list of granted authorities, prefixing each scope with the string "SCOPE_". - --This means that to protect an endpoint or method with a scope derived from an Opaque Token, the corresponding expressions should include this prefix: -+This means that, to protect an endpoint or method with a scope derived from an Opaque Token, the corresponding expressions should include this prefix: - - .Authorization Opaque Token Configuration - ==== -@@ -1945,7 +1956,7 @@ class MappedAuthorities : WebSecurityConfigurerAdapter() { - ---- - ==== - --Or similarly with method security: -+Method security requires a similar approach: - - ==== - .Java -@@ -1966,10 +1977,11 @@ fun getMessages(): List {} - [[oauth2resourceserver-opaque-authorization-extraction]] - ==== Extracting Authorities Manually - --By default, Opaque Token support will extract the scope claim from an introspection response and parse it into individual `GrantedAuthority` instances. -+By default, Opaque Token support extracts the scope claim from an introspection response and parse it into individual `GrantedAuthority` instances. - --For example, if the introspection response were: -+For example, consider the following introspection response: - -+==== - [source,json] - ---- - { -@@ -1977,10 +1989,11 @@ For example, if the introspection response were: - "scope" : "message:read message:write" - } - ---- -+==== - --Then Resource Server would generate an `Authentication` with two authorities, one for `message:read` and the other for `message:write`. -+Given that response, Resource Server would generate an `Authentication` with two authorities, one for `message:read` and the other for `message:write`. - --This can, of course, be customized using a custom <> that takes a look at the attribute set and converts in its own way: -+You can customize this can be customized by using a custom <> that examines the attribute set and converts in its own way: - - ==== - .Java -@@ -2025,7 +2038,7 @@ class CustomAuthoritiesOpaqueTokenIntrospector : OpaqueTokenIntrospector { - ---- - ==== - --Thereafter, this custom introspector can be configured simply by exposing it as a `@Bean`: -+Thereafter, you can configure this custom introspector by exposing it as a `@Bean`: - - ==== - .Java -@@ -2050,10 +2063,10 @@ fun introspector(): OpaqueTokenIntrospector { - [[oauth2resourceserver-opaque-timeouts]] - === Configuring Timeouts - --By default, Resource Server uses connection and socket timeouts of 30 seconds each for coordinating with the authorization server. -+By default, Resource Server uses connection and socket timeouts of 30 seconds each to coordinate with the authorization server. - --This may be too short in some scenarios. --Further, it doesn't take into account more sophisticated patterns like back-off and discovery. -+In some scenarios this value may be too short. -+Further, it does not take into account more sophisticated patterns, such as backing off and discovery. - - To adjust the way in which Resource Server connects to the authorization server, `NimbusOpaqueTokenIntrospector` accepts an instance of `RestOperations`: - -@@ -2092,12 +2105,13 @@ fun introspector(builder: RestTemplateBuilder, properties: OAuth2ResourceServerP - === Using Introspection with JWTs - - A common question is whether or not introspection is compatible with JWTs. --Spring Security's Opaque Token support has been designed to not care about the format of the token -- it will gladly pass any token to the introspection endpoint provided. -+Spring Security's Opaque Token support has been designed to not care about the format of the token -- it gladly passes any token to the provided introspection endpoint. - --So, let's say that you've got a requirement that requires you to check with the authorization server on each request, in case the JWT has been revoked. -+So, suppose you have a requirement to check with the authorization server on each request, in case the JWT has been revoked. - --Even though you are using the JWT format for the token, your validation method is introspection, meaning you'd want to do: -+Even though you use the JWT format for the token, your validation method is introspection, meaning that you want to do: - -+==== - [source,yaml] - ---- - spring: -@@ -2109,14 +2123,15 @@ spring: - client-id: client - client-secret: secret - ---- -+==== - --In this case, the resulting `Authentication` would be `BearerTokenAuthentication`. -+In this case, the resulting `Authentication` is `BearerTokenAuthentication`. - Any attributes in the corresponding `OAuth2AuthenticatedPrincipal` would be whatever was returned by the introspection endpoint. - --But, let's say that, oddly enough, the introspection endpoint only returns whether or not the token is active. -+However, suppose that, oddly enough, the introspection endpoint returns only whether or not the token is active. - Now what? - --In this case, you can create a custom <> that still hits the endpoint, but then updates the returned principal to have the JWTs claims as the attributes: -+In that case, you can create a custom <> that still hits the endpoint but then updates the returned principal to have the JWTs claims as the attributes: - - ==== - .Java -@@ -2171,7 +2186,7 @@ class JwtOpaqueTokenIntrospector : OpaqueTokenIntrospector { - ---- - ==== - --Thereafter, this custom introspector can be configured simply by exposing it as a `@Bean`: -+Thereafter, you can configure this custom introspector by exposing it as a `@Bean`: - - ==== - .Java -@@ -2196,12 +2211,12 @@ fun introspector(): OpaqueTokenIntrospector { - [[oauth2resourceserver-opaque-userinfo]] - === Calling a `/userinfo` Endpoint - --Generally speaking, a Resource Server doesn't care about the underlying user, but instead about the authorities that have been granted. -+Generally speaking, a Resource Server does not care about the underlying user but, instead, cares about the authorities that have been granted. - --That said, at times it can be valuable to tie the authorization statement back to a user. -+That said, at times, it can be valuable to tie the authorization statement back to a user. - --If an application is also using `spring-security-oauth2-client`, having set up the appropriate `ClientRegistrationRepository`, then this is quite simple with a custom <>. --This implementation below does three things: -+If an application also uses `spring-security-oauth2-client`, having set up the appropriate `ClientRegistrationRepository`, then this is possible with a custom <>. -+The implementation shown in the next listing does three things: - - * Delegates to the introspection endpoint, to affirm the token's validity - * Looks up the appropriate client registration associated with the `/userinfo` endpoint -@@ -2256,8 +2271,8 @@ class UserInfoOpaqueTokenIntrospector : OpaqueTokenIntrospector { - ---- - ==== - --If you aren't using `spring-security-oauth2-client`, it's still quite simple. --You will simply need to invoke the `/userinfo` with your own instance of `WebClient`: -+If you do not use `spring-security-oauth2-client`, it is still possible. -+You need to invoke the `/userinfo` with your own instance of `WebClient`: - - ==== - .Java -@@ -2316,10 +2331,10 @@ fun introspector(): OpaqueTokenIntrospector { - [[oauth2reourceserver-opaqueandjwt]] - === Supporting both JWT and Opaque Token - --In some cases, you may have a need to access both kinds of tokens. --For example, you may support more than one tenant where one tenant issues JWTs and the other issues opaque tokens. -+In some cases, you may need to access both kinds of tokens. -+For example, you may support more than one tenant, where one tenant issues JWTs and the other issues opaque tokens. - --If this decision must be made at request-time, then you can use an `AuthenticationManagerResolver` to achieve it, like so: -+If this decision must be made at request-time, you can use an `AuthenticationManagerResolver` to achieve it: - - ==== - .Java -@@ -2361,9 +2376,9 @@ fun tokenAuthenticationManagerResolver(): AuthenticationManagerResolver A hypothetical source for tenant information. -+<2> A cache for `JWKKeySelector`s, keyed by tenant identifier. -+<3> Looking up the tenant is more secure than calculating the JWK Set endpoint on the fly -- the lookup acts as a list of allowed tenants. -+<4> Create a `JWSKeySelector` through the types of keys that come back from the JWK Set endpoint -- the lazy lookup here means that you need not configure all tenants at startup. - ==== --<1> A hypothetical source for tenant information --<2> A cache for `JWKKeySelector`s, keyed by tenant identifier --<3> Looking up the tenant is more secure than simply calculating the JWK Set endpoint on the fly - the lookup acts as a list of allowed tenants --<4> Create a `JWSKeySelector` via the types of keys that come back from the JWK Set endpoint - the lazy lookup here means that you don't need to configure all tenants at startup - --The above key selector is a composition of many key selectors. -+The preceding key selector is a composition of many key selectors. - It chooses which key selector to use based on the `iss` claim in the JWT. - - NOTE: To use this approach, make sure that the authorization server is configured to include the claim set as part of the token's signature. --Without this, you have no guarantee that the issuer hasn't been altered by a bad actor. -+Without this, you have no guarantee that the issuer has not been altered by a bad actor. - - Next, we can construct a `JWTProcessor`: - -@@ -2661,8 +2676,8 @@ fun jwtProcessor(keySelector: JWTClaimsSetAwareJWSKeySelector): - As you are already seeing, the trade-off for moving tenant-awareness down to this level is more configuration. - We have just a bit more. - --Next, we still want to make sure you are validating the issuer. --But, since the issuer may be different per JWT, then you'll need a tenant-aware validator, too: -+Next, we still want to make sure you validate the issuer. -+However, since the issuer may differ per JWT, you need a tenant-aware validator, too: - - ==== - .Java -@@ -2755,10 +2770,10 @@ fun jwtDecoder(jwtProcessor: JWTProcessor?, jwtValidator: OAuth - ---- - ==== - --We've finished talking about resolving the tenant. -+We have finished talking about resolving the tenant. - --If you've chosen to resolve the tenant by something other than a JWT claim, then you'll need to make sure you address your downstream resource servers in the same way. --For example, if you are resolving it by subdomain, you may need to address the downstream resource server using the same subdomain. -+If you chose to resolve the tenant by something other than a JWT claim, you need to make sure you address your downstream resource servers in the same way. -+For example, if you resolve it by subdomain, you may need to address the downstream resource server by using the same subdomain. - - However, if you resolve it by a claim in the bearer token, read on to learn about <>. - -@@ -2766,12 +2781,12 @@ However, if you resolve it by a claim in the bearer token, read on to learn abou - === Bearer Token Resolution - - By default, Resource Server looks for a bearer token in the `Authorization` header. --This, however, can be customized in a handful of ways. -+However, you can customize this in a handful of ways. - - ==== Reading the Bearer Token from a Custom Header - --For example, you may have a need to read the bearer token from a custom header. --To achieve this, you can expose a `DefaultBearerTokenResolver` as a bean, or wire an instance into the DSL, as you can see in the following example: -+For example, you may need to read the bearer token from a custom header. -+To do so, you can expose a `DefaultBearerTokenResolver` as a bean or wire an instance into the DSL, as follows: - - .Custom Bearer Token Header - ==== -@@ -2811,11 +2826,11 @@ fun bearerTokenResolver(): BearerTokenResolver { - ---- - ==== - --Or, in circumstances where a provider is using both a custom header and value, you can use `HeaderBearerTokenResolver` instead. -+Alternatively, in circumstances where a provider uses both a custom header and value, you can use `HeaderBearerTokenResolver` instead. - - ==== Reading the Bearer Token from a Form Parameter - --Or, you may wish to read the token from a form parameter, which you can do by configuring the `DefaultBearerTokenResolver`, as you can see below: -+Alternatively, you may wish to read the token from a form parameter, which you can do by configuring the `DefaultBearerTokenResolver`: - - .Form Parameter Bearer Token - ==== -@@ -2858,8 +2873,8 @@ http { - - === Bearer Token Propagation - --Now that you're resource server has validated the token, it might be handy to pass it to downstream services. --This is quite simple with `{security-api-url}org/springframework/security/oauth2/server/resource/web/reactive/function/client/ServletBearerExchangeFilterFunction.html[ServletBearerExchangeFilterFunction]`, which you can see in the following example: -+Now that your resource server has validated the token, it might be handy to pass it to downstream services. -+This is possible with {security-api-url}org/springframework/security/oauth2/server/resource/web/reactive/function/client/ServletBearerExchangeFilterFunction.html[`ServletBearerExchangeFilterFunction`]: - - ==== - .Java -@@ -2885,10 +2900,8 @@ fun rest(): WebClient { - ---- - ==== - --When the above `WebClient` is used to perform requests, Spring Security will look up the current `Authentication` and extract any `{security-api-url}org/springframework/security/oauth2/core/AbstractOAuth2Token.html[AbstractOAuth2Token]` credential. --Then, it will propagate that token in the `Authorization` header. -- --For example: -+When the `WebClient` performs requests, Spring Security looks up the current `Authentication` and extracts any `{security-api-url}org/springframework/security/oauth2/core/AbstractOAuth2Token.html[`AbstractOAuth2Token`]` credential. -+Then it propagates that token in the `Authorization` header: - - ==== - .Java -@@ -2912,9 +2925,9 @@ this.rest.get() - ---- - ==== - --Will invoke the `https://other-service.example.com/endpoint`, adding the bearer token `Authorization` header for you. -+The preceding code invokes the `https://other-service.example.com/endpoint`, adding the bearer token `Authorization` header for you. - --In places where you need to override this behavior, it's a simple matter of supplying the header yourself, like so: -+In places where you need to override this behavior, you can supply the header yourself: - - ==== - .Java -@@ -2940,15 +2953,14 @@ this.rest.get() - ---- - ==== - --In this case, the filter will fall back and simply forward the request onto the rest of the web filter chain. -+In this case, the filter falls back and forwards the request onto the rest of the web filter chain. - --[NOTE] --Unlike the {security-api-url}org/springframework/security/oauth2/client/web/reactive/function/client/ServletOAuth2AuthorizedClientExchangeFilterFunction.html[OAuth 2.0 Client filter function], this filter function makes no attempt to renew the token, should it be expired. --To obtain this level of support, please use the OAuth 2.0 Client filter. -+NOTE: Unlike the {security-api-url}org/springframework/security/oauth2/client/web/reactive/function/client/ServletOAuth2AuthorizedClientExchangeFilterFunction.html[OAuth 2.0 Client filter function], this filter function makes no attempt to renew the token, should it be expired. -+To obtain this level of support, use the OAuth 2.0 Client filter. - - ==== `RestTemplate` support - --There is no `RestTemplate` equivalent for `ServletBearerExchangeFilterFunction` at the moment, but you can propagate the request's bearer token quite simply with your own interceptor: -+There is no `RestTemplate` equivalent for `ServletBearerExchangeFilterFunction` at the moment, but you can propagate the request's bearer token with your own interceptor: - - ==== - .Java -@@ -3001,25 +3013,26 @@ fun rest(): RestTemplate { - ==== - - --[NOTE] --Unlike the {security-api-url}org/springframework/security/oauth2/client/OAuth2AuthorizedClientManager.html[OAuth 2.0 Authorized Client Manager], this filter interceptor makes no attempt to renew the token, should it be expired. --To obtain this level of support, please create an interceptor using the <>. -+NOTE: Unlike the {security-api-url}org/springframework/security/oauth2/client/OAuth2AuthorizedClientManager.html[OAuth 2.0 Authorized Client Manager], this filter interceptor makes no attempt to renew the token, should it be expired. -+To obtain this level of support, create an interceptor by using the <>. - - [[oauth2resourceserver-bearertoken-failure]] - === Bearer Token Failure - --A bearer token may be invalid for a number of reasons. For example, the token may no longer be active. -+A bearer token can be invalid for a number of reasons. For example, the token may no longer be active. - - In these circumstances, Resource Server throws an `InvalidBearerTokenException`. - Like other exceptions, this results in an OAuth 2.0 Bearer Token error response: - --[source,http request] -+==== -+[source,text] - ---- - HTTP/1.1 401 Unauthorized - WWW-Authenticate: Bearer error_code="invalid_token", error_description="Unsupported algorithm of none", error_uri="https://tools.ietf.org/html/rfc6750#section-3.1" - ---- -+==== - --Additionally, it is published as an `AuthenticationFailureBadCredentialsEvent`, which you can <> like so: -+Additionally, it is published as an `AuthenticationFailureBadCredentialsEvent`, for which you can <>: - - ==== - .Java -diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/saml2/index.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/saml2/index.adoc -index e872f5d9d8..b1eccd4112 100644 ---- a/docs/manual/src/docs/asciidoc/_includes/servlet/saml2/index.adoc -+++ b/docs/manual/src/docs/asciidoc/_includes/servlet/saml2/index.adoc -@@ -1,4 +1,7 @@ - [[servlet-saml2]] --= SAML2 -+= SAML 2.0 -+ -+This section discusses how Spring Security works with Security Assertion Markup Language 2.0. -+The https://en.wikipedia.org/wiki/SAML_2.0[Wikipedia article about SAML 2.0] provides some general background - - include::saml2-login.adoc[] -diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/saml2/saml2-login.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/saml2/saml2-login.adoc -index a0431de31e..cba42cb8c0 100644 ---- a/docs/manual/src/docs/asciidoc/_includes/servlet/saml2/saml2-login.adoc -+++ b/docs/manual/src/docs/asciidoc/_includes/servlet/saml2/saml2-login.adoc -@@ -1,10 +1,9 @@ -- - [[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). -+The SAML 2.0 Login feature provides an application with the ability 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, and others). - - 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]. -@@ -14,55 +13,54 @@ Since 2009, support for relying parties has existed as an https://github.com/spr - 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 <>. - --[NOTE] --==== --A working sample for {gh-samples-url}/boot/saml2login[SAML 2.0 Login] is available in the {gh-samples-url}[Spring Security repository]. --==== -+NOTE: A working sample for {gh-samples-url}/boot/saml2login[SAML 2.0 Login] is available in the {gh-samples-url}[Spring Security repository]. - --Let's take a look at how SAML 2.0 Relying Party Authentication works within Spring Security. --First, we see that, like <>, Spring Security takes the user to a third-party for performing authentication. --It does this through a series of redirects. -+We start by examining how SAML 2.0 Relying Party Authentication works within Spring Security. -+First, we see that, like <>, 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 <> and <> diagrams: -+NOTE: The preceding figure above builds off our <> and <> 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_1.png[] First, a user makes an unauthenticated request to the `/private` resource, for which it is not authorized. - --image:{icondir}/number_2.png[] Spring Security's <> indicates that the unauthenticated request is __Denied__ by throwing an `AccessDeniedException`. -+image:{icondir}/number_2.png[] Spring Security's <> indicates that the unauthenticated request is _Denied_ by throwing an `AccessDeniedException`. - --image:{icondir}/number_3.png[] Since the user lacks authorization, the <> initiates __Start Authentication__. --The configured <> is an instance of {security-api-url}org/springframework/security/web/authentication/LoginUrlAuthenticationEntryPoint.html[`LoginUrlAuthenticationEntryPoint`] which redirects to <` generating endpoint>>, `Saml2WebSsoAuthenticationRequestFilter`. --Or, if you've <>, it will first redirect to a picker page. -+image:{icondir}/number_3.png[] Since the user lacks authorization, the <> initiates _Start Authentication_. -+The configured <> is an instance of {security-api-url}org/springframework/security/web/authentication/LoginUrlAuthenticationEntryPoint.html[`LoginUrlAuthenticationEntryPoint`], which redirects to <` generating endpoint>>, `Saml2WebSsoAuthenticationRequestFilter`. -+Alternatively, if you have <>, it first redirects to a picker page. - --image:{icondir}/number_4.png[] Next, the `Saml2WebSsoAuthenticationRequestFilter` creates, signs, serializes, and encodes a `` using its configured <>. -+image:{icondir}/number_4.png[] Next, the `Saml2WebSsoAuthenticationRequestFilter` creates, signs, serializes, and encodes a `` by using its configured <>. - --image:{icondir}/number_5.png[] Then, the browser takes this `` and presents it to the asserting party. --The asserting party attempts to authentication the user. --If successful, it will return a `` back to the browser. -+image:{icondir}/number_5.png[] Then the browser takes this `` and presents it to the asserting party. -+The asserting party tries to authentication the user. -+If successful, it returns a `` back to the browser. - - image:{icondir}/number_6.png[] The browser then POSTs the `` to the assertion consumer service endpoint. - -+The following image shows how Spring Security authenticates a ``. -+ - [[servlet-saml2login-authentication-saml2webssoauthenticationfilter]] - .Authenticating a `` - image::{figures}/saml2webssoauthenticationfilter.png[] - --The figure builds off our <> diagram. -+NOTE: The figure builds off our <> diagram. - - image:{icondir}/number_1.png[] When the browser submits a `` to the application, it <>. - This filter calls its configured `AuthenticationConverter` to create a `Saml2AuthenticationToken` by extracting the response from the `HttpServletRequest`. - This converter additionally resolves the <> and supplies it to `Saml2AuthenticationToken`. - - image:{icondir}/number_2.png[] Next, the filter passes the token to its configured <>. --By default, it will use the <>. -+By default, it uses the <>. - --image:{icondir}/number_3.png[] If authentication fails, then __Failure__ -+image:{icondir}/number_3.png[] If authentication fails, then _Failure_. - - * The <> is cleared out. - * The <> is invoked to restart the authentication process. - --image:{icondir}/number_4.png[] If authentication is successful, then __Success__. -+image:{icondir}/number_4.png[] If authentication is successful, then _Success_. - - * The <> is set on the <>. - * The `Saml2WebSsoAuthenticationFilter` invokes `FilterChain#doFilter(request,response)` to continue with the rest of the application logic. -@@ -76,16 +74,19 @@ 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. -+When using https://spring.io/projects/spring-boot[Spring Boot], configuring an application as a service provider consists of two basic steps: -+. Include the needed dependencies. -+. Indicate the necessary asserting party metadata. - - [NOTE] --Also, this presupposes that you've already <>. -+Also, this configuration presupposes that you have already <>. - -+[[saml2-specifying-identity-provider-metadata]] - ==== Specifying Identity Provider Metadata - --In a Spring Boot application, to specify an identity provider's metadata, simply do: -+In a Spring Boot application, to specify an identity provider's metadata, create configuration similar to the following: - -+==== - [source,yml] - ---- - spring: -@@ -101,63 +102,63 @@ spring: - 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. -+where: - --And that's it! -+* `https://idp.example.com/issuer` is the value contained in the `Issuer` attribute of the SAML responses that the identity provider issues. -+* `classpath:idp.crt` is the location on the classpath for the identity provider's certificate for verifying SAML responses. -+* `https://idp.example.com/issuer/sso` is the endpoint where the identity provider is expecting `AuthnRequest` instances. - --[NOTE] --Identity Provider and Asserting Party are synonymous, as are Service Provider and Relying Party. -+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: -+As configured <>, the application processes any `+POST /login/saml2/sso/{registrationId}+` request containing a `SAMLResponse` parameter: - --[source,html] -+==== -+[source,text] - ---- - POST /login/saml2/sso/adfs HTTP/1.1 - - SAMLResponse=PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZ... - ---- -+==== - --There are two ways to see induce your asserting party to generate a `SAMLResponse`: -+There are two ways to induce your asserting party to generate a `SAMLResponse`: - --* First, you can navigate to your asserting party. -+* 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`. -+* You can navigate to a protected page in your application -- for example, `http://localhost:8080`. -+Your application 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 - - 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. -+* 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. -+* Ensure that 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. -+This makes it possible for you to switch out OpenSAML for some other library or 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 `OpenSamlAuthenticationRequestFactory` and `OpenSamlAuthenticationProvider` expose `Converter` s that customize various steps in the authentication process. -+As a natural outcome of these two goals, Spring Security's SAML API is quite small relative to other modules. -+Instead, such classes as `OpenSamlAuthenticationRequestFactory` and `OpenSamlAuthenticationProvider` expose `Converter` implementationss 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 `OpenSamlAuthenticationProvider`. -+For example, once your application receives a `SAMLResponse` and delegates to `Saml2WebSsoAuthenticationFilter`, the filter delegates to `OpenSamlAuthenticationProvider`: - - .Authenticating an OpenSAML `Response` - image:{figures}/opensamlauthenticationprovider.png[] - --This figure builds off of the <>. -+NOTE: This figure builds off of the <>. - - image:{icondir}/number_1.png[] The `Saml2WebSsoAuthenticationFilter` formulates the `Saml2AuthenticationToken` and invokes the <>. - -@@ -166,18 +167,18 @@ image:{icondir}/number_2.png[] The <>. -+image:{icondir}/number_4.png[] Then the provider <>. - 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. -+If they do not 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 <>. -+image:{icondir}/number_7.png[] Then the provider <>. - If any decryptions fail, authentication fails. - - image:{icondir}/number_8.png[] Next, the provider validates each assertion's `ExpiresAt` and `NotBefore` timestamps, the `` and any `` conditions. -@@ -186,29 +187,31 @@ 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>`. - 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`. -+image:{icondir}/number_10.png[] 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: -+Any class that uses both Spring Security and OpenSAML should statically initialize `OpenSamlInitializationService` at the beginning of the class: - -+==== - [source,java] - ---- - static { - 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, in the event that you always want to always force the asserting party to reauthenticate the user, you can register your own `AuthnRequestMarshaller`, like so: -+For example, if you always want to always force the asserting party to reauthenticate the user, you can register your own `AuthnRequestMarshaller`: - - [source,java] - ---- -@@ -230,20 +233,20 @@ static { - authnRequest.setForceAuthN(true); - } - } -- -+ - factory.getMarshallerFactory().registerMarshaller(AuthnRequest.DEFAULT_ELEMENT_NAME, marshaller); - }); - } - ---- - --The `requireInitialize` method may only be called once per application instance. -+The `requireInitialize` method may be called only 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. -+Spring Boot generates two `@Bean` objects for a relying party. - --The first is a `WebSecurityConfigurerAdapter` that configures the app as a relying party. -+The first is a `WebSecurityConfigurerAdapter` that configures the application as a relying party. - When including `spring-security-saml2-service-provider`, the `WebSecurityConfigurerAdapter` looks like: - - .Default JWT Configuration -@@ -274,7 +277,7 @@ fun configure(http: HttpSecurity) { - ---- - ==== - --If the application doesn't expose a `WebSecurityConfigurerAdapter` bean, then Spring Boot will expose the above default one. -+If the application does not expose a `WebSecurityConfigurerAdapter` bean, Spring Boot exposes the preceding default one. - - You can replace this by exposing the bean within the application: - -@@ -315,14 +318,14 @@ class MyCustomSecurityConfiguration : WebSecurityConfigurerAdapter() { - ---- - ==== - --The above requires the role of `USER` for any URL that starts with `/messages/`. -+The preceding example 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. -+This includes such things as 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: -+For example, you can look up the asserting party's configuration by hitting its metadata endpoint: - - .Relying Party Registration Repository - ==== -@@ -342,7 +345,7 @@ public RelyingPartyRegistrationRepository relyingPartyRegistrations() { - ---- - ==== - --Or you can provide each detail manually, as you can see below: -+Alternatively, you can provide each detail manually: - - .Relying Party Registration Repository Manual Configuration - ==== -@@ -369,12 +372,10 @@ public RelyingPartyRegistrationRepository relyingPartyRegistrations() throws Exc - ---- - ==== - --[NOTE] --Note that `X509Support` is an OpenSAML class, used here in the snippet for brevity -+NOTE: `X509Support` is an OpenSAML class, used in the preceding 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`: -+Alternatively, you can directly wire up the repository by using the DSL, which also overrides the auto-configured `WebSecurityConfigurerAdapter`: - - .Custom Relying Party Registration DSL - ==== -@@ -416,20 +417,20 @@ class MyCustomSecurityConfiguration : WebSecurityConfigurerAdapter() { - ---- - ==== - --[NOTE] --A relying party can be multi-tenant by registering more than one relying party in the `RelyingPartyRegistrationRepository`. -+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. -+instance represents a link between an relying party and an asserting 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. -+In a `RelyingPartyRegistration`, you can provide relying party metadata, such as its `Issuer` value, where it expects SAML Responses to be sent, 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. -+Also, you can provide asserting party metadata such as its `Issuer` value, where it expects AuthnRequests to be sent, 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: - -+==== - [source,java] - ---- - RelyingPartyRegistration relyingPartyRegistration = RelyingPartyRegistrations -@@ -437,9 +438,11 @@ RelyingPartyRegistration relyingPartyRegistration = RelyingPartyRegistrations - .registrationId("my-id") - .build(); - ---- -+==== - --Though a more sophisticated setup is also possible, like so: -+A more sophisticated setup is also possible: - -+==== - [source,java] - ---- - RelyingPartyRegistration relyingPartyRegistration = RelyingPartyRegistration.withRegistrationId("my-id") -@@ -452,26 +455,25 @@ RelyingPartyRegistration relyingPartyRegistration = RelyingPartyRegistration.wit - .singleSignOnServiceLocation("https://ap.example.org/SSO.saml2") - ); - ---- -+==== - --[TIP] --The top-level metadata methods are details about the relying party. -+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. -+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. -+You need this value when you configure 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 <> in the filter chain. -+By default, it is mapped to <> in the filter chain. - - [[servlet-saml2login-rpr-uripatterns]] - ==== URI Patterns - --You probably noticed in the above examples the `+{baseUrl}+` and `+{registrationId}+` placeholders. -+You probably noticed the `+{baseUrl}+` and `+{registrationId}+` placeholders in the preceding examples. - --These are useful for generating URIs. As such, the relying party's `entityId` and `assertionConsumerServiceLocation` support the following placeholders: -+These are useful for generating URIs. As a result, 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 -@@ -479,37 +481,38 @@ These are useful for generating URIs. As such, the relying party's `entityId` an - * `baseHost` - the host of a deployed application - * `basePort` - the port of a deployed application - --For example, the `assertionConsumerServiceLocation` defined above was: -+For example, the `assertionConsumerServiceLocation` defined earlier was: - - `+/my-login-endpoint/{registrationId}+` - --which in a deployed application would translate to -+In a deployed application, it translates to: - - `+/my-login-endpoint/adfs+` - --The `entityId` above was defined as: -+The `entityId` shown earlier was defined as: - - `+{baseUrl}/{registrationId}+` - --which in a deployed application would translate to -+In a deployed application, that translates to: - - `+https://rp.example.com/adfs+` - - [[servlet-saml2login-rpr-credentials]] - ==== Credentials - --You also likely noticed the credential that was used. -+In the example shown <>, 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. -+Oftentimes, a relying party uses the same key to sign payloads as well as decrypt them. -+Alternatively, it can 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. -+At a minimum, you need 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: -+To construct a `Saml2X509Credential` that you can use to verify assertions from the asserting party, you can load the file and use -+the `CertificateFactory`: - -+==== - [source,java] - ---- - Resource resource = new ClassPathResource("ap.crt"); -@@ -519,13 +522,15 @@ try (InputStream is = resource.getInputStream()) { - return Saml2X509Credential.verification(certificate); - } - ---- -+==== - --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. -+Suppose that the asserting party is going to also encrypt the assertion. -+In that case, the relying party needs a private key 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: -+In that case, you need an `RSAPrivateKey` as well as its corresponding `X509Certificate`. -+You can load the first by using Spring Security's `RsaKeyConverters` utility class and the second as you did before: - -+==== - [source,java] - ---- - X509Certificate certificate = relyingPartyDecryptionCertificate(); -@@ -535,25 +540,26 @@ try (InputStream is = resource.getInputStream()) { - 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. -+TIP: When you specify the locations of these files as the appropriate Spring Boot properties, Spring Boot performs 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. -+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 want to customize for a number of reasons, including: - --* 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 -+* You may know that your application is never going to be a multi-tenant application and, as a result, want 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`. --The default looks up the registration id from the URI's last path element and looks it up in your `RelyingPartyRegistrationRepository`. -+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: - -+==== - [source,java] - ---- - public class SingleRelyingPartyRegistrationResolver -@@ -565,11 +571,11 @@ public class SingleRelyingPartyRegistrationResolver - } - } - ---- -+==== - --Then, you can provide this resolver to the appropriate filters that <` s>>, <` s>>, and <` metadata>>. -+Then you can provide this resolver to the appropriate filters that <` instances>>, <` instances>>, and <` metadata>>. - --[NOTE] --Remember that if you have any placeholders in your `RelyingPartyRegistration`, your resolver implementation should resolve them. -+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 -@@ -577,15 +583,16 @@ Remember that if you have any placeholders in your `RelyingPartyRegistration`, y - 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 -+* Its `assertionConsumerServiceLocation` -+* 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. -+This setup may let credentials be more easily rotated for some identity providers versus others. - - The duplication can be alleviated in a few different ways. - --First, in YAML this can be alleviated with references, like so: -+First, in YAML this can be alleviated with references: - -+==== - [source,yaml] - ---- - spring: -@@ -603,11 +610,13 @@ spring: - identityprovider: - entity-id: ... - ---- -+==== - --Second, in a database, it's not necessary to replicate `RelyingPartyRegistration` 's model. -+Second, in a database, you need not replicate the model of `RelyingPartyRegistration`. - --Third, in Java, you can create a custom configuration method, like so: -+Third, in Java, you can create a custom configuration method: - -+==== - [source,java] - ---- - private RelyingPartyRegistration.Builder -@@ -633,29 +642,29 @@ public RelyingPartyRegistrationRepository relyingPartyRegistrations() { - return new InMemoryRelyingPartyRegistrationRepository(okta, azure); - } - ---- -+==== - - [[servlet-saml2login-sp-initiated-factory]] --=== Producing `` s -+=== Producing `` Instances - --As stated earlier, Spring Security's SAML 2.0 support produces a `` to commence authentication with the asserting party. -+As stated earlier, Spring Security's SAML 2.0 support produces a `` to start 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}+`. -+Spring Security achieves this, in part, by registering the `Saml2WebSsoAuthenticationRequestFilter` in the filter chain. -+By default, this filter responds to the `+/saml2/authenticate/{registrationId}+` endpoint. - --For example, if you were deployed to `https://rp.example.com` and you gave your registration an ID of `okta`, you could navigate to: -+For example, if you were deployed to `https://rp.example.com` and 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 ``. -+The result should be a redirect that includes a `SAMLRequest` parameter containing the signed, deflated, and encoded ``. - - [[servlet-saml2login-sp-initiated-factory-signing]] - ==== Changing How the `` Gets Sent - --By default, Spring Security signs each `` and send it as a GET to the asserting party. -- --Many asserting parties don't require a signed ``. --This can be configured automatically via `RelyingPartyRegistrations`, or you can supply it manually, like so: -+By default, Spring Security signs each `` and sends it as a `GET` to the asserting party. - -+Many asserting parties do not require a signed ``. -+This can be configured automatically by `RelyingPartyRegistrations`, or you can supply it manually: - - .Not Requiring Signed AuthnRequests - ==== -@@ -684,15 +693,16 @@ RelyingPartyRegistration relyingPartyRegistration = RelyingPartyRegistration.wit - ---- - ==== - --Otherwise, you will need to specify a private key to `RelyingPartyRegistration#signingX509Credentials` so that Spring Security can sign the `` before sending. -+Otherwise, you need to specify a private key to `RelyingPartyRegistration#signingX509Credentials` so that Spring Security can sign the `` before sending. - - [[servlet-saml2login-sp-initiated-factory-algorithm]] --By default, Spring Security will sign the `` using `rsa-sha256`, though some asserting parties will require a different algorithm, as indicated in their metadata. -+By default, Spring Security signs the `` by using `rsa-sha256`, though some asserting parties require a different algorithm, as indicated in their metadata. - --You can configure the algorithm based on the asserting party's <>. -+You can configure the algorithm based on the asserting party's <>. - --Or, you can provide it manually: -+Alternatively, you can provide it manually: - -+==== - [source,java] - ---- - String metadataLocation = "classpath:asserting-party-metadata.xml"; -@@ -703,15 +713,17 @@ RelyingPartyRegistration relyingPartyRegistration = RelyingPartyRegistrations.fr - .signingAlgorithms((sign) -> sign.add(SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA512)) - ); - ---- -+==== - --NOTE: The snippet above uses the OpenSAML `SignatureConstants` class to supply the algorithm name. --But, that's just for convenience. -+NOTE: The preceding snippet uses the OpenSAML `SignatureConstants` class to supply the algorithm name. -+However, that is only 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 `` be POSTed. --This can be configured automatically via `RelyingPartyRegistrations`, or you can supply it manually, like so: -+This can be configured automatically through `RelyingPartyRegistrations`, or you can supply it manually: - -+==== - [source,java] - ---- - RelyingPartyRegistration relyingPartyRegistration = RelyingPartyRegistration.withRegistrationId("okta") -@@ -721,19 +733,20 @@ RelyingPartyRegistration relyingPartyRegistration = RelyingPartyRegistration.wit - .singleSignOnServiceBinding(Saml2MessageType.POST) - ); - ---- -- -+==== - - [[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. -+You may want to adjust an `AuthnRequest` for a number of reasons. -+For example, you may want `ForceAuthN` to be set to `true`. By default, Spring Security sets it to `false`. - --If you don't need information from the `HttpServletRequest` to make your decision, then the easiest way is to <>. --This will give you access to post-process the `AuthnRequest` instance before it's serialized. -+If you do not need information from the `HttpServletRequest` to make your decision, the easiest way is to <>. -+This gives you access to post-process the `AuthnRequest` instance before it is serialized. - --But, if you do need something from the request, then you can use create a custom `Saml2AuthenticationRequestContext` implementation and then a `Converter` to build an `AuthnRequest` yourself, like so: -+However, if you do need something from the request, you can use create a custom `Saml2AuthenticationRequestContext` implementation and then a `Converter` to build an `AuthnRequest` yourself: - -+==== - [source,java] - ---- - @Component -@@ -762,9 +775,11 @@ public class AuthnRequestConverter implements - } - } - ---- -+==== - --Then, you can construct your own `Saml2AuthenticationRequestContextResolver` and `Saml2AuthenticationRequestFactory` and publish them as `@Bean` s: -+Then you can construct your own `Saml2AuthenticationRequestContextResolver` and `Saml2AuthenticationRequestFactory` and publish them as `@Bean` objects: - -+==== - [source,java] - ---- - @Bean -@@ -787,27 +802,29 @@ Saml2AuthenticationRequestFactory authenticationRequestFactory( - return authenticationRequestFactory; - } - ---- -+==== - - [[servlet-saml2login-authenticate-responses]] --=== Authenticating `` s -+=== Authenticating `` Instances - - To verify SAML 2.0 Responses, Spring Security uses <> by default. - --You can configure this in a number of ways including: -+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 -+* Setting a clock skew to timestamp validation -+* Mapping the response to a list of `GrantedAuthority` instances -+* Customizing the strategy for validating assertions -+* Customizing the strategy for decrypting response and assertion elements - --To configure these, you'll use the `saml2Login#authenticationManager` method in the DSL. -+To configure these, you can 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 `OpenSamlAuthenticationProvider` 's default assertion validator with some tolerance: -+Often, the asserting and relying parties have system clocks that are not perfectly synchronized. -+For that reason, you can configure the default assertion validator of `OpenSamlAuthenticationProvider` with some tolerance: - -+==== - [source,java] - ---- - @EnableWebSecurity -@@ -835,13 +852,15 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter { - } - } - ---- -+==== - - [[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: -+Alternatively, you might like to include user details from a legacy `UserDetailsService`. -+In that case, the response authentication converter can come in handy: - -+==== - [source,java] - ---- - @EnableWebSecurity -@@ -872,28 +891,29 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter { - } - } - ---- --<1> First, call the default converter, which extracts attributes and authorities from the response --<2> Second, call the <> using the relevant information --<3> Third, return a custom authentication that includes the user details -+<1> Call the default converter, which extracts attributes and authorities from the response -+<2> Call the <> by using the relevant information -+<3> Return a custom authentication that includes the user details -+==== - --[NOTE] --It's not required to call `OpenSamlAuthenticationProvider` 's default authentication converter. --It returns a `Saml2AuthenticatedPrincipal` containing the attributes it extracted from `AttributeStatement` s as well as the single `ROLE_USER` authority. -+NOTE: You need not call the default authentication converter of `OpenSamlAuthenticationProvider`. -+It returns a `Saml2AuthenticatedPrincipal` that contains the attributes it extracted from `AttributeStatement` instances as well as the single `ROLE_USER` authority. - - [[servlet-saml2login-opensamlauthenticationprovider-additionalvalidation]] - ==== Performing Additional Validation - - `OpenSamlAuthenticationProvider` performs minimal validation on SAML 2.0 Assertions. --After verifying the signature, it will: -+After verifying the signature, it: - --1. Validate `` and `` conditions --2. Validate `` s, expect for any IP address information -+. Validates `` and `` conditions -+. Validates `` instances, expect for any IP address information - --To perform additional validation, you can configure your own assertion validator that delegates to `OpenSamlAuthenticationProvider` 's default and then performs its own. -+To perform additional validation, you can configure your own assertion validator that delegates to the default of `OpenSamlAuthenticationProvider` and then performs its own validation. - - [[servlet-saml2login-opensamlauthenticationprovider-onetimeuse]] --For example, you can use OpenSAML's `OneTimeUseConditionValidator` to also validate a `` condition, like so: -+For example, you can use OpenSAML's `OneTimeUseConditionValidator` to also validate a `` condition: - -+==== - [source,java] - ---- - OpenSamlAuthenticationProvider provider = new OpenSamlAuthenticationProvider(); -@@ -915,10 +935,10 @@ provider.setAssertionValidator(assertionToken -> { - return result.contact(new Saml2Error(INVALID_ASSERTION, context.getValidationFailureMessage())); - }); - ---- -+==== - --[NOTE] --While recommended, it's not necessary to call `OpenSamlAuthenticationProvider` 's default assertion validator. --A circumstance where you would skip it would be if you don't need it to check the `` or the `` since you are doing those yourself. -+NOTE: While recommended, you need not call the default assertion validator of `OpenSamlAuthenticationProvider`. -+For example, you could skip it if you do not need to check the `` or the `` because you are doing those yourself. - - [[servlet-saml2login-opensamlauthenticationprovider-decryption]] - ==== Customizing Decryption -@@ -926,37 +946,42 @@ A circumstance where you would skip it would be if you don't need it to check th - Spring Security decrypts ``, ``, and `` elements automatically by using the decryption <> registered in the <>. - - `OpenSamlAuthenticationProvider` exposes <>. --The response decrypter is for decrypting encrypted elements of the ``, like ``. --The assertion decrypter is for decrypting encrypted elements of the ``, like `` and ``. -+The response decrypter decrypts encrypted elements of the ``, such as ``. -+The assertion decrypter decrypts encrypted elements of the ``, such as `` and ``. - --You can replace `OpenSamlAuthenticationProvider`'s default decryption strategy with your own. --For example, if you have a separate service that decrypts the assertions in a ``, you can use it instead like so: -+You can replace the default decryption strategy of `OpenSamlAuthenticationProvider` with your own strategy. -+For example, if you have a separate service that decrypts the assertions in a ``, you can use it instead: - -+==== - [source,java] - ---- - MyDecryptionService decryptionService = ...; - OpenSamlAuthenticationProvider provider = new OpenSamlAuthenticationProvider(); - provider.setResponseElementsDecrypter((responseToken) -> decryptionService.decrypt(responseToken.getResponse())); - ---- -+==== - --If you are also decrypting individual elements in a ``, you can customize the assertion decrypter, too: -+If you also decrypt individual elements in a ``, you can customize the assertion decrypter, too: - -+==== - [source,java] - ---- - provider.setAssertionElementsDecrypter((assertionToken) -> decryptionService.decrypt(assertionToken.getAssertion())); - ---- -+==== - --NOTE: There are two separate decrypters since assertions can be signed separately from responses. -+NOTE: We have two separate decrypters, because 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. -+If your asserting party signs only the response, it is safe to decrypt all elements by 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. -+You can also use the `authenticationManager` DSL method to perform a completely custom SAML 2.0 authentication. -+This authentication manager should expect a `Saml2AuthenticationToken` object that contains the SAML 2.0 Response XML data. - -+==== - [source,java] - ---- - @EnableWebSecurity -@@ -976,15 +1001,17 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter { - } - } - ---- -+==== - - [[servlet-saml2login-authenticatedprincipal]] --=== Using `Saml2AuthenticatedPrincipal` -+=== Using the `Saml2AuthenticatedPrincipal` - --With the relying party correctly configured for a given asserting party, it's ready to accept assertions. -+With the relying party correctly configured for a given asserting party, it is 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: -+This means that you can access the principal in your controller: - -+==== - [source,java] - ---- - @Controller -@@ -997,16 +1024,17 @@ public class MainController { - } - } - ---- -+==== - --[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. -+TIP: Because the SAML 2.0 specification lets each attribute 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 handy when you know that there is only one value. - - [[servlet-saml2login-metadata]] - === Producing `` Metadata - --You can publish a metadata endpoint by adding the `Saml2MetadataFilter` to the filter chain, as you'll see below: -+You can publish a metadata endpoint by adding the `Saml2MetadataFilter` to the filter chain: - -+==== - [source,java] - ---- - Converter relyingPartyRegistrationResolver = -@@ -1020,26 +1048,31 @@ http - .saml2Login(withDefaults()) - .addFilterBefore(new Saml2MetadataFilter(r), Saml2WebSsoAuthenticationFilter.class); - ---- -+==== - - 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. -+This is often as simple as finding the correct form field to supply to 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: - -+==== - [source,java] - ---- - filter.setRequestMatcher(new AntPathRequestMatcher("/saml2/metadata/{registrationId}", "GET")); - ---- -+==== - --ensuring that the `registrationId` hint is at the end of the path. -+Doing so ensures 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: -+Alternatively, if you have registered a custom relying party registration resolver in the constructor, you can specify a path without a `registrationId` hint: - -+==== - [source,java] - ---- - filter.setRequestMatcher(new AntPathRequestMatcher("/saml2/metadata", "GET")); - ---- -+==== - - [[servlet-saml2login-logout]] - === Performing Single Logout -@@ -1048,6 +1081,7 @@ Spring Security does not yet support single logout. - - Generally speaking, though, you can achieve this by creating and registering a custom `LogoutSuccessHandler` and `RequestMatcher`: - -+==== - [source,java] - ---- - http -@@ -1057,7 +1091,8 @@ http - .logoutRequestMatcher(myRequestMatcher()) - ) - ---- -+==== - --The success handler will send logout requests to the asserting party. -+The success handler sends logout requests to the asserting party. - --The request matcher will detect logout requests from the asserting party. -+The request matcher detects logout requests from the asserting party. -diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/test/index.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/test/index.adoc -index da7d74db4a..ae8ef2de74 100644 ---- a/docs/manual/src/docs/asciidoc/_includes/servlet/test/index.adoc -+++ b/docs/manual/src/docs/asciidoc/_includes/servlet/test/index.adoc -@@ -3,10 +3,7 @@ - - This section describes the testing support provided by Spring Security. - --[TIP] --==== --To use the Spring Security test support, you must include `spring-security-test-{spring-security-version}.jar` as a dependency of your project. --==== -+NOTE: To use the Spring Security test support, you must include `spring-security-test-{spring-security-version}.jar` as a dependency of your project. - - include::method.adoc[] - -diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/test/method.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/test/method.adoc -index 6bc7272347..316cf6c4d0 100644 ---- a/docs/manual/src/docs/asciidoc/_includes/servlet/test/method.adoc -+++ b/docs/manual/src/docs/asciidoc/_includes/servlet/test/method.adoc -@@ -1,9 +1,10 @@ - [[test-method]] - == 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. -+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 to be able to access it: - -+==== - [source,java] - ---- - public class HelloMessageService implements MessageService { -@@ -16,41 +17,46 @@ public class HelloMessageService implements MessageService { - } - } - ---- -+==== - --The result of `getMessage` is a String saying "Hello" to the current Spring Security `Authentication`. --An example of the output is displayed below. -+The result of `getMessage` is a `String` that says "`Hello`" to the current Spring Security `Authentication`. -+The follwoing listing shows example output: - -+==== - [source,text] - ---- - Hello org.springframework.security.authentication.UsernamePasswordAuthenticationToken@ca25360: Principal: org.springframework.security.core.userdetails.User@36ebcb: Username: user; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: ROLE_USER; Credentials: [PROTECTED]; Authenticated: true; Details: null; Granted Authorities: ROLE_USER - ---- -+==== - - [[test-method-setup]] - === Security Test Setup - --Before we can use Spring Security Test support, we must perform some setup. An example can be seen below: -+Before we can use the Spring Security test support, we must perform some setup: - -+==== - [source,java] - ---- - @RunWith(SpringJUnit4ClassRunner.class) // <1> - @ContextConfiguration // <2> - public class WithMockUserTests { -+ ... -+} - ---- -+<1> `@RunWith` instructs the spring-test module that it should create an `ApplicationContext`. This is no different than using the existing Spring Test support. For additional information, see the https://docs.spring.io/spring-framework/docs/4.0.x/spring-framework-reference/htmlsingle/#integration-testing-annotations-standard[Spring Reference]. -+<2> `@ContextConfiguration` instructs the Spring test configuration to use to create the `ApplicationContext`. Since no configuration is specified, the default configuration locations are tried. This is no different than using the existing Spring test support. For additional information, see the https://docs.spring.io/spring-framework/docs/4.0.x/spring-framework-reference/htmlsingle/#testcontext-ctx-management[Spring Reference]. -+==== - --This is a basic example of how to setup Spring Security Test. The highlights are: -- --<1> `@RunWith` instructs the spring-test module that it should create an `ApplicationContext`. This is no different than using the existing Spring Test support. For additional information, refer to the https://docs.spring.io/spring-framework/docs/4.0.x/spring-framework-reference/htmlsingle/#integration-testing-annotations-standard[Spring Reference] --<2> `@ContextConfiguration` instructs the spring-test the configuration to use to create the `ApplicationContext`. Since no configuration is specified, the default configuration locations will be tried. This is no different than using the existing Spring Test support. For additional information, refer to the https://docs.spring.io/spring-framework/docs/4.0.x/spring-framework-reference/htmlsingle/#testcontext-ctx-management[Spring Reference] -- --NOTE: Spring Security hooks into Spring Test support using the `WithSecurityContextTestExecutionListener` which will ensure our tests are ran with the correct user. -+NOTE: Spring Security hooks into Spring Test support through the `WithSecurityContextTestExecutionListener`, which ensures that our tests are run with the correct user. - It does this by populating the `SecurityContextHolder` prior to running our tests. --If you are using reactive method security, you will also need `ReactorContextTestExecutionListener` which populates `ReactiveSecurityContextHolder`. --After the test is done, it will clear out the `SecurityContextHolder`. --If you only need Spring Security related support, you can replace `@ContextConfiguration` with `@SecurityTestExecutionListeners`. -+If you use reactive method security, you also need `ReactorContextTestExecutionListener`, which populates `ReactiveSecurityContextHolder`. -+After the test is done, it clears out the `SecurityContextHolder`. -+If you need only Spring Security related support, you can replace `@ContextConfiguration` with `@SecurityTestExecutionListeners`. - --Remember we added the `@PreAuthorize` annotation to our `HelloMessageService` and so it requires an authenticated user to invoke it. --If we ran the following test, we would expect the following test will pass: -+Remember, we added the `@PreAuthorize` annotation to our `HelloMessageService`, so it requires an authenticated user to invoke it. -+If we run the tests, we expect the following test will pass: - -+==== - [source,java] - ---- - @Test(expected = AuthenticationCredentialsNotFoundException.class) -@@ -58,14 +64,16 @@ public void getMessageUnauthenticated() { - messageService.getMessage(); - } - ---- -+==== - - [[test-method-withmockuser]] - === @WithMockUser - --The question is "How could we most easily run the test as a specific user?" -+The question is "`How could we most easily run the test as a specific user?`" - The answer is to use `@WithMockUser`. --The following test will be run as a user with the username "user", the password "password", and the roles "ROLE_USER". -+The following test runs as a user with a username of `user`, a password of `password`, and the role of `ROLE_USER`. - -+==== - [source,java] - ---- - @Test -@@ -75,18 +83,22 @@ String message = messageService.getMessage(); - ... - } - ---- -+==== - - Specifically the following is true: - --* The user with the username "user" does not have to exist since we are mocking the user --* The `Authentication` that is populated in the `SecurityContext` is of type `UsernamePasswordAuthenticationToken` --* The principal on the `Authentication` is Spring Security's `User` object --* The `User` will have the username of "user", the password "password", and a single `GrantedAuthority` named "ROLE_USER" is used. -+* The user with a username of `user` does not have to exist, since we mock the user object. -+* The `Authentication` that is populated in the `SecurityContext` is of type `UsernamePasswordAuthenticationToken`. -+* The principal on the `Authentication` is Spring Security's `User` object. -+* The `User` has a username of `user`. -+* The `User` has a password of `password`. -+* A single `GrantedAuthority` named `ROLE_USER` is used. - --Our example is nice because we are able to leverage a lot of defaults. -+The preceding example is handy, because it lets us use a lot of defaults. - What if we wanted to run the test with a different username? --The following test would run with the username "customUser". Again, the user does not need to actually exist. -+The following test would run with a username of `customUser` (again, the user does not need to actually exist): - -+==== - [source,java] - ---- - @Test -@@ -96,10 +108,12 @@ public void getMessageWithMockUserCustomUsername() { - ... - } - ---- -+==== - - We can also easily customize the roles. --For example, this test will be invoked with the username "admin" and the roles "ROLE_USER" and "ROLE_ADMIN". -+For example, the following test is invoked with a username of `admin` and roles of `ROLE_USER` and `ROLE_ADMIN`. - -+==== - [source,java] - ---- - @Test -@@ -109,10 +123,12 @@ public void getMessageWithMockUserCustomUser() { - ... - } - ---- -+==== - --If we do not want the value to automatically be prefixed with ROLE_ we can leverage the authorities attribute. --For example, this test will be invoked with the username "admin" and the authorities "USER" and "ADMIN". -+If we do not want the value to automatically be prefixed with `ROLE_` we can use the `authorities` attribute. -+For example, the following test is invoked with a username of `admin` and the `USER` and `ADMIN` authorities. - -+==== - [source,java] - ---- - @Test -@@ -122,22 +138,28 @@ public void getMessageWithMockUserCustomAuthorities() { - ... - } - ---- -+==== - --Of course it can be a bit tedious placing the annotation on every test method. --Instead, we can place the annotation at the class level and every test will use the specified user. --For example, the following would run every test with a user with the username "admin", the password "password", and the roles "ROLE_USER" and "ROLE_ADMIN". -+It can be a bit tedious to place the annotation on every test method. -+Instead, we can place the annotation at the class level. Then every test uses the specified user. -+The following example runs every test with a user whose username is `admin`, whose password is `password`, and who has the `ROLE_USER` and `ROLE_ADMIN` roles: - -+==== - [source,java] - ---- - @RunWith(SpringJUnit4ClassRunner.class) - @ContextConfiguration - @WithMockUser(username="admin",roles={"USER","ADMIN"}) - public class WithMockUserTests { -+ ... -+} - ---- -+==== - --If you are using JUnit 5's `@Nested` test support, you can also place the annotation on the enclosing class to apply to all nested classes. --For example, the following would run every test with a user with the username "admin", the password "password", and the roles "ROLE_USER" and "ROLE_ADMIN" for both test methods. -+If you use JUnit 5's `@Nested` test support, you can also place the annotation on the enclosing class to apply to all nested classes. -+The following example runs every test with a user whose username is `admin`, whose password is `password`, and who has the `ROLE_USER` and `ROLE_ADMIN` roles for both test methods. - -+==== - [source,java] - ---- - @ExtendWith(SpringExtension.class) -@@ -156,24 +178,27 @@ public class WithMockUserTests { - } - } - ---- -+==== - --By default the `SecurityContext` is set during the `TestExecutionListener.beforeTestMethod` event. -+By default, the `SecurityContext` is set during the `TestExecutionListener.beforeTestMethod` event. - This is the equivalent of happening before JUnit's `@Before`. --You can change this to happen during the `TestExecutionListener.beforeTestExecution` event which is after JUnit's `@Before` but before the test method is invoked. -+You can change this to happen during the `TestExecutionListener.beforeTestExecution` event, which is after JUnit's `@Before` but before the test method is invoked: - -+==== - [source,java] - ---- - @WithMockUser(setupBefore = TestExecutionEvent.TEST_EXECUTION) - ---- -- -+==== - - [[test-method-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. --For example, the following will run withMockUser1 and withMockUser2 using <> and anonymous 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. -+The following example runs `withMockUser1` and `withMockUser2` by using <> and `anonymous` as an anonymous user: - -+==== - [source,java] - ---- - @RunWith(SpringJUnit4ClassRunner.class) -@@ -195,30 +220,33 @@ public class WithUserClassLevelAuthenticationTests { - } - } - ---- -+==== - --By default the `SecurityContext` is set during the `TestExecutionListener.beforeTestMethod` event. -+By default, the `SecurityContext` is set during the `TestExecutionListener.beforeTestMethod` event. - This is the equivalent of happening before JUnit's `@Before`. --You can change this to happen during the `TestExecutionListener.beforeTestExecution` event which is after JUnit's `@Before` but before the test method is invoked. -+You can change this to happen during the `TestExecutionListener.beforeTestExecution` event, which is after JUnit's `@Before` but before the test method is invoked: - -+==== - [source,java] - ---- - @WithAnonymousUser(setupBefore = TestExecutionEvent.TEST_EXECUTION) - ---- -- -+==== - - [[test-method-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. -+While `@WithMockUser` is a convenient way to get started, it may not work in all instances. -+For example, some applications expect the `Authentication` principal to be of a specific type. - This is done so that the application can refer to the principal as the custom type and reduce coupling on Spring Security. - --The custom principal is often times returned by a custom `UserDetailsService` that returns an object that implements both `UserDetails` and the custom type. --For situations like this, it is useful to create the test user using the custom `UserDetailsService`. -+The custom principal is often returned by a custom `UserDetailsService` that returns an object that implements both `UserDetails` and the custom type. -+For situations like this, it is useful to create the test user by using a custom `UserDetailsService`. - That is exactly what `@WithUserDetails` does. - --Assuming we have a `UserDetailsService` exposed as a bean, the following test will be invoked with an `Authentication` of type `UsernamePasswordAuthenticationToken` and a principal that is returned from the `UserDetailsService` with the username of "user". -+Assuming we have a `UserDetailsService` exposed as a bean, the following test is invoked with an `Authentication` of type `UsernamePasswordAuthenticationToken` and a principal that is returned from the `UserDetailsService` with the username of `user`: - -+==== - [source,java] - ---- - @Test -@@ -228,10 +256,12 @@ public void getMessageWithUserDetails() { - ... - } - ---- -+==== - - We can also customize the username used to lookup the user from our `UserDetailsService`. --For example, this test would be run with a principal that is returned from the `UserDetailsService` with the username of "customUsername". -+For example, this test can be run with a principal that is returned from the `UserDetailsService` with the username of `customUsername`: - -+==== - [source,java] - ---- - @Test -@@ -241,10 +271,12 @@ public void getMessageWithUserDetailsCustomUsername() { - ... - } - ---- -+==== - - We can also provide an explicit bean name to look up the `UserDetailsService`. --For example, this test would look up the username of "customUsername" using the `UserDetailsService` with the bean name "myUserDetailsService". -+The following test looks up the username of `customUsername` by using the `UserDetailsService` with a bean name of `myUserDetailsService`: - -+==== - [source,java] - ---- - @Test -@@ -254,30 +286,33 @@ public void getMessageWithUserDetailsServiceBeanName() { - ... - } - ---- -+==== - --Like `@WithMockUser` we can also place our annotation at the class level so that every test uses the same user. --However unlike `@WithMockUser`, `@WithUserDetails` requires the user to exist. -+As we did with `@WithMockUser`, we can also place our annotation at the class level so that every test uses the same user. -+However, unlike `@WithMockUser`, `@WithUserDetails` requires the user to exist. - --By default the `SecurityContext` is set during the `TestExecutionListener.beforeTestMethod` event. -+By default, the `SecurityContext` is set during the `TestExecutionListener.beforeTestMethod` event. - This is the equivalent of happening before JUnit's `@Before`. --You can change this to happen during the `TestExecutionListener.beforeTestExecution` event which is after JUnit's `@Before` but before the test method is invoked. -+You can change this to happen during the `TestExecutionListener.beforeTestExecution` event, which is after JUnit's `@Before` but before the test method is invoked: - -+==== - [source,java] - ---- - @WithUserDetails(setupBefore = TestExecutionEvent.TEST_EXECUTION) - ---- -- -+==== - - [[test-method-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. --We will now see an option that allows the most flexibility. -+We have seen that `@WithMockUser` is an excellent choice if we do not use a custom `Authentication` principal. -+Next, we discovered that `@WithUserDetails` lets us use a custom `UserDetailsService` to create our `Authentication` principal but requires the user to exist. -+We now see an option that allows the most flexibility. - - We can create our own annotation that uses the `@WithSecurityContext` to create any `SecurityContext` we want. --For example, we might create an annotation named `@WithMockCustomUser` as shown below: -+For example, we might create an annotation named `@WithMockCustomUser`: - -+==== - [source,java] - ---- - @Retention(RetentionPolicy.RUNTIME) -@@ -289,12 +324,14 @@ public @interface WithMockCustomUser { - String name() default "Rob Winch"; - } - ---- -+==== - - You can see that `@WithMockCustomUser` is annotated with the `@WithSecurityContext` annotation. --This is what signals to Spring Security Test support that we intend to create a `SecurityContext` for the test. --The `@WithSecurityContext` annotation requires we specify a `SecurityContextFactory` that will create a new `SecurityContext` given our `@WithMockCustomUser` annotation. --You can find our `WithMockCustomUserSecurityContextFactory` implementation below: -+This is what signals to Spring Security test support that we intend to create a `SecurityContext` for the test. -+The `@WithSecurityContext` annotation requires that we specify a `SecurityContextFactory` to create a new `SecurityContext`, given our `@WithMockCustomUser` annotation. -+The following listing shows our `WithMockCustomUserSecurityContextFactory` implementation: - -+==== - [source,java] - ---- - public class WithMockCustomUserSecurityContextFactory -@@ -312,12 +349,14 @@ public class WithMockCustomUserSecurityContextFactory - } - } - ---- -+==== - --We can now annotate a test class or a test method with our new annotation and Spring Security's `WithSecurityContextTestExecutionListener` will ensure that our `SecurityContext` is populated appropriately. -+We can now annotate a test class or a test method with our new annotation and Spring Security's `WithSecurityContextTestExecutionListener` to ensure that our `SecurityContext` is populated appropriately. - - When creating your own `WithSecurityContextFactory` implementations, it is nice to know that they can be annotated with standard Spring annotations. - For example, the `WithUserDetailsSecurityContextFactory` uses the `@Autowired` annotation to acquire the `UserDetailsService`: - -+==== - [source,java] - ---- - final class WithUserDetailsSecurityContextFactory -@@ -341,39 +380,45 @@ final class WithUserDetailsSecurityContextFactory - } - } - ---- -+==== - --By default the `SecurityContext` is set during the `TestExecutionListener.beforeTestMethod` event. -+By default, the `SecurityContext` is set during the `TestExecutionListener.beforeTestMethod` event. - This is the equivalent of happening before JUnit's `@Before`. --You can change this to happen during the `TestExecutionListener.beforeTestExecution` event which is after JUnit's `@Before` but before the test method is invoked. -+You can change this to happen during the `TestExecutionListener.beforeTestExecution` event, which is after JUnit's `@Before` but before the test method is invoked: - -+==== - [source,java] - ---- - @WithSecurityContext(setupBefore = TestExecutionEvent.TEST_EXECUTION) - ---- -- -+==== - - [[test-method-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: -+For example, if you have many tests related to an administrative user with a username of `admin` and roles of `ROLE_USER` and `ROLE_ADMIN`, you have to write: - -+==== - [source,java] - ---- - @WithMockUser(username="admin",roles={"USER","ADMIN"}) - ---- -+==== - - Rather than repeating this everywhere, we can use a meta annotation. - For example, we could create a meta annotation named `WithMockAdmin`: - -+==== - [source,java] - ---- - @Retention(RetentionPolicy.RUNTIME) - @WithMockUser(value="rob",roles="ADMIN") - public @interface WithMockAdmin { } - ---- -+==== - - Now we can use `@WithMockAdmin` in the same way as the more verbose `@WithMockUser`. - --Meta annotations work with any of the testing annotations described above. --For example, this means we could create a meta annotation for `@WithUserDetails("admin")` as well. -+Meta annotations work with any of the testing annotations described in this section. -+For example, this means that we could create a meta annotation for `@WithUserDetails("admin")` as well. -diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/test/mockmvc.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/test/mockmvc.adoc -index 5fe1fbd94d..6a8e3712b1 100644 ---- a/docs/manual/src/docs/asciidoc/_includes/servlet/test/mockmvc.adoc -+++ b/docs/manual/src/docs/asciidoc/_includes/servlet/test/mockmvc.adoc -@@ -6,16 +6,15 @@ Spring Security provides comprehensive integration with https://docs.spring.io/s - [[test-mockmvc-setup]] - === 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 <>. --This can be done using Spring Security's `SecurityMockMvcConfigurers.springSecurity()`. --For example: -- - NOTE: Spring Security's testing support requires spring-test-4.1.3.RELEASE or greater. - -+To use Spring Security with Spring MVC Test, add the Spring Security `FilterChainProxy` as a `Filter`. -+You also need to add Spring Security's `TestSecurityContextHolderPostProcessor` to support <>. -+To do so, use Spring Security's `SecurityMockMvcConfigurers.springSecurity()`: -+ -+==== - [source,java] - ---- -- - import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.*; - - @RunWith(SpringJUnit4ClassRunner.class) -@@ -37,129 +36,151 @@ public 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 - --Spring MVC Test provides a convenient interface called a `RequestPostProcessor` that can be used to modify a request. -+Spring MVC Test provides a convenient interface (`RequestPostProcessor`) that you can use to modify a request. - Spring Security provides a number of `RequestPostProcessor` implementations that make testing easier. --In order to use Spring Security's `RequestPostProcessor` implementations ensure the following static import is used: -+To use Spring Security's `RequestPostProcessor` implementations, use the following static import: - -+==== - [source,java] - ---- - import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.*; - ---- -+==== - - [[test-mockmvc-csrf]] - ==== 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: -+When testing any non-safe HTTP methods and using Spring Security's CSRF protection, you must include a valid CSRF Token in the request. -+To specify a valid CSRF token as a request parameter, use the following: - -+==== - [source,java] - ---- - mvc - .perform(post("/").with(csrf())) - ---- -+==== - --If you like you can include CSRF token in the header instead: -+If you like, you can include CSRF token in the header instead: - -+==== - [source,java] - ---- - mvc - .perform(post("/").with(csrf().asHeader())) - ---- -+==== - --You can also test providing an invalid CSRF token using the following: -+You can also test providing an invalid CSRF token by using the following: - -+==== - [source,java] - ---- - mvc - .perform(post("/").with(csrf().useInvalidToken())) - ---- -+==== - - [[test-mockmvc-securitycontextholder]] - ==== 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: -+There are two simple ways to populate the user: - --* <> --* <> -+* <> -+* <> - - [[test-mockmvc-securitycontextholder-rpp]] - ==== 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": -+You have a number of options to associate a user to the current `HttpServletRequest`. -+The following example runs as a user (which does not need to exist) whose username is `user`, whose password is `password`, and whose role is `ROLE_USER`: -+ -+==== -+[source,java] -+---- -+mvc -+ .perform(get("/").with(user("user"))) -+---- -+==== - - [NOTE] - ==== - The support works by associating the user to the `HttpServletRequest`. --To associate the request to the `SecurityContextHolder` you need to ensure that the `SecurityContextPersistenceFilter` is associated with the `MockMvc` instance. --A few ways to do this are: -+To associate the request to the `SecurityContextHolder`, you need to ensure that the `SecurityContextPersistenceFilter` is associated with the `MockMvc` instance. -+You can do so in a number of ways: - - * Invoking <> - * Adding Spring Security's `FilterChainProxy` to `MockMvc` - * Manually adding `SecurityContextPersistenceFilter` to the `MockMvc` instance may make sense when using `MockMvcBuilders.standaloneSetup` - ==== - --[source,java] ------ --mvc -- .perform(get("/").with(user("user"))) ------ -- --You can easily make customizations. --For example, the following will run as a user (which does not need to exist) with the username "admin", the password "pass", and the roles "ROLE_USER" and "ROLE_ADMIN". -+You can make customizations. -+The following example runs as a user (which does not need to exist) whose username is `admin`, whose password is `pass`, and whose roles are `ROLE_USER` and `ROLE_ADMIN`. - -+==== - [source,java] - ---- - mvc - .perform(get("/admin").with(user("admin").password("pass").roles("USER","ADMIN"))) - ---- -+==== - --If you have a custom `UserDetails` that you would like to use, you can easily specify that as well. --For example, the following will use the specified `UserDetails` (which does not need to exist) to run with a `UsernamePasswordAuthenticationToken` that has a principal of the specified `UserDetails`: -+If you have a custom `UserDetails` object that you would like to use, you can specify that as well. -+The following example uses the specified `UserDetails` (which does not need to exist) to run with a `UsernamePasswordAuthenticationToken` that has a principal of the specified `UserDetails`: - -+==== - [source,java] - ---- - mvc - .perform(get("/").with(user(userDetails))) - ---- -+==== - --You can run as anonymous user using the following: -+You can run as anonymous user by using the following: - -+==== - [source,java] - ---- - mvc - .perform(get("/").with(anonymous())) - ---- -+==== - --This is especially useful if you are running with a default user and wish to process a few requests as an anonymous user. -+This is especially useful when you run with a default user and wish to process a few requests as an anonymous user. - --If you want a custom `Authentication` (which does not need to exist) you can do so using the following: -+If you want a custom `Authentication` (which does not need to exist), you can do so by using the following: - -+==== - [source,java] - ---- - mvc - .perform(get("/").with(authentication(authentication))) - ---- -+==== - --You can even customize the `SecurityContext` using the following: -+You can even customize the `SecurityContext`, by using the following: - -+==== - [source,java] - ---- - mvc - .perform(get("/").with(securityContext(securityContext))) - ---- -+==== - --We can also ensure to run as a specific user for every request by using ``MockMvcBuilders``'s default request. --For example, the following will run as a user (which does not need to exist) with the username "admin", the password "password", and the role "ROLE_ADMIN": -+We can also ensure running as a specific user for every request by using the default request of `MockMvcBuilders`. -+The following exampe runs as a user (which does not need to exist) whose username is `admin`, whose password is `password`, and whose role is `ROLE_ADMIN`: - -+==== - [source,java] - ---- - mvc = MockMvcBuilders -@@ -168,19 +189,23 @@ mvc = MockMvcBuilders - .apply(springSecurity()) - .build(); - ---- -+==== - --If you find you are using the same user in many of your tests, it is recommended to move the user to a method. --For example, you can specify the following in your own class named `CustomSecurityMockMvcRequestPostProcessors`: -+If you find yourself using the same user in many of your tests, we recommended moving the user to a method. -+For example, you can specify the following in your own `CustomSecurityMockMvcRequestPostProcessors` class: - -+==== - [source,java] - ---- - public static RequestPostProcessor rob() { - return user("rob").roles("ADMIN"); - } - ---- -+==== - - Now you can perform a static import on `SecurityMockMvcRequestPostProcessors` and use that within your tests: - -+==== - [source,java] - ---- - import static sample.CustomSecurityMockMvcRequestPostProcessors.*; -@@ -190,12 +215,14 @@ import static sample.CustomSecurityMockMvcRequestPostProcessors.*; - mvc - .perform(get("/").with(rob())) - ---- -- -+==== -+[[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 <>. --For example, the following will run the test with the user with username "user", password "password", and role "ROLE_USER": -+As an alternative to using a `RequestPostProcessor` to create your user, you can use the annotations described in <>. -+The following example runs the test with a user whose username is `user`, whose password is `password`, and whose role is `ROLE_USER`: - -+==== - [source,java] - ---- - @Test -@@ -206,9 +233,11 @@ mvc - ... - } - ---- -+==== - --Alternatively, the following will run the test with the user with username "user", password "password", and role "ROLE_ADMIN": -+Alternatively, the following example runs the test with a user whose username is `user`, whose password is `password`, and whose role is `ROLE_ADMIN`: - -+==== - [source,java] - ---- - @Test -@@ -219,33 +248,39 @@ mvc - ... - } - ---- -+==== - - ==== 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`. --For example, the snippet below: -+Now you can do so by using Spring Security's `httpBasic` `RequestPostProcessor`. -+Consider the following snippet: - -+==== - [source,java] - ---- - mvc - .perform(get("/").with(httpBasic("user","password"))) - ---- -+==== - --will attempt to use HTTP Basic to authenticate a user with the username "user" and the password "password" by ensuring the following header is populated on the HTTP Request: -+The preceding line tries to use HTTP Basic to authenticate a user whose username is `user` and whose password is `password` by ensuring the following header is populated on the HTTP Request: - -+==== - [source,text] - ---- - Authorization: Basic dXNlcjpwYXNzd29yZA== - ---- -+==== - - [[testing-oauth2]] - ==== 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`. - --For example, for a controller that looks like this: -+For example, consider the following controller: - -+==== - [source,java] - ---- - @GetMapping("/endpoint") -@@ -253,11 +288,13 @@ public String foo(Principal user) { - return user.getName(); - } - ---- -+==== - --There's nothing OAuth2-specific about it, so you will likely be able to simply <> and be fine. -+There is nothing OAuth2-specific about it, so you can probably <> and be fine. - --But, in cases where your controllers are bound to some aspect of Spring Security's OAuth 2.0 support, like the following: -+However, in cases where your controllers are bound to some aspect of Spring Security's OAuth 2.0 support, Spring Security's test support can come in handy: - -+==== - [source,java] - ---- - @GetMapping("/endpoint") -@@ -265,50 +302,57 @@ public String foo(@AuthenticationPrincipal OidcUser user) { - return user.getIdToken().getSubject(); - } - ---- -- --then Spring Security's test support can come in handy. -+==== - - [[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. -+Testing the method above with Spring MVC Test requires simulating some kind of grant flow with an authorization server. -+This can be a daunting task, which is why Spring Security ships with support for removing this boilerplate. - --For example, we can tell Spring Security to include a default `OidcUser` using the `SecurityMockMvcRequestPostProcessors#oidcLogin` method, like so: -+For example, we can tell Spring Security to include a default `OidcUser` by using the `SecurityMockMvcRequestPostProcessors#oidcLogin` method: - -+==== - [source,java] - ---- - mvc - .perform(get("/endpoint").with(oidcLogin())); - ---- -+==== - --What this will do is configure the associated `MockHttpServletRequest` with an `OidcUser` that includes a simple `OidcIdToken`, `OidcUserInfo`, and `Collection` of granted authorities. -+The preceding line configures the associated `MockHttpServletRequest` with an `OidcUser` that includes a `OidcIdToken`, an `OidcUserInfo`, and a `Collection` of granted authorities. - --Specifically, it will include an `OidcIdToken` with a `sub` claim set to `user`: -+Specifically, it includes an `OidcIdToken` with a `sub` claim set to `user`: - --[source,json] -+==== -+[source,java] - ---- - assertThat(user.getIdToken().getClaim("sub")).isEqualTo("user"); - ---- -+==== - --an `OidcUserInfo` with no claims set: -+It also includes an `OidcUserInfo` with no claims set: - --[source,json] -+==== -+[source,java] - ---- - assertThat(user.getUserInfo().getClaims()).isEmpty(); - ---- -+==== - --and a `Collection` of authorities with just one authority, `SCOPE_read`: -+Finally, it includes a `Collection` of authorities with only one authority, `SCOPE_read`: - --[source,json] -+==== -+[source,java] - ---- - assertThat(user.getAuthorities()).hasSize(1); - assertThat(user.getAuthorities()).containsExactly(new SimpleGrantedAuthority("SCOPE_read")); - ---- -+==== - - Spring Security does the necessary work to make sure that the `OidcUser` instance is available for <>. - --Further, it also links that `OidcUser` to a simple instance of `OAuth2AuthorizedClient` that it deposits into an mock `OAuth2AuthorizedClientRepository`. -+Further, it also links the `OidcUser` to an instance of `OAuth2AuthorizedClient` that it deposits into an mock `OAuth2AuthorizedClientRepository`. - This can be handy if your tests <>.. - - [[testing-oidc-login-authorities]] -@@ -316,8 +360,9 @@ This can be handy if your tests <>, 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. - --Let's say that we've got a controller that gets the logged-in user as an `OAuth2User`: -+Suppose that you have a controller that gets the logged-in user as an `OAuth2User`: - -+==== - [source,java] - ---- - @GetMapping("/endpoint") -@@ -403,35 +456,42 @@ public String foo(@AuthenticationPrincipal OAuth2User oauth2User) { - return oauth2User.getAttribute("sub"); - } - ---- -+==== - --In that case, we can tell Spring Security to include a default `OAuth2User` using the `SecurityMockMvcRequestPostProcessors#oauth2User` method, like so: -+In that case, you can tell Spring Security to include a default `OAuth2User` by using the `SecurityMockMvcRequestPostProcessors#oauth2User` method: - -+==== - [source,java] - ---- - mvc - .perform(get("/endpoint").with(oauth2Login())); - ---- -+==== - --What this will do is configure the associated `MockHttpServletRequest` with an `OAuth2User` that includes a simple `Map` of attributes and `Collection` of granted authorities. -+This line configures the associated `MockHttpServletRequest` with an `OAuth2User` that includes a simple `Map` of attributes and a `Collection` of granted authorities. - --Specifically, it will include a `Map` with a key/value pair of `sub`/`user`: -+Specifically, it includes a `Map` with a key/value pair of `sub`/`user`: - --[source,json] -+==== -+[source,java] - ---- - assertThat((String) user.getAttribute("sub")).isEqualTo("user"); - ---- -+==== - --and a `Collection` of authorities with just one authority, `SCOPE_read`: -+It also includes a `Collection` of authorities with only one authority, `SCOPE_read`: - --[source,json] -+==== -+[source,java] - ---- - assertThat(user.getAuthorities()).hasSize(1); - assertThat(user.getAuthorities()).containsExactly(new SimpleGrantedAuthority("SCOPE_read")); - ---- -+==== - - Spring Security does the necessary work to make sure that the `OAuth2User` instance is available for <>. - --Further, it also links that `OAuth2User` to a simple instance of `OAuth2AuthorizedClient` that it deposits in a mock `OAuth2AuthorizedClientRepository`. -+Further, it also links that `OAuth2User` to an instance of `OAuth2AuthorizedClient` that it deposits in a mock `OAuth2AuthorizedClientRepository`. - This can be handy if your tests <>. - - [[testing-oauth2-login-authorities]] -@@ -439,8 +499,9 @@ This can be handy if your tests <)` - For configuring the associated `ClientRegistration` --* `clientRegistration(ClientRegistration)` - For configuring the complete `ClientRegistration` -+* `principalName(String)`: For configuring the resource owner name -+* `clientRegistration(Consumer)`: For configuring the associated `ClientRegistration` -+* `clientRegistration(ClientRegistration)`: For configuring the complete `ClientRegistration` - --That last one is handy if you want to use a real `ClientRegistration` -+That last one is handy if you want to use a real `ClientRegistration` object. - --For example, let's say that you are wanting to use one of your app's `ClientRegistration` definitions, as specified in your `application.yml`. -+For example, suppose that you want to use one of your application's `ClientRegistration` definitions, as specified in your `application.yml`. - - In that case, your test can autowire the `ClientRegistrationRepository` and look up the one your test needs: - -+==== - [source,java] - ---- - @Autowired -@@ -623,33 +706,37 @@ mvc - .with(oauth2Client() - .clientRegistration(this.clientRegistrationRepository.findByRegistrationId("facebook")))); - ---- -+==== - - [[testing-jwt]] - ==== Testing JWT Authentication - --In order to make an authorized request on a resource server, you need a bearer token. -+To make an authorized request on a resource server, you need a bearer token. - --If your resource server is configured for JWTs, then this would mean that the bearer token needs to be signed and then encoded according to the JWT specification. --All of this can be quite daunting, especially when this isn't the focus of your test. -+If your resource server is configured for JWTs, the bearer token needs to be signed and then encoded according to the JWT specification. -+All of this can be quite daunting, especially when this is not the focus of your test. - --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: -+Fortunately, there are a number of ways that you can overcome this difficulty and let your tests focus on authorization and not on representing bearer tokens. -+We look at two of them in the next two subsections. - - ===== `jwt() RequestPostProcessor` - --The first way is via a `RequestPostProcessor`. --The simplest of these would look something like this: -+The first way is with a `RequestPostProcessor`. -+The simplest of these looks something like this: - -+==== - [source,java] - ---- - mvc - .perform(get("/endpoint").with(jwt())); - ---- -+==== - --What this will do is create a mock `Jwt`, passing it correctly through any authentication APIs so that it's available for your authorization mechanisms to verify. -+This line creates a mock `Jwt` and passes it correctly through any authentication APIs so that itis available for your authorization mechanisms to verify. - - By default, the `JWT` that it creates has the following characteristics: - -+==== - [source,json] - ---- - { -@@ -660,9 +747,11 @@ By default, the `JWT` that it creates has the following characteristics: - } - } - ---- -+==== - --And the resulting `Jwt`, were it tested, would pass in the following way: -+The resulting `Jwt`, were it tested, would pass in the following way: - -+==== - [source,java] - ---- - assertThat(jwt.getTokenValue()).isEqualTo("token"); -@@ -671,11 +760,13 @@ assertThat(jwt.getSubject()).isEqualTo("sub"); - GrantedAuthority authority = jwt.getAuthorities().iterator().next(); - assertThat(authority.getAuthority()).isEqualTo("read"); - ---- -+==== - --These values can, of course be configured. -+You can configure these values. - --Any headers or claims can be configured with their corresponding methods: -+You can configure any headers or claims with their corresponding methods: - -+==== - [source,java] - ---- - mvc -@@ -689,28 +780,34 @@ mvc - .perform(get("/endpoint") - .with(jwt().jwt(jwt -> jwt.claims(claims -> claims.remove("scope"))))); - ---- -+==== - - The `scope` and `scp` claims are processed the same way here as they are in a normal bearer token request. --However, this can be overridden simply by providing the list of `GrantedAuthority` instances that you need for your test: -+However, you can override this by providing the list of `GrantedAuthority` instances that you need for your test: - -+==== - [source,java] - ---- - mvc - .perform(get("/endpoint") - .with(jwt().authorities(new SimpleGrantedAuthority("SCOPE_messages")))); - ---- -+==== - --Or, if you have a custom `Jwt` to `Collection` converter, you can also use that to derive the authorities: -+Alternatively, if you have a custom `Jwt` to `Collection` converter, you can also use that to derive the authorities: - -+==== - [source,java] - ---- - mvc - .perform(get("/endpoint") - .with(jwt().authorities(new MyConverter()))); - ---- -+==== - --You can also specify a complete `Jwt`, for which `{security-api-url}org/springframework/security/oauth2/jwt/Jwt.Builder.html[Jwt.Builder]` comes quite handy: -+You can also specify a complete `Jwt`, which you can do with `{security-api-url}org/springframework/security/oauth2/jwt/Jwt.Builder.html[`Jwt.Builder`]`: - -+==== - [source,java] - ---- - Jwt jwt = Jwt.withTokenValue("token") -@@ -722,12 +819,14 @@ mvc - .perform(get("/endpoint") - .with(jwt().jwt(jwt))); - ---- -+==== - - ===== `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: -+Essentially, you can instantiate your own `JwtAuthenticationToken` and provide it in your test: - -+==== - [source,java] - ---- - Jwt jwt = Jwt.withTokenValue("token") -@@ -741,17 +840,19 @@ mvc - .perform(get("/endpoint") - .with(authentication(token))); - ---- -+==== - --Note that as an alternative to these, you can also mock the `JwtDecoder` bean itself with a `@MockBean` annotation. -+Note that, as an alternative to these approaches, you can also mock the `JwtDecoder` bean itself with a `@MockBean` annotation. - - [[testing-opaque-token]] - ==== Testing Opaque Token Authentication - --Similar to <>, opaque tokens require an authorization server in order to verify their validity, which can make testing more difficult. -+Similar to <>, opaque tokens require an authorization server to verify their validity, which can make testing more difficult. - To help with that, Spring Security has test support for opaque tokens. - --Let's say that we've got a controller that retrieves the authentication as a `BearerTokenAuthentication`: -+Suppose that you have a controller that retrieves the authentication as a `BearerTokenAuthentication`: - -+==== - [source,java] - ---- - @GetMapping("/endpoint") -@@ -759,27 +860,32 @@ public String foo(BearerTokenAuthentication authentication) { - return (String) authentication.getTokenAttributes("sub"); - } - ---- -+==== - --In that case, we can tell Spring Security to include a default `BearerTokenAuthentication` using the `SecurityMockMvcRequestPostProcessors#opaqueToken` method, like so: -+In that case, we can tell Spring Security to include a default `BearerTokenAuthentication` by using the `SecurityMockMvcRequestPostProcessors#opaqueToken` method: - -+==== - [source,java] - ---- - mvc - .perform(get("/endpoint").with(opaqueToken())); - ---- -+==== - --What this will do is configure the associated `MockHttpServletRequest` with a `BearerTokenAuthentication` that includes a simple `OAuth2AuthenticatedPrincipal`, `Map` of attributes, and `Collection` of granted authorities. -+This line configures the associated `MockHttpServletRequest` with a `BearerTokenAuthentication` that includes a simple `OAuth2AuthenticatedPrincipal`, a `Map` of attributes, and a `Collection` of granted authorities. - --Specifically, it will include a `Map` with a key/value pair of `sub`/`user`: -+Specifically, it includes a `Map` with a key/value pair of `sub`/`user`: - --[source,json] -+==== -+[source,java] - ---- - assertThat((String) token.getTokenAttributes().get("sub")).isEqualTo("user"); - ---- -+==== - --and a `Collection` of authorities with just one authority, `SCOPE_read`: -+It also includes a `Collection` of authorities with only one authority, `SCOPE_read`: - --[source,json] -+[source,java] - ---- - assertThat(token.getAuthorities()).hasSize(1); - assertThat(token.getAuthorities()).containsExactly(new SimpleGrantedAuthority("SCOPE_read")); -@@ -792,8 +898,9 @@ Spring Security does the necessary work to make sure that the `BearerTokenAuthen - - 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. - --In this case, you can supply what granted authorities you need using the `authorities()` method: -+In this case, you can supply the granted authorities you need by using the `authorities()` method: - -+==== - [source,java] - ---- - mvc -@@ -803,15 +910,17 @@ mvc - ) - ); - ---- -+==== - - [[testing-opaque-token-attributes]] - ===== 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. -+While granted authorities are quite common across all of Spring Security, we also have attributes, in the case of OAuth 2.0. - --Let's say, for example, that you've got a `user_id` attribute that indicates the user's id in your system. --You might access it like so in a controller: -+Suppose, for example, that you have a `user_id` attribute that indicates the user's ID in your system. -+You can access it in a controller: - -+==== - [source,java] - ---- - @GetMapping("/endpoint") -@@ -820,9 +929,11 @@ public String foo(BearerTokenAuthentication authentication) { - // ... - } - ---- -+==== - --In that case, you'd want to specify that attribute with the `attributes()` method: -+In that case, you want to specify that attribute with the `attributes()` method: - -+==== - [source,java] - ---- - mvc -@@ -832,21 +943,23 @@ mvc - ) - ); - ---- -+==== - - [[testing-opaque-token-principal]] - ===== Additional Configurations - --There are additional methods, too, for further configuring the authentication; it simply depends on what data your controller expects. -+There are additional methods, too, for further configuring the authentication. It simply depends on what data your controller expects. - --One such is `principal(OAuth2AuthenticatedPrincipal)`, which you can use to configure the complete `OAuth2AuthenticatedPrincipal` instance that underlies the `BearerTokenAuthentication` -+One such method is `principal(OAuth2AuthenticatedPrincipal)`, which you can use to configure the complete `OAuth2AuthenticatedPrincipal` instance that underlies the `BearerTokenAuthentication` - --It's handy if you: --1. Have your own implementation of `OAuth2AuthenticatedPrincipal`, or --2. Want to specify a different principal name -+It is useful if you: -+* Have your own implementation of `OAuth2AuthenticatedPrincipal` -+* Want to specify a different principal name - --For example, let's say that your authorization server sends the principal name in the `user_name` attribute instead of the `sub` attribute. -+For example, suppose that your authorization server sends the principal name in the `user_name` attribute instead of the `sub` attribute. - In that case, you can configure an `OAuth2AuthenticatedPrincipal` by hand: - -+==== - [source,java] - ---- - Map attributes = Collections.singletonMap("user_name", "foo_user"); -@@ -860,136 +973,162 @@ mvc - .with(opaqueToken().principal(principal)) - ); - ---- -+==== - --Note that as an alternative to using `opaqueToken()` test support, you can also mock the `OpaqueTokenIntrospector` bean itself with a `@MockBean` annotation. -+Note that, as an alternative to using `opaqueToken()` test support, you can also mock the `OpaqueTokenIntrospector` bean itself with a `@MockBean` annotation. - - === 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. --In order to use Spring Security's `RequestBuilder` implementations ensure the following static import is used: -+Spring MVC Test also provides a `RequestBuilder` interface that you can use to create the `MockHttpServletRequest` for your test. -+Spring Security provides a few `RequestBuilder` implementations that you can use to make testing easier. -+To use Spring Security's `RequestBuilder` implementations, use the following static import: - -+==== - [source,java] - ---- - import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestBuilders.*; - ---- -+==== - --==== 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: -+You can create a request to test a form-based authentication using Spring Security's testing support. -+For example, the following line submits a POST to `/login` with a username of `user`, a password of `password`, and a valid CSRF token: - -+==== - [source,java] - ---- - mvc - .perform(formLogin()) - ---- -+==== - - It is easy to customize the request. --For example, the following will submit a POST to "/auth" with the username "admin", the password "pass", and a valid CSRF token: -+For example, the following line submits a POST to `/auth` with a username of `admin`, a password of `pass`, and a valid CSRF token: - -+==== - [source,java] - ---- - mvc - .perform(formLogin("/auth").user("admin").password("pass")) - ---- -+==== - --We can also customize the parameters names that the username and password are included on. --For example, this is the above request modified to include the username on the HTTP parameter "u" and the password on the HTTP parameter "p". -+You can also customize the parameters names on which the username and password are included. -+For example, the following line modifies the preceding request to include the username on the HTTP parameter named `u` and the password on the HTTP parameter named `p`: - -+==== - [source,java] - ---- - mvc - .perform(formLogin("/auth").user("u","admin").password("p","pass")) - ---- -+==== - - [[test-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: -+A minor but still useful use case for Spring Security's testing support is to test logging out. -+The following example submits a POST to `/logout` with a valid CSRF token: - -+==== - [source,java] - ---- - mvc - .perform(logout()) - ---- -+==== - --You can also customize the URL to post to. --For example, the snippet below will submit a POST to "/signout" with a valid CSRF token: -+You can also customize the URL to which to post. -+The following example submits a POST to `/signout` with a valid CSRF token: - -+==== - [source,java] - ---- - mvc - .perform(logout("/signout")) - ---- -+==== - - === 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. --In order to use Spring Security's `ResultMatcher` implementations ensure the following static import is used: -+At times, you may want to make various security-related assertions about a request. -+To accommodate this need, Spring Security's testing support implements Spring MVC Test's `ResultMatcher` interface. -+To use Spring Security's `ResultMatcher` implementations, use the following static import: - -+==== - [source,java] - ---- - import static org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.*; - ---- -+==== - - ==== Unauthenticated Assertion - --At times it may be valuable to assert that there is no authenticated user associated with the result of a `MockMvc` invocation. -+At times, you may want 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. --You can easily do this with Spring Security's testing support using something like the following: -+You can do so with Spring Security's testing support by using something like the following: - -+==== - [source,java] - ---- - mvc - .perform(formLogin().password("invalid")) - .andExpect(unauthenticated()); - ---- -+==== - - ==== 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. --We could verify that a form based login was successful with the following snippet of code: -+Often, you must assert that an authenticated user exists. -+For example, you may want to verify that we authenticated successfully. -+You could verify that a form-based login was successful: - -+==== - [source,java] - ---- - mvc - .perform(formLogin()) - .andExpect(authenticated()); - ---- -+==== - --If we wanted to assert the roles of the user, we could refine our previous code as shown below: -+To assert the roles of the user, you can refine our previous code as follows: - -+==== - [source,java] - ---- - mvc - .perform(formLogin().user("admin")) - .andExpect(authenticated().withRoles("USER","ADMIN")); - ---- -+==== - --Alternatively, we could verify the username: -+Similarly, you can verify the username: - -+==== - [source,java] - ---- - mvc - .perform(formLogin().user("admin")) - .andExpect(authenticated().withUsername("admin")); - ---- -+==== - --We can also combine the assertions: -+You can also combine the assertions: - -+==== - [source,java] - ---- - mvc - .perform(formLogin().user("admin").roles("USER","ADMIN")) - .andExpect(authenticated().withUsername("admin")); - ---- -+==== - --We can also make arbitrary assertions on the authentication -+We can also make arbitrary assertions on the authentication: - -+==== - [source,java] - ---- - mvc -@@ -997,3 +1136,4 @@ mvc - .andExpect(authenticated().withAuthentication(auth -> - assertThat(auth).isInstanceOf(UsernamePasswordAuthenticationToken.class))); - ---- -+==== -diff --git a/docs/manual/src/docs/asciidoc/index.adoc b/docs/manual/src/docs/asciidoc/index.adoc -index 3be0158b67..c248a98304 100644 ---- a/docs/manual/src/docs/asciidoc/index.adoc -+++ b/docs/manual/src/docs/asciidoc/index.adoc -@@ -6,8 +6,9 @@ Ben Alex; Luke Taylor; Rob Winch; Gunnar Hillert; Joe Grandja; Jay Bryant; Eddú - :tabsize: 4 - :toc: left - --// FIXME: Add links for authentication, authorization, common attacks --Spring Security is a framework that provides authentication, authorization, and protection against common attacks. -+ -+// FIXME: The current authorization link is for the servlet architecture. We need a reactive link, too. (On a deeper level, we need an authorization topic that accounts for both paths.) -+Spring Security is a framework that provides <>, <>, and protection against <>. - // FIXME: Add links for imperative and reactive applications - With first class support for both imperative and reactive applications, it is the de-facto standard for securing Spring-based applications. - -@@ -16,5 +17,3 @@ include::{include-dir}/about/index.adoc[] - include::{include-dir}/servlet/index.adoc[] - - include::{include-dir}/reactive/index.adoc[] -- -- --- -2.24.1 - diff --git a/docs/manual/src/docs/asciidoc/_includes/about/authentication/password-storage.adoc b/docs/manual/src/docs/asciidoc/_includes/about/authentication/password-storage.adoc index a0cec811eda..b961ca5a12c 100644 --- a/docs/manual/src/docs/asciidoc/_includes/about/authentication/password-storage.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/about/authentication/password-storage.adoc @@ -9,7 +9,7 @@ Typically, `PasswordEncoder` is used for storing a password that needs to be com == Password Storage History Throughout the years, the standard mechanism for storing passwords has evolved. -In the beginning, passwords were stored in plain text. +In the beginning, passwords were stored in plaintext. The passwords were assumed to be safe because the data store the passwords were saved in required credentials to access it. However, malicious users were able to find ways to get large "`data dumps`" of usernames and passwords by using attacks such as SQL Injection. As more and more user credentials became public, security experts realized that we needed to do more to protect users' passwords. @@ -189,8 +189,8 @@ By default, the result of invoking `matches(CharSequence, String)` with a passwo This behavior can be customized by using `DelegatingPasswordEncoder.setDefaultPasswordEncoderForMatches(PasswordEncoder)`. By using the `id`, we can match on any password encoding but encode passwords by using the most modern password encoding. -This is important, because unlike encryption, password hashes are designed so that there is no simple way to recover the plain text. -Since there is no way to recover the plain text, it is difficult to migrate the passwords. +This is important, because unlike encryption, password hashes are designed so that there is no simple way to recover the plaintext. +Since there is no way to recover the plaintext, it is difficult to migrate the passwords. While it is simple for users to migrate `NoOpPasswordEncoder`, we chose to include it by default to make it simple for the getting-started experience. [[authentication-password-storage-dep-getting-started]] diff --git a/docs/manual/src/docs/asciidoc/_includes/about/exploits/headers.adoc b/docs/manual/src/docs/asciidoc/_includes/about/exploits/headers.adoc index babd63026f4..9ebccff448e 100644 --- a/docs/manual/src/docs/asciidoc/_includes/about/exploits/headers.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/about/exploits/headers.adoc @@ -246,7 +246,7 @@ Content-Security-Policy-Report-Only: script-src 'self' https://trustedscripts.ex ---- ==== -If the site violates this policy, by attempting to load a script from evil.com, the user-agent sends a violation report to the declared URL specified by the `report-uri` directive but still lets the violating resource load. +If the site violates this policy, by attempting to load a script from `evil.example.com`, the user-agent sends a violation report to the declared URL specified by the `report-uri` directive but still lets the violating resource load. Applying Content Security Policy to a web application is often a non-trivial undertaking. The following resources may provide further assistance in developing effective security policies for your site: diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/form.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/form.adoc index 85f7601fcda..c0655d4c26a 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/form.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/form.adoc @@ -6,9 +6,9 @@ This section provides details on how form based authentication works within Spri // FIXME: describe authenticationentrypoint, authenticationfailurehandler, authenticationsuccesshandler This section examines how form-based login works within Spring Security. -First, we see how the user is redirected to the log in form: +First, we see how the user is redirected to the login form: -.Redirecting to the Log In Page +.Redirecting to the Login Page image::{figures}/loginurlauthenticationentrypoint.png[] The preceding figure builds off our <> diagram. @@ -22,7 +22,7 @@ In most cases, the `AuthenticationEntryPoint` is an instance of {security-api-ur image:{icondir}/number_4.png[] The browser requests the login page to which it was redirected. -image:{icondir}/number_5.png[] Something within the application must <>. +image:{icondir}/number_5.png[] Something within the application must <>. [[servlet-authentication-usernamepasswordauthenticationfilter]] When the username and password are submitted, the `UsernamePasswordAuthenticationFilter` authenticates the username and password. @@ -49,7 +49,7 @@ See the {security-api-url}springframework/security/web/authentication/Authentica image:{icondir}/number_4.png[] If authentication is successful, then __Success__. -. `SessionAuthenticationStrategy` is notified of a new log in. +. `SessionAuthenticationStrategy` is notified of a new login. See the {security-api-url}springframework/security/web/authentication/session/SessionAuthenticationStrategy.html[`SessionAuthenticationStrategy`] interface in the Javadoc. . The <> is set on the <>. See the {security-api-url}springframework/security/web/context/SecurityContextPersistenceFilter.html[`SecurityContextPersistenceFilter`] class in the Javadoc. @@ -64,7 +64,7 @@ By default, Spring Security form login is enabled. However, as soon as any servlet-based configuration is provided, form based login must be explicitly provided. The following example shows a minimal, explicit Java configuration: -.Form LogIn +.Form Login ==== .Java [source,java,role="primary"] @@ -103,7 +103,7 @@ Most production applications require a custom login form. [[servlet-authentication-form-custom]] The following configuration demonstrates how to provide a custom login form. -.Custom Log In Form Configuration +.Custom Login Form Configuration ==== .Java [source,java,role="primary"] @@ -187,7 +187,7 @@ There are a few key points about the default HTML form: * If the HTTP parameter named `error` is found, it indicates the user failed to provide a valid username or password. * If the HTTP parameter named `logout` is found, it indicates the user has logged out successfully. -Many users do not need much more than to customize the log in page. +Many users do not need much more than to customize the login page. However, if needed, you can customize everything shown earlier with additional configuration. [[servlet-authentication-form-custom-controller]] diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/kotlin-configuration/index.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/kotlin-configuration/index.adoc index 03dda38e48c..49d3d4c9abd 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/kotlin-configuration/index.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/kotlin-configuration/index.adoc @@ -52,11 +52,10 @@ Note that this configuration is parallels the XML namespace configuration: We can configure multiple HttpSecurity instances, just as we can have multiple `` blocks. The key is to extend the `WebSecurityConfigurerAdapter` multiple times. -The following example has a different configuration for URL's that start with `/api/`: +The following example has a different configuration for URL's that start with `/api/`: -// The source is Kotlin, but we specify Java to get code formatting. At present, Asciidoctor doesnt' have a Kotlin formatter. ==== -[source,java] +[source,kotlin] ---- @EnableWebSecurity class MultiHttpSecurityConfig { diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/oauth2/oauth2-resourceserver.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/oauth2/oauth2-resourceserver.adoc index e51364d40a2..f5b2ea6dc18 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/oauth2/oauth2-resourceserver.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/oauth2/oauth2-resourceserver.adoc @@ -3,7 +3,7 @@ :figures: images/servlet/oauth2 :icondir: images/icons -Spring Security supports protecting endpoints BY using two forms of OAuth 2.0 https://tools.ietf.org/html/rfc6750.html[Bearer Tokens]: +Spring Security supports protecting endpoints by using two forms of OAuth 2.0 https://tools.ietf.org/html/rfc6750.html[Bearer Tokens]: * https://tools.ietf.org/html/rfc7519[JWT] * Opaque Tokens @@ -1485,7 +1485,7 @@ This startup process is quite a bit simpler than for JWTs, since no endpoints ne Once the application has started, Resource Server tries to process any request containing an `Authorization: Bearer` header: ==== -[source,text] +[source,http] ---- GET / HTTP/1.1 Authorization: Bearer some-token-value # Resource Server will process this @@ -3026,7 +3026,7 @@ In these circumstances, Resource Server throws an `InvalidBearerTokenException`. Like other exceptions, this results in an OAuth 2.0 Bearer Token error response: ==== -[source,text] +[source,http] ---- HTTP/1.1 401 Unauthorized WWW-Authenticate: Bearer error_code="invalid_token", error_description="Unsupported algorithm of none", error_uri="https://tools.ietf.org/html/rfc6750#section-3.1" From 7171521b474ad2c1bce7086b7cb1f0b86dace7d5 Mon Sep 17 00:00:00 2001 From: Jay Bryant Date: Fri, 4 Jun 2021 14:12:59 -0500 Subject: [PATCH 6/7] Further changes based on feedback Mostly restoring the formatting of admonitions. --- .../authentication/password-storage.adoc | 16 +- .../_includes/about/exploits/csrf.adoc | 25 ++- .../_includes/about/exploits/headers.adoc | 95 ++++++++--- .../about/getting-spring-security.adoc | 5 +- .../asciidoc/_includes/about/modules.adoc | 6 +- .../_includes/reactive/exploits/csrf.adoc | 10 +- .../asciidoc/_includes/reactive/method.adoc | 5 +- .../_includes/reactive/oauth2/login.adoc | 26 ++- .../reactive/oauth2/resource-server.adoc | 50 ++++-- .../registered-oauth2-authorized-client.adoc | 5 +- .../asciidoc/_includes/reactive/rsocket.adoc | 5 +- .../_includes/reactive/webclient.adoc | 5 +- .../_includes/servlet/appendix/faq.adoc | 5 +- .../_includes/servlet/appendix/namespace.adoc | 32 +++- .../exception-translation-filter.adoc | 5 +- .../servlet/authentication/anonymous.adoc | 5 +- .../_includes/servlet/authentication/cas.adoc | 5 +- .../servlet/authentication/logout.adoc | 5 +- .../servlet/authentication/openid.adoc | 5 +- .../servlet/authentication/preauth.adoc | 6 +- .../authentication/session-management.adoc | 10 +- .../servlet/authentication/unpwd/digest.adoc | 5 +- .../servlet/authentication/unpwd/jdbc.adoc | 5 +- .../servlet/authentication/unpwd/ldap.adoc | 10 +- .../unpwd/user-details-service.adoc | 5 +- .../authorization/method-security.adoc | 15 +- .../_includes/servlet/crypto/index.adoc | 6 +- .../_includes/servlet/exploits/csrf.adoc | 15 +- .../_includes/servlet/exploits/firewall.adoc | 10 +- .../_includes/servlet/hello/index.adoc | 5 +- .../servlet/integrations/jsp-taglibs.adoc | 12 +- .../_includes/servlet/integrations/mvc.adoc | 21 ++- .../servlet/integrations/servlet-api.adoc | 10 +- .../servlet/java-configuration/index.adoc | 11 +- .../servlet/kotlin-configuration/index.adoc | 5 +- .../_includes/servlet/namespace/index.adoc | 10 +- .../servlet/oauth2/oauth2-client.adoc | 158 ++++++++++++++---- .../servlet/oauth2/oauth2-login.adoc | 67 ++++++-- .../servlet/oauth2/oauth2-resourceserver.adoc | 91 ++++++++-- .../_includes/servlet/saml2/saml2-login.adoc | 88 ++++++++-- .../_includes/servlet/test/index.adoc | 5 +- .../_includes/servlet/test/method.adoc | 5 +- .../_includes/servlet/test/mockmvc.adoc | 5 +- 43 files changed, 712 insertions(+), 183 deletions(-) diff --git a/docs/manual/src/docs/asciidoc/_includes/about/authentication/password-storage.adoc b/docs/manual/src/docs/asciidoc/_includes/about/authentication/password-storage.adoc index b961ca5a12c..6c512d1c04d 100644 --- a/docs/manual/src/docs/asciidoc/_includes/about/authentication/password-storage.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/about/authentication/password-storage.adoc @@ -146,15 +146,15 @@ All of the original passwords are `password`. ---- ==== -<1> The first password has a `PasswordEncoder` id of `bcrypt` and an encoded password value of `$2a$10$dXJ3SW6G7P50lGmMkkmwe.20cQQubK3.HZWzG3YB1tlRy.fqvM/BG`. +<1> The first password has a `PasswordEncoder` id of `bcrypt` and an `encodedPassword` value of `$2a$10$dXJ3SW6G7P50lGmMkkmwe.20cQQubK3.HZWzG3YB1tlRy.fqvM/BG`. When matching, it would delegate to `BCryptPasswordEncoder` -<2> The second password has a `PasswordEncoder` id of `noop` and encoded password value of `password`. +<2> The second password has a `PasswordEncoder` id of `noop` and `encodedPassword` value of `password`. When matching, it would delegate to `NoOpPasswordEncoder` -<3> The third password has a `PasswordEncoder` id of `pbkdf2` and encoded password value of `5d923b44a6d129f3ddf3e3c8d29412723dcbde72445e8ef6bf3b508fbf17fa4ed4d6b99ca763d8dc`. +<3> The third password has a `PasswordEncoder` id of `pbkdf2` and `encodedPassword` value of `5d923b44a6d129f3ddf3e3c8d29412723dcbde72445e8ef6bf3b508fbf17fa4ed4d6b99ca763d8dc`. When matching, it would delegate to `Pbkdf2PasswordEncoder` -<4> The fourth password has a `PasswordEncoder` id of `scrypt` and encoded password value of `$e0801$8bWJaSu2IKSn9Z9kM+TPXfOc/9bdYSrN1oD9qfVThWEwdRTnO7re7Ei+fUZRJ68k9lTyuTeUp4of4g24hHnazw==$OAOec05+bXxvuu/1qZ6NUR+xQYvYv7BeL1QxwRpY5Pc=` +<4> The fourth password has a `PasswordEncoder` id of `scrypt` and `encodedPassword` value of `$e0801$8bWJaSu2IKSn9Z9kM+TPXfOc/9bdYSrN1oD9qfVThWEwdRTnO7re7Ei+fUZRJ68k9lTyuTeUp4of4g24hHnazw==$OAOec05+bXxvuu/1qZ6NUR+xQYvYv7BeL1QxwRpY5Pc=` When matching, it would delegate to `SCryptPasswordEncoder` -<5> The final password has a `PasswordEncoder` id of `sha256` and encoded password value of `97cde38028ad898ebc02e690819fa220e88c62e0699403e94fff291cfffaf8410849f27605abcbc0`. +<5> The final password has a `PasswordEncoder` id of `sha256` and `encodedPassword` value of `97cde38028ad898ebc02e690819fa220e88c62e0699403e94fff291cfffaf8410849f27605abcbc0`. When matching, it would delegate to `StandardPasswordEncoder` [NOTE] @@ -487,4 +487,8 @@ fun passwordEncoder(): PasswordEncoder { ---- ==== -NOTE: XML Configuration requires the `NoOpPasswordEncoder` bean name to be `passwordEncoder`. + +[NOTE] +==== +XML Configuration requires the `NoOpPasswordEncoder` bean name to be `passwordEncoder`. +==== diff --git a/docs/manual/src/docs/asciidoc/_includes/about/exploits/csrf.adoc b/docs/manual/src/docs/asciidoc/_includes/about/exploits/csrf.adoc index 67728e135ba..ad290d6ba97 100644 --- a/docs/manual/src/docs/asciidoc/_includes/about/exploits/csrf.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/about/exploits/csrf.adoc @@ -8,8 +8,11 @@ In the following sections, we explore: * <> * <> -NOTE: This portion of the documentation discusses the general topic of CSRF protection. +[NOTE] +==== +This portion of the documentation discusses the general topic of CSRF protection. See the relevant sections for specific information on CSRF protection for <>- and <>-based applications. +==== [[csrf-explained]] == What is a CSRF Attack? @@ -95,7 +98,10 @@ Spring provides two mechanisms to protect against CSRF attacks: * The <> * Specifying the <> on your session cookie -NOTE: Both protections require that <>. +[NOTE] +==== +Both protections require that <>. +==== [[csrf-protection-idempotent]] === Safe Methods Must be Idempotent @@ -172,9 +178,12 @@ The evil website cannot provide the correct value for the `_csrf` parameter (whi An emerging way to protect against <> is to specify the https://tools.ietf.org/html/draft-west-first-party-cookies[SameSite Attribute] on cookies. A server can specify the `SameSite` attribute when setting a cookie to indicate that the cookie should not be sent when coming from external sites. -NOTE: Spring Security does not directly control the creation of the session cookie, so it does not provide support for the SameSite attribute. +[NOTE] +==== +Spring Security does not directly control the creation of the session cookie, so it does not provide support for the SameSite attribute. https://spring.io/projects/spring-session[Spring Session] provides support for the `SameSite` attribute in servlet-based applications. Spring Framework's https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/server/session/CookieWebSessionIdResolver.html[`CookieWebSessionIdResolver`] provides support for the `SameSite` attribute in WebFlux-based applications. +==== An example of an HTTP response header with the `SameSite` attribute might look like: @@ -207,7 +216,10 @@ The user receives an email at https://email.example.org that includes a link to If the user clicks on the link, they would rightfully expect to be authenticated to the social media site. However, if the `SameSite` attribute is `Strict`, the cookie would not be sent and the user would not be authenticated. -NOTE: We could improve the protection and usability of `SameSite` protection against CSRF attacks by implementing https://github.com/spring-projects/spring-security/issues/7537[gh-7537]. +[NOTE] +==== +We could improve the protection and usability of `SameSite` protection against CSRF attacks by implementing https://github.com/spring-projects/spring-security/issues/7537[gh-7537]. +==== Another obvious consideration is that, in order for the `SameSite` attribute to protect users, the browser must support the `SameSite` attribute. Most modern browsers do https://developer.mozilla.org/en-US/docs/Web/HTTP/headers/Set-Cookie#Browser_compatibility[support the SameSite attribute]. @@ -351,8 +363,11 @@ There are two options to using CSRF protection with multipart/form-data: Each option has its trade-offs. -NOTE: Before you integrate Spring Security's CSRF protection with multipart file upload, you should first ensure that you can upload without the CSRF protection. +[NOTE] +==== +Before you integrate Spring Security's CSRF protection with multipart file upload, you should first ensure that you can upload without the CSRF protection. More information about using multipart forms with Spring, see the https://docs.spring.io/spring/docs/5.2.x/spring-framework-reference/web.html#mvc-multipart[1.1.11. Multipart Resolver] section of the Spring reference and the https://docs.spring.io/spring/docs/5.2.x/javadoc-api/org/springframework/web/multipart/support/MultipartFilter.html[`MultipartFilter` Javadoc]. +==== [[csrf-considerations-multipart-body]] ==== Place CSRF Token in the Body diff --git a/docs/manual/src/docs/asciidoc/_includes/about/exploits/headers.adoc b/docs/manual/src/docs/asciidoc/_includes/about/exploits/headers.adoc index 9ebccff448e..baed9fe61f8 100644 --- a/docs/manual/src/docs/asciidoc/_includes/about/exploits/headers.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/about/exploits/headers.adoc @@ -1,8 +1,11 @@ [[headers]] = Security HTTP Response Headers -NOTE: This portion of the documentation discusses the general topic of Security HTTP Response Headers. +[NOTE] +==== +This portion of the documentation discusses the general topic of Security HTTP Response Headers. See the relevant sections for specific information on Security HTTP Response Headers in <>- and <>-based applications. +==== You can use https://www.owasp.org/index.php/OWASP_Secure_Headers_Project#tab=Headers[HTTP response headers] in many ways to increase the security of web applications. This section is dedicated to the various HTTP response headers for which Spring Security provides explicit support. @@ -11,7 +14,10 @@ If necessary, you can also configure Spring Security to provide <>- and <>-based applications. +[NOTE] +==== +See the relevant sections for how to customize the defaults for both <>- and <>-based applications. +==== Spring Security provides a default set of security related HTTP response headers to provide secure defaults. @@ -31,7 +37,10 @@ X-XSS-Protection: 1; mode=block ---- ==== -NOTE: Strict-Transport-Security is added only on HTTPS requests +[NOTE] +==== +Strict-Transport-Security is added only on HTTPS requests +==== If the defaults do not meet your needs, you can easily remove, modify, or add headers from these defaults. For additional details on each of these headers, see the corresponding sections: @@ -45,7 +54,10 @@ For additional details on each of these headers, see the corresponding sections: [[headers-cache-control]] == Cache Control -NOTE: See the relevant sections for how to customize the defaults for both <>- and <>-based applications. +[NOTE] +==== +See the relevant sections for how to customize the defaults for both <>- and <>-based applications. +==== Spring Security's default is to disable caching to protect the user's content. @@ -70,15 +82,21 @@ This allows for applications to ensure that static resources (such as CSS and Ja [[headers-content-type-options]] == Content Type Options -NOTE: See the relevant sections for how to customize the defaults for both <>- and <>-based applications. +[NOTE] +==== +See the relevant sections for how to customize the defaults for both <>- and <>-based applications. +==== Historically, browsers, including Internet Explorer, would try to guess the content type of a request by using https://en.wikipedia.org/wiki/Content_sniffing[content sniffing]. This let browsers improve the user experience by guessing the content type on resources that had not specified the content type. For example, if a browser encountered a JavaScript file that did not have the content type specified, it would be able to guess the content type and then run it. -NOTE: There are many additional things one should do (such as only display the document in a distinct domain, ensure Content-Type header is set, sanitize the document, and others) when allowing content to be uploaded. +[NOTE] +==== +There are many additional things one should do (such as only display the document in a distinct domain, ensure Content-Type header is set, sanitize the document, and others) when allowing content to be uploaded. However, these measures are out of the scope of what Spring Security provides. It is also important to point out that, when disabling content sniffing, you must specify the content type in order for things to work properly. +==== The problem with content sniffing is that this allowed malicious users to use polyglots (that is, a file that is valid as multiple content types) to perform XSS attacks. For example, some sites may allow users to submit a valid postscript document to a website and view it. @@ -97,7 +115,10 @@ X-Content-Type-Options: nosniff [[headers-hsts]] == HTTP Strict Transport Security (HSTS) -NOTE: Refer to the relevant sections to see how to customize the defaults for both <> and <> based applications. +[NOTE] +==== +Refer to the relevant sections to see how to customize the defaults for both <> and <> based applications. +==== When you type in your bank's website, do you enter `mybank.example.com` or do you enter `https://mybank.example.com`? If you omit the `https` protocol, you are potentially vulnerable to https://en.wikipedia.org/wiki/Man-in-the-middle_attack[Man-in-the-Middle attacks]. @@ -107,8 +128,11 @@ Many users omit the `https` protocol, and this is why https://tools.ietf.org/htm Once `mybank.example.com` is added as a https://tools.ietf.org/html/rfc6797#section-5.1[HSTS host], a browser can know ahead of time that any request to mybank.example.com should be interpreted as https://mybank.example.com. This greatly reduces the possibility of a Man-in-the-Middle attack occurring. -NOTE: In accordance with https://tools.ietf.org/html/rfc6797#section-7.2[RFC6797], the HSTS header is injected only into HTTPS responses. +[NOTE] +==== +In accordance with https://tools.ietf.org/html/rfc6797#section-7.2[RFC6797], the HSTS header is injected only into HTTPS responses. For the browser to acknowledge the header, the browser must first trust the CA that signed the SSL certificate used to make the connection (not just the SSL certificate). +==== One way for a site to be marked as a HSTS host is to have the host preloaded into the browser. Another way is to add the `Strict-Transport-Security` header to the response. @@ -131,7 +155,10 @@ For more details on HSTS preload, see https://hstspreload.org. [[headers-hpkp]] == HTTP Public Key Pinning (HPKP) -NOTE: To remain passive, Spring Security still provides <>. However, for the reasons listed earlier, HPKP is no longer recommended by the Spring Security team. +[NOTE] +==== +To remain passive, Spring Security still provides <>. However, for the reasons listed earlier, HPKP is no longer recommended by the Spring Security team. +==== https://developer.mozilla.org/en-US/docs/Web/HTTP/Public_Key_Pinning[HTTP Public Key Pinning (HPKP)] specifies to a web client which public key to use with a certain web server to prevent Man-in-the-Middle (MITM) attacks with forged certificates. When used correctly, HPKP could add additional layers of protection against compromised certificates. @@ -143,14 +170,20 @@ For additional details around why HPKP is no longer recommended, read https://bl [[headers-frame-options]] == X-Frame-Options -NOTE: See the relevant sections to see how to customize the defaults for both <> and <> based applications. +[NOTE] +==== +See the relevant sections to see how to customize the defaults for both <> and <> based applications. +==== Letting your website be added to a frame can be a security issue. For example, by using clever CSS styling, users could be tricked into clicking on something that they were not intending. For example, a user that is logged into their bank might click a button that grants access to other users. This sort of attack is known as https://en.wikipedia.org/wiki/Clickjacking[Clickjacking]. -NOTE: Another modern approach to dealing with clickjacking is to use <>. +[NOTE] +==== +Another modern approach to dealing with clickjacking is to use <>. +==== There are a number ways to mitigate clickjacking attacks. For example, to protect legacy browsers from clickjacking attacks, you can use https://www.owasp.org/index.php/Clickjacking_Defense_Cheat_Sheet#Best-for-now_Legacy_Browser_Frame_Breaking_Script[frame breaking code]. @@ -169,7 +202,10 @@ X-Frame-Options: DENY [[headers-xss-protection]] == X-XSS-Protection -NOTE: See the relevant sections to see how to customize the defaults for both <>- and <>-based applications. +[NOTE] +==== +See the relevant sections to see how to customize the defaults for both <>- and <>-based applications. +==== Some browsers have built-in support for filtering out https://www.owasp.org/index.php/Testing_for_Reflected_Cross_site_scripting_(OWASP-DV-001)[reflected XSS attacks]. This is by no means foolproof but does assist in XSS protection. @@ -190,14 +226,20 @@ X-XSS-Protection: 1; mode=block [[headers-csp]] == Content Security Policy (CSP) -NOTE: See the relevant sections to see how to configure both <>- and <>-based applications. +[NOTE] +==== +See the relevant sections to see how to configure both <>- and <>-based applications. +==== https://www.w3.org/TR/CSP2/[Content Security Policy (CSP)] is a mechanism that web applications can use to mitigate content injection vulnerabilities, such as cross-site scripting (XSS). CSP is a declarative policy that provides a facility for web application authors to declare and ultimately inform the client (user-agent) about the sources from which the web application expects to load resources. -NOTE: Content Security Policy is not intended to solve all content injection vulnerabilities. +[NOTE] +==== +Content Security Policy is not intended to solve all content injection vulnerabilities. Instead, you can use CSP to help reduce the harm caused by content injection attacks. As a first line of defense, web application authors should validate their input and encode their output. +==== A web application can use CSP by including one of the following HTTP headers in the response: @@ -260,7 +302,10 @@ https://www.w3.org/TR/CSP2/[W3C Candidate Recommendation] [[headers-referrer]] == Referrer Policy -NOTE: See the relevant sections to see how to configure both <>- and <>-based applications. +[NOTE] +==== +See the relevant sections to see how to configure both <>- and <>-based applications. +==== https://www.w3.org/TR/referrer-policy[Referrer Policy] is a mechanism that web applications can use to manage the referrer field, which contains the last page the user was on. @@ -280,7 +325,10 @@ The Referrer-Policy response header instructs the browser to let the destination [[headers-feature]] == Feature Policy -NOTE: See the relevant sections to see how to configure both <>- and <>-based applications. +[NOTE] +==== +See the relevant sections to see how to configure both <>- and <>-based applications. +==== https://wicg.github.io/feature-policy/[Feature Policy] is a mechanism that lets web developers selectively enable, disable, and modify the behavior of certain APIs and web features in the browser. @@ -299,7 +347,10 @@ These policies restrict what APIs the site can access or modify the browser's de [[headers-permissions]] == Permissions Policy -NOTE: See the relevant sections to see how to configure both <>- and <>-based applications. +[NOTE] +==== +See the relevant sections to see how to configure both <>- and <>-based applications. +==== https://w3c.github.io/webappsec-permissions-policy/[Permissions Policy] is a mechanism that lets web developers selectively enable, disable, and modify the behavior of certain APIs and web features in the browser. @@ -318,7 +369,10 @@ These policies restrict what APIs the site can access or modify the browser's de [[headers-clear-site-data]] == Clear Site Data -NOTE: See the relevant sections to see how to configure both <> and <> based applications. +[NOTE] +==== +See the relevant sections to see how to configure both <> and <> based applications. +==== https://www.w3.org/TR/clear-site-data/[Clear Site Data] is a mechanism by which any browser-side data (cookies, local storage, and the like) can be removed when an HTTP response contains this header: @@ -335,7 +389,10 @@ This is a nice clean-up action to perform on logout. [[headers-custom]] == Custom Headers -NOTE: See the relevant sections to see how to configure both <> based applications. +[NOTE] +==== +See the relevant sections to see how to configure both <> based applications. +==== Spring Security has mechanisms to make it convenient to add the more common security headers to your application. However, it also provides hooks to enable adding custom headers. diff --git a/docs/manual/src/docs/asciidoc/_includes/about/getting-spring-security.adoc b/docs/manual/src/docs/asciidoc/_includes/about/getting-spring-security.adoc index 464ee567dc7..489eed42534 100644 --- a/docs/manual/src/docs/asciidoc/_includes/about/getting-spring-security.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/about/getting-spring-security.adoc @@ -145,8 +145,11 @@ The easiest way to resolve this is to use the `spring-framework-bom` within the The preceding example ensures that all the transitive dependencies of Spring Security use the Spring {spring-core-version} modules. -NOTE: This approach uses Maven's "`bill of materials`" (BOM) concept and is only available in Maven 2.0.9+. +[NOTE] +==== +This approach uses Maven's "`bill of materials`" (BOM) concept and is only available in Maven 2.0.9+. For additional details about how dependencies are resolved, see https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html[Maven's Introduction to the Dependency Mechanism documentation]. +==== [[maven-repositories]] === Maven Repositories diff --git a/docs/manual/src/docs/asciidoc/_includes/about/modules.adoc b/docs/manual/src/docs/asciidoc/_includes/about/modules.adoc index fd0c274581c..99d836c420e 100644 --- a/docs/manual/src/docs/asciidoc/_includes/about/modules.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/about/modules.adoc @@ -277,7 +277,11 @@ This is the basis of the Spring Security integration. [[spring-security-openid]] == OpenID -- `spring-security-openid.jar` -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. + +[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. +==== This module contains OpenID web authentication support. It is used to authenticate users against an external OpenID server. diff --git a/docs/manual/src/docs/asciidoc/_includes/reactive/exploits/csrf.adoc b/docs/manual/src/docs/asciidoc/_includes/reactive/exploits/csrf.adoc index b0f80242204..69555a80bb1 100644 --- a/docs/manual/src/docs/asciidoc/_includes/reactive/exploits/csrf.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/reactive/exploits/csrf.adoc @@ -63,9 +63,12 @@ fun springSecurityFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain ----- ==== -NOTE: The preceding sample explicitly sets `cookieHttpOnly=false`. +[NOTE] +==== +The preceding sample explicitly sets `cookieHttpOnly=false`. This is necessary to let JavaScript (in this case, AngularJS) to read it. If you do not need the ability to read the cookie with JavaScript directly, we recommend to omitting `cookieHttpOnly=false` (by using `new CookieServerCsrfTokenRepository()` instead) to improve security. +==== [[webflux-csrf-configure-disable]] ==== Disable CSRF Protection @@ -344,7 +347,10 @@ For details, see the <> section. We have <> how protecting multipart requests (file uploads) from CSRF attacks causes a https://en.wikipedia.org/wiki/Chicken_or_the_egg[chicken and the egg] problem. This section discusses how to implement placing the CSRF token in the <> and <> within a WebFlux application. -NOTE: For more information about using multipart forms with Spring, see the https://docs.spring.io/spring/docs/5.2.x/spring-framework-reference/web-reactive.html#webflux-multipart[Multipart Data] section of the Spring reference. +[NOTE] +==== +For more information about using multipart forms with Spring, see the https://docs.spring.io/spring/docs/5.2.x/spring-framework-reference/web-reactive.html#webflux-multipart[Multipart Data] section of the Spring reference. +==== [[webflux-csrf-considerations-multipart-body]] ==== Place CSRF Token in the Body diff --git a/docs/manual/src/docs/asciidoc/_includes/reactive/method.adoc b/docs/manual/src/docs/asciidoc/_includes/reactive/method.adoc index 5f6b135c5d4..9e54fdadd6a 100644 --- a/docs/manual/src/docs/asciidoc/_includes/reactive/method.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/reactive/method.adoc @@ -4,8 +4,11 @@ Spring Security supports method security by using https://projectreactor.io/docs/core/release/reference/#context[Reactor's Context], which is set up by `ReactiveSecurityContextHolder`. The following example shows how to retrieve the currently logged in user's message: -NOTE: For this example to work, the return type of the method must be a `org.reactivestreams.Publisher` (that is, a `Mono` or a `Flux`) or the function must be a Kotlin coroutine function. +[NOTE] +==== +For this example to work, the return type of the method must be a `org.reactivestreams.Publisher` (that is, a `Mono` or a `Flux`) or the function must be a Kotlin coroutine function. This is necessary to integrate with Reactor's `Context`. +==== ==== .Java diff --git a/docs/manual/src/docs/asciidoc/_includes/reactive/oauth2/login.adoc b/docs/manual/src/docs/asciidoc/_includes/reactive/oauth2/login.adoc index 71c262889d8..49a89b9cd26 100644 --- a/docs/manual/src/docs/asciidoc/_includes/reactive/oauth2/login.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/reactive/oauth2/login.adoc @@ -5,7 +5,10 @@ The OAuth 2.0 Login feature provides an application with the ability to have use GitHub) or OpenID Connect 1.0 Provider (such as Google). OAuth 2.0 Login implements the "Login with Google" or "Login with GitHub" use cases. -NOTE: OAuth 2.0 Login is implemented by using the *Authorization Code Grant*, as specified in the https://tools.ietf.org/html/rfc6749#section-4.1[OAuth 2.0 Authorization Framework] and https://openid.net/specs/openid-connect-core-1_0.html#CodeFlowAuth[OpenID Connect Core 1.0]. +[NOTE] +==== +OAuth 2.0 Login is implemented by using the *Authorization Code Grant*, as specified in the https://tools.ietf.org/html/rfc6749#section-4.1[OAuth 2.0 Authorization Framework] and https://openid.net/specs/openid-connect-core-1_0.html#CodeFlowAuth[OpenID Connect Core 1.0]. +==== [[webflux-oauth2-login-sample]] == Spring Boot 2.0 Sample @@ -25,7 +28,10 @@ This section shows how to configure the {gh-samples-url}/boot/oauth2login-webflu To use Google's OAuth 2.0 authentication system for login, you must set up a project in the Google API Console to obtain OAuth 2.0 credentials. -NOTE: https://developers.google.com/identity/protocols/OpenIDConnect[Google's OAuth 2.0 implementation] for authentication conforms to the https://openid.net/connect/[OpenID Connect 1.0] specification and is https://openid.net/certification/[OpenID Certified]. +[NOTE] +==== +https://developers.google.com/identity/protocols/OpenIDConnect[Google's OAuth 2.0 implementation] for authentication conforms to the https://openid.net/connect/[OpenID Connect 1.0] specification and is https://openid.net/certification/[OpenID Certified]. +==== Follow the instructions on the https://developers.google.com/identity/protocols/OpenIDConnect[OpenID Connect] page, starting in the "`Setting up OAuth 2.0`" section. @@ -38,12 +44,19 @@ The redirect URI is the path in the application that the end-user's user-agent i In the "`Set a redirect URI`" sub-section, ensure that the *Authorized redirect URIs* field is set to `http://localhost:8080/login/oauth2/code/google`. -TIP: The default redirect URI template is `+{baseUrl}/login/oauth2/code/{registrationId}+`. +[TIP] +==== +The default redirect URI template is `+{baseUrl}/login/oauth2/code/{registrationId}+`. The *_registrationId_* is a unique identifier for the <>. For our example, the `registrationId` is `google`. +==== -IMPORTANT: If the OAuth Client runs behind a proxy server, we recommend checking the <> to ensure the application is correctly configured. +[IMPORTANT] +==== +If the OAuth Client runs behind a proxy server, we recommend checking the <> to ensure the application is correctly configured. Also, see the supported <> for the `redirect-uri`. +==== + [[webflux-oauth2-login-sample-config]] === Configure `application.yml` @@ -111,7 +124,10 @@ spring: The `issuer-uri` instructs Spring Security to query, in series, the following endpoints to discover the configuration: `https://idp.example.com/auth/realms/demo/.well-known/openid-configuration`, `https://idp.example.com/.well-known/openid-configuration/auth/realms/demo`, or `https://idp.example.com/.well-known/oauth-authorization-server/auth/realms/demo`. -NOTE: Spring Security queries the endpoints one at a time, stopping at the first that gives a 200 response. +[NOTE] +==== +Spring Security queries the endpoints one at a time, stopping at the first that gives a 200 response. +==== The `client-id` and `client-secret` are linked to the provider because `keycloak` is used for both the provider and the registration. diff --git a/docs/manual/src/docs/asciidoc/_includes/reactive/oauth2/resource-server.adoc b/docs/manual/src/docs/asciidoc/_includes/reactive/oauth2/resource-server.adoc index b16fcbe0106..cc429e47658 100644 --- a/docs/manual/src/docs/asciidoc/_includes/reactive/oauth2/resource-server.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/reactive/oauth2/resource-server.adoc @@ -9,7 +9,10 @@ Spring Security supports protecting endpoints by offering two forms of OAuth 2.0 This is handy in circumstances where an application has delegated its authority management to an https://tools.ietf.org/html/rfc6749[authorization server] (for example, Okta or Ping Identity). Resource serves can consult this authorization server to authorize requests. -NOTE: A complete working example for {gh-samples-url}/boot/oauth2resourceserver-webflux[JWT] is available in the {gh-samples-url}[Spring Security repository]. +[NOTE] +==== +A complete working example for {gh-samples-url}/boot/oauth2resourceserver-webflux[JWT] is available in the {gh-samples-url}[Spring Security repository]. +==== [[webflux-oauth2resourceserver-jwt-minimaldependencies]] == Minimal Dependencies for JWT @@ -42,8 +45,11 @@ spring: Where `https://idp.example.com/issuer` is the value contained in the `iss` claim for JWT tokens that the authorization server issues. This resource server uses this property to further self-configure, discover the authorization server's public keys, and subsequently validate incoming JWTs. -NOTE: To use the `issuer-uri` property, it must also be true that one of `https://idp.example.com/issuer/.well-known/openid-configuration`, `https://idp.example.com/.well-known/openid-configuration/issuer`, or `https://idp.example.com/.well-known/oauth-authorization-server/issuer` is a supported endpoint for the authorization server. +[NOTE] +==== +To use the `issuer-uri` property, it must also be true that one of `https://idp.example.com/issuer/.well-known/openid-configuration`, `https://idp.example.com/.well-known/openid-configuration/issuer`, or `https://idp.example.com/.well-known/oauth-authorization-server/issuer` is a supported endpoint for the authorization server. This endpoint is referred to as a https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfig[Provider Configuration] endpoint or a https://tools.ietf.org/html/rfc8414#section-3[Authorization Server Metadata] endpoint. +==== === Startup Expectations @@ -57,7 +63,10 @@ It achieves this through a deterministic startup process: A consequence of this process is that the authorization server must be receiving requests in order for Resource Server to successfully start up. -NOTE: If the authorization server is down when Resource Server queries it (given appropriate timeouts), then startup fails. +[NOTE] +==== +If the authorization server is down when Resource Server queries it (given appropriate timeouts), then startup fails. +==== === Runtime Expectations @@ -79,7 +88,10 @@ Given a well-formed JWT, Resource Server: 2. Validates the JWTs `exp` and `nbf` timestamps and the JWTs `iss` claim. 3. Maps each scope to an authority with the prefix `SCOPE_`. -NOTE: As the authorization server makes available new keys, Spring Security automatically rotates the keys used to validate the JWT tokens. +[NOTE] +==== +As the authorization server makes available new keys, Spring Security automatically rotates the keys used to validate the JWT tokens. +==== By default, the resulting `Authentication#getPrincipal` is a Spring Security `Jwt` object, and `Authentication#getName` maps to the JWT's `sub` property, if one is present. @@ -106,12 +118,18 @@ spring: ---- ==== -NOTE: The JWK Set uri is not standardized, but you can typically find it in the authorization server's documentation. +[NOTE] +==== +The JWK Set uri is not standardized, but you can typically find it in the authorization server's documentation. +==== Consequently, Resource Server does not ping the authorization server at startup. We still specify the `issuer-uri` so that Resource Server still validates the `iss` claim on incoming JWTs. -NOTE: You can supply this property directly on the <>. +[NOTE] +==== +You can supply this property directly on the <>. +==== [[webflux-oauth2resourceserver-jwt-sansboot]] === Overriding or Replacing Boot Auto Configuration @@ -221,8 +239,11 @@ fun jwtDecoder(): ReactiveJwtDecoder { ---- ==== -NOTE: Calling `{security-api-url}org/springframework/security/oauth2/jwt/ReactiveJwtDecoders.html#fromIssuerLocation-java.lang.String-[ReactiveJwtDecoders#fromIssuerLocation]` invokes the Provider Configuration or Authorization Server Metadata endpoint to derive the JWK Set URI. +[NOTE] +==== +Calling `{security-api-url}org/springframework/security/oauth2/jwt/ReactiveJwtDecoders.html#fromIssuerLocation-java.lang.String-[ReactiveJwtDecoders#fromIssuerLocation]` invokes the Provider Configuration or Authorization Server Metadata endpoint to derive the JWK Set URI. If the application does not expose a `ReactiveJwtDecoder` bean, Spring Boot exposes the above default one. +==== Its configuration can be overridden by using `jwkSetUri()` or replaced by using `decoder()`. @@ -939,8 +960,11 @@ Where `https://idp.example.com/introspect` is the introspection endpoint hosted Resource Server uses these properties to further self-configure and subsequently validate incoming JWTs. -NOTE: When using introspection, the authorization server's word is the law. +[NOTE] +==== +When using introspection, the authorization server's word is the law. If the authorization server responses that the token is valid, it is. +==== ==== Startup Expectations @@ -1796,8 +1820,11 @@ return http { In this case, you construct `JwtIssuerReactiveAuthenticationManagerResolver` with a strategy for obtaining the `ReactiveAuthenticationManager` given to the issuer. This approach lets us add and remove elements from the repository (shown as a `Map` in the preceding snippet) at runtime. -NOTE: It would be unsafe to simply take any issuer and construct an `ReactiveAuthenticationManager` from it. +[NOTE] +==== +It would be unsafe to simply take any issuer and construct an `ReactiveAuthenticationManager` from it. The issuer should be one that the code can verify from a trusted source, such as an allowed list of issuers. +==== [[webflux-oauth2resourceserver-bearertoken-resolver]] == Bearer Token Resolution @@ -1914,5 +1941,8 @@ rest.get() In this case, the filter falls back and forwards the request onto the rest of the web filter chain. -NOTE: Unlike the https://docs.spring.io/spring-security/site/docs/current-SNAPSHOT/api/org/springframework/security/oauth2/client/web/reactive/function/client/ServerOAuth2AuthorizedClientExchangeFilterFunction.html[OAuth 2.0 Client filter function], this filter function makes no attempt to renew the token, should it be expired. +[NOTE] +==== +Unlike the https://docs.spring.io/spring-security/site/docs/current-SNAPSHOT/api/org/springframework/security/oauth2/client/web/reactive/function/client/ServerOAuth2AuthorizedClientExchangeFilterFunction.html[OAuth 2.0 Client filter function], this filter function makes no attempt to renew the token, should it be expired. To obtain this level of support, use the OAuth 2.0 Client filter. +==== diff --git a/docs/manual/src/docs/asciidoc/_includes/reactive/registered-oauth2-authorized-client.adoc b/docs/manual/src/docs/asciidoc/_includes/reactive/registered-oauth2-authorized-client.adoc index ce986905603..c858b666347 100644 --- a/docs/manual/src/docs/asciidoc/_includes/reactive/registered-oauth2-authorized-client.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/reactive/registered-oauth2-authorized-client.adoc @@ -3,7 +3,10 @@ Spring Security allows resolving an access token by using `@RegisteredOAuth2AuthorizedClient`. -NOTE: You can find a working example in the {gh-samples-url}/boot/oauth2webclient-webflux[OAuth 2.0 WebClient WebFlux sample]. +[NOTE] +==== +You can find a working example in the {gh-samples-url}/boot/oauth2webclient-webflux[OAuth 2.0 WebClient WebFlux sample]. +==== After configuring Spring Security for <> or as an <>, you can resolve an `OAuth2AuthorizedClient` by using the following: diff --git a/docs/manual/src/docs/asciidoc/_includes/reactive/rsocket.adoc b/docs/manual/src/docs/asciidoc/_includes/reactive/rsocket.adoc index d3b7eac685d..d7dccd0a692 100644 --- a/docs/manual/src/docs/asciidoc/_includes/reactive/rsocket.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/reactive/rsocket.adoc @@ -82,8 +82,11 @@ This means that individual users can make requests but not make additional conne Spring Security has support for the https://github.com/rsocket/rsocket/blob/5920ed374d008abb712cb1fd7c9d91778b2f4a68/Extensions/Security/Simple.md[Simple Authentication Metadata Extension]. -NOTE: Basic Authentication evolved into Simple Authentication and is only supported for backward compatibility. +[NOTE] +==== +Basic Authentication evolved into Simple Authentication and is only supported for backward compatibility. See `RSocketSecurity.basicAuthentication(Customizer)` for setting it up. +==== The RSocket receiver can decode the credentials by using `AuthenticationPayloadExchangeConverter`, which is automatically setup by using the `simpleAuthentication` portion of the DSL. The following example shows an explicit configuration: diff --git a/docs/manual/src/docs/asciidoc/_includes/reactive/webclient.adoc b/docs/manual/src/docs/asciidoc/_includes/reactive/webclient.adoc index 2ea6b412d2b..0f73302b13d 100644 --- a/docs/manual/src/docs/asciidoc/_includes/reactive/webclient.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/reactive/webclient.adoc @@ -1,8 +1,11 @@ [[webclient]] = WebClient -NOTE: The documentation in this section is for use within Reactive environments. +[NOTE] +==== +The documentation in this section is for use within Reactive environments. For Servlet environments, see <>. +==== Spring Framework has built-in support for setting a Bearer token: diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/appendix/faq.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/appendix/faq.adoc index e3481e3ab0f..d05a263c437 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/appendix/faq.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/appendix/faq.adoc @@ -259,10 +259,13 @@ This happens because sessions created under HTTPS, for which the session cookie However, Spring Security's https://docs.spring.io/spring-security/site/docs/3.1.x/reference/springsecurity-single.html#ns-session-fixation[Session Fixation Protection] can interfere with this because it results in a new session ID cookie being sent back to the user's browser, usually with the secure flag. To get around this, you can disable session fixation protection. However, in newer Servlet containers, you can also configure session cookies to never use the secure flag. -IMPORTANT: Switching between HTTP and HTTPS is not a good idea in general, as any application that uses HTTP at all is vulnerable to man-in-the-middle attacks. +[IMPORTANT] +==== +Switching between HTTP and HTTPS is not a good idea in general, as any application that uses HTTP at all is vulnerable to man-in-the-middle attacks. To be truly secure, the user should begin accessing your site in HTTPS and continue using it until they log out. Even clicking on an HTTPS link from a page accessed over HTTP is potentially risky. If you need more convincing, check out a tool such as https://www.thoughtcrime.org/software/sslstrip/[sslstrip]. +==== ==== I am not switching between HTTP and HTTPS, but my session is still lost. What happened? diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/appendix/namespace.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/appendix/namespace.adoc index 5281530d23c..ee660da68c8 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/appendix/namespace.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/appendix/namespace.adoc @@ -554,7 +554,11 @@ The policy value to write for the `Permissions-Policy` header [[nsa-xss-protection]] ==== The `` adds the https://blogs.msdn.com/b/ie/archive/2008/07/02/ie8-security-part-iv-the-xss-filter.aspx[X-XSS-Protection header] to the response, to assist in protecting against https://en.wikipedia.org/wiki/Cross-site_scripting#Non-Persistent[reflected / Type-1 Cross-Site Scripting (XSS)] attacks. -NOTE: Full protection against XSS attacks is not possible. + +[NOTE] +==== +Full protection against XSS attacks is not possible. +==== [[nsa-xss-protection-attributes]] @@ -803,8 +807,11 @@ This always takes precedence over other namespace-created entry points. If no attributes are supplied, a login page is generated automatically at the `/login` URL. You can customize this behavior by setting the <` Attributes>>. -NOTE: This feature is provided for convenience and is not intended for production (where a view technology should have been chosen and can be used to render a customized login page). +[NOTE] +==== +This feature is provided for convenience and is not intended for production (where a view technology should have been chosen and can be used to render a customized login page). The class `DefaultLoginPageGeneratingFilter` class is responsible for rendering the login page and provide login forms for both normal form login and OpenID if required. +==== [[nsa-form-login-parents]] @@ -1370,7 +1377,10 @@ If this attribute is present on any `` element, a `ChannelProcess If a `` configuration is added, it is used by the `SecureChannelProcessor` and `InsecureChannelProcessor` beans to determine the ports used for redirecting to HTTP and HTTPS. -NOTE: This property is invalid for <> +[NOTE] +==== +This property is invalid for <> +==== [[nsa-intercept-url-servlet-path]] `servlet-path`:: @@ -1380,7 +1390,10 @@ In addition, the value is only required in the following two use cases: * Two or more `HttpServlet` instances that have mappings starting with `/` and are different are registered in the `ServletContext`. * The pattern starts with the same value of a registered `HttpServlet` path, excluding the default (root) `HttpServlet` `/`. -NOTE: This property is invalid for <> +[NOTE] +==== +This property is invalid for <> +==== [[nsa-jee]] @@ -2316,8 +2329,11 @@ The `` element has the following attributes: [[nsa-password-encoder-hash]] `hash`:: Defines the hashing algorithm for user passwords. -IMPORTANT: We recommend strongly against using MD4, as it is a very weak hashing algorithm. +[IMPORTANT] +==== +We recommend strongly against using MD4, as it is a very weak hashing algorithm. +==== [[nsa-password-encoder-ref]] `ref`:: @@ -2473,9 +2489,13 @@ mode:: You can set this attribute to `aspectj` to specify that AspectJ should be used instead of the default Spring AOP. You must weave secured methods with the `AnnotationSecurityAspect` from the `spring-security-aspects` module. + -NOTE: AspectJ follows Java's rule that annotations on interfaces are not inherited. +[NOTE] +==== +AspectJ follows Java's rule that annotations on interfaces are not inherited. This means that methods that define the Security annotations on the interface are not secured. Instead, you must place the Security annotation on the class when you use AspectJ. +==== + [[nsa-global-method-security-order]] `order`:: diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/architecture/exception-translation-filter.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/architecture/exception-translation-filter.adoc index f3c97ed7de0..dfe51ef5f6f 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/architecture/exception-translation-filter.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/architecture/exception-translation-filter.adoc @@ -25,7 +25,10 @@ For example, it might redirect to a log in page or send a `WWW-Authenticate` hea The `AccessDeniedHandler` is invoked to handle access denied. // FIXME: link to AccessDeniedHandler -NOTE: If the application does not throw an `AccessDeniedException` or an `AuthenticationException`, `ExceptionTranslationFilter` does not do anything. +[NOTE] +==== +If the application does not throw an `AccessDeniedException` or an `AuthenticationException`, `ExceptionTranslationFilter` does not do anything. +==== The pseudocode for `ExceptionTranslationFilter` looks something like this: diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/anonymous.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/anonymous.adoc index 16306a34022..428d918d7c5 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/anonymous.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/anonymous.adoc @@ -48,11 +48,14 @@ The filter and authentication provider is defined as follows: The `key` is shared between the filter and authentication provider so that tokens created by the former are accepted by the latter -NOTE: The use of the `key` property should not be regarded as providing any real security here. +[NOTE] +==== +The use of the `key` property should not be regarded as providing any real security here. It is merely a book-keeping exercise. If you share a `ProviderManager` that contains an `AnonymousAuthenticationProvider` in a scenario where it is possible for an authenticating client to construct the `Authentication` object (such as with RMI invocations), then a malicious client could submit an `AnonymousAuthenticationToken` that it had created itself (with the chosen username and authority list). If the `key` is guessable or can be found out, the token would be accepted by the anonymous provider. This is not a problem with normal usage. However, if you use RMI, you should use a customized `ProviderManager` that omits the anonymous provider rather than sharing the one you use for your HTTP authentication mechanisms. +==== The `userAttribute` is expressed in the form of `usernameInTheAuthenticationToken,grantedAuthority[,grantedAuthority]`. The same syntax is used after the equals sign for the `userMap` property of `InMemoryDaoImpl`. diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/cas.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/cas.adoc index 310044eca6a..bd4abfcac55 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/cas.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/cas.adoc @@ -15,7 +15,10 @@ While the CAS web site contains documents that detail the architecture of CAS, w Spring Security 3.x (and later) supports CAS 3 (and later). At the time of writing, the CAS server is at version 6.3.3. -NOTE: This section was written about CAS version 3.4, but the material is still current. +[NOTE] +==== +This section was written about CAS version 3.4, but the material is still current. +==== Somewhere in your enterprise, you need to setup a CAS server. The CAS server runs from a standard WAR file. diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/logout.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/logout.adoc index 1b5a3f1893b..8c2bf19b670 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/logout.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/logout.adoc @@ -73,8 +73,11 @@ By default, `SecurityContextLogoutHandler` is added as the last `LogoutHandler`. <7> Lets specifying the names of cookies be removed on logout success. This is a shortcut for adding a `CookieClearingLogoutHandler` explicitly. -NOTE: Logouts can also be configured by using the XML Namespace notation. +[NOTE] +==== +Logouts can also be configured by using the XML Namespace notation. See the documentation for the <> in the Spring Security XML Namespace section for further details. +==== Generally, to customize logout functionality, you can add `{security-api-url}org/springframework/security/web/authentication/logout/LogoutHandler.html[LogoutHandler]` diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/openid.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/openid.adoc index c615550bcff..de3ed417ee0 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/openid.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/openid.adoc @@ -1,7 +1,10 @@ [[servlet-openid]] == OpenID Support -NOTE: The OpenID 1.0 and 2.0 protocols have been deprecated. You should migrate to OpenID Connect, which is supported by `spring-security-oauth2`. +[NOTE] +==== +The OpenID 1.0 and 2.0 protocols have been deprecated. You should migrate to OpenID Connect, which is supported by `spring-security-oauth2`. +==== The namespace supports https://openid.net/[OpenID] login either instead of or in addition to normal form-based login, with a simple change: diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/preauth.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/preauth.adoc index ae6a0799129..b62b627d785 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/preauth.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/preauth.adoc @@ -100,8 +100,12 @@ This mechanism is supported by the `RequestHeaderAuthenticationFilter` class, wh It defaults to using a name of `SM_USER` as the header name. See the Javadoc for more details. -TIP: When using a system like this, the framework performs no authentication checks at all, and it is _extremely_ important that the external system is configured properly and protects all access to the application. +[TIP] +==== +When using a system like this, the framework performs no authentication checks at all, and it is _extremely_ important that the external system is configured properly and protects all access to the application. If an attacker is able to forge the headers in their original request without this being detected, they could potentially choose any username they wished. +==== + ===== Siteminder Example Configuration The following example shows a typical configuration that uses this filter: diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/session-management.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/session-management.adoc index 0916bd138f1..fe251a4aecd 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/session-management.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/session-management.adoc @@ -127,8 +127,11 @@ See the <> chapter for additional information. === 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 -NOTE: Authentication by mechanisms that perform a redirect after authenticating (such as form-login) are not detected by `SessionManagementFilter`, as the filter is not invoked during the authenticating request. +[NOTE] +==== +Authentication by mechanisms that perform a redirect after authenticating (such as form-login) are not detected by `SessionManagementFilter`, as the filter is not invoked during the authenticating request. Session-management functionality has to be handled separately in these cases. +==== If the repository contains a security context, the filter does nothing. If it does not and the thread-local `SecurityContext` contains a (non-anonymous) `Authentication` object, the filter assumes they have been authenticated by a previous filter in the stack. @@ -179,10 +182,13 @@ Sometimes, though, you need to customize things. The implementation uses a specialized version of `SessionAuthenticationStrategy`, called `ConcurrentSessionControlAuthenticationStrategy`. -NOTE: Previously, the concurrent authentication check was made by the `ProviderManager`, which could be injected with a `ConcurrentSessionController`. +[NOTE] +==== +Previously, the concurrent authentication check was made by the `ProviderManager`, which could be injected with a `ConcurrentSessionController`. The latter would check if the user was attempting to exceed the number of permitted sessions. However, this approach required that an HTTP session be created in advance, which is undesirable. In Spring Security 3 and later, the user is first authenticated by the `AuthenticationManager` and once they are successfully authenticated, a session is created and the check is made whether they are allowed to have another session open. +==== To use concurrent session support, you need to add the following to `web.xml`: diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/digest.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/digest.adoc index 565503a29fb..293b339dd91 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/digest.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/digest.adoc @@ -3,10 +3,13 @@ This section provides details on how Spring Security provides support for https://tools.ietf.org/html/rfc2617[Digest Authentication], which is provided `DigestAuthenticationFilter`. -WARNING: You should not use Digest Authentication in modern applications, because it is not considered to be secure. +[WARNING] +==== +You should not use Digest Authentication in modern applications, because it is not considered to be secure. The most obvious problem is that you must store your passwords in plaintext or an encrypted or MD5 format. All of these storage formats are considered insecure. Instead, you should store credentials by using a one way adaptive password hash (bCrypt, PBKDF2, SCrypt, and others), which is not supported by Digest Authentication. +==== Digest Authentication tries to solve many of the weaknesses of <>, specifically by ensuring credentials are never sent in clear text across the wire. Many https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Digest#Browser_compatibility[browsers support Digest Authentication]. diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/jdbc.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/jdbc.adoc index 740c8b4de73..227f027d809 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/jdbc.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/jdbc.adoc @@ -23,7 +23,10 @@ You need to adjust the schema to match any customizations to the queries and the `JdbcDaoImpl` requires tables to load the password, account status (enabled or disabled) and a list of authorities (roles) for the user. -NOTE: The default schema is also exposed as a classpath resource named `org/springframework/security/core/userdetails/jdbc/users.ddl`. +[NOTE] +==== +The default schema is also exposed as a classpath resource named `org/springframework/security/core/userdetails/jdbc/users.ddl`. +==== .Default User Schema ==== diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/ldap.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/ldap.adoc index f1c32667e26..38ae5a784b0 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/ldap.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/ldap.adoc @@ -155,9 +155,12 @@ fun ldapContainer(): UnboundIdContainer { [[servlet-authentication-ldap-apacheds]] === Embedded ApacheDS Server -NOTE: Spring Security uses ApacheDS 1.x, which is no longer maintained. +[NOTE] +==== +Spring Security uses ApacheDS 1.x, which is no longer maintained. Unfortunately, ApacheDS 2.x has only released milestone versions with no stable release. Once a stable release of ApacheDS 2.x is available, we will consider updating. +==== If you wish to use https://directory.apache.org/apacheds/[Apache DS], specify the following dependencies: @@ -543,8 +546,11 @@ To make this easier, Spring Security has an authentication provider, which is cu Configuring `ActiveDirectoryLdapAuthenticationProvider` is quite straightforward. You need only supply the domain name and an LDAP URL that supplies the address of the server. -NOTE: It is also possible to obtain the server's IP address byusing a DNS lookup. +[NOTE] +==== +It is also possible to obtain the server's IP address byusing a DNS lookup. This is not currently supported, but hopefully will be in a future version. +==== The following example configures Active Directory: diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/user-details-service.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/user-details-service.adoc index f630021ee5c..1ed13105bdc 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/user-details-service.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/user-details-service.adoc @@ -7,7 +7,10 @@ Spring Security provides <> and <>. +[NOTE] +==== +For earlier versions, please read about similar support with <>. +==== For example, the following would enable Spring Security's `@PreAuthorize` annotation: @@ -772,11 +775,17 @@ public Account post(Account account, double amount); Expression-based annotations are a good choice if you need to define simple rules that go beyond checking the role names against the user's list of authorities. -NOTE: The annotated methods will only be secured for instances which are defined as Spring beans (in the same application context in which method-security is enabled). +[NOTE] +==== +The annotated methods will only be secured for instances which are defined as Spring beans (in the same application context in which method-security is enabled). If you want to secure instances which are not created by Spring (using the `new` operator, for example) then you need to use AspectJ. +==== -NOTE: You can enable more than one type of annotation in the same application, but only one type should be used for any interface or class as the behaviour will not be well-defined otherwise. +[NOTE] +==== +You can enable more than one type of annotation in the same application, but only one type should be used for any interface or class as the behaviour will not be well-defined otherwise. If two annotations are found which apply to a particular method, then only one of them will be applied. +==== [[ns-protect-pointcut]] === Adding Security Pointcuts by using protect-pointcut diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/crypto/index.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/crypto/index.adoc index e5cd9f81e55..c2c020ab460 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/crypto/index.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/crypto/index.adoc @@ -14,7 +14,11 @@ This class lets you create {security-api-url}org/springframework/security/crypto You can also construct {security-api-url}org/springframework/security/crypto/encrypt/TextEncryptor.html[TextEncryptor] instances to encrypt text strings. Encryptors are thread-safe. -NOTE: Both `BytesEncryptor` and `TextEncryptor` are interfaces. `BytesEncryptor` has multiple implementations. +[NOTE] +==== +Both `BytesEncryptor` and `TextEncryptor` are interfaces. `BytesEncryptor` has multiple implementations. +==== + [[spring-security-crypto-encryption-bytes]] === BytesEncryptor diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/exploits/csrf.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/exploits/csrf.adoc index ca941c692f6..2607659e886 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/exploits/csrf.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/exploits/csrf.adoc @@ -48,9 +48,12 @@ You can configure `CookieCsrfTokenRepository` in XML byusing the following: ---- ==== -NOTE: The sample explicitly sets `cookieHttpOnly=false`. +[NOTE] +==== +The sample explicitly sets `cookieHttpOnly=false`. This is necessary to allow JavaScript (such as AngularJS) to read it. If you do not need the ability to read the cookie with JavaScript directly, we recommend omitting `cookieHttpOnly=false` to improve security. +==== You can configure `CookieCsrfTokenRepository` in Java or Kotlin configuration by using: @@ -90,9 +93,12 @@ class SecurityConfig : WebSecurityConfigurerAdapter() { ---- ==== -NOTE: The sample explicitly sets `cookieHttpOnly=false`. +[NOTE] +==== +The sample explicitly sets `cookieHttpOnly=false`. This is necessary to let JavaScript (such as AngularJS) read it. If you do not need the ability to read the cookie with JavaScript directly, we recommend omitting `cookieHttpOnly=false` (by using `new CookieCsrfTokenRepository()` instead) to improve security. +==== [[servlet-csrf-configure-disable]] ==== Disable CSRF Protection @@ -375,7 +381,10 @@ For an example of how to customize the `AccessDeniedHandler`, see the provided l We have <> how protecting multipart requests (file uploads) from CSRF attacks causes a https://en.wikipedia.org/wiki/Chicken_or_the_egg[chicken and the egg] problem. This section discusses how to implement placing the CSRF token in the <> and <> within a servlet application. -NOTE: You can find more information about using multipart forms with Spring in the https://docs.spring.io/spring/docs/5.2.x/spring-framework-reference/web.html#mvc-multipart[1.1.11. Multipart Resolver] section of the Spring reference and the https://docs.spring.io/spring/docs/5.2.x/javadoc-api/org/springframework/web/multipart/support/MultipartFilter.html[`MultipartFilter` javadoc]. +[NOTE] +==== +You can find more information about using multipart forms with Spring in the https://docs.spring.io/spring/docs/5.2.x/spring-framework-reference/web.html#mvc-multipart[1.1.11. Multipart Resolver] section of the Spring reference and the https://docs.spring.io/spring/docs/5.2.x/javadoc-api/org/springframework/web/multipart/support/MultipartFilter.html[`MultipartFilter` javadoc]. +==== [[servlet-csrf-considerations-multipart-body]] ==== Place CSRF Token in the Body diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/exploits/firewall.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/exploits/firewall.adoc index 618368eef42..b086b73b937 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/exploits/firewall.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/exploits/firewall.adoc @@ -120,10 +120,13 @@ fun httpFirewall(): StrictHttpFirewall { ---- ==== -TIP: If you use `new MockHttpServletRequest()`, it currently creates an HTTP method as an empty String (`""`). +[TIP] +==== +If you use `new MockHttpServletRequest()`, it currently creates an HTTP method as an empty String (`""`). This is an invalid HTTP method and is rejected by Spring Security. You can resolve this by replacing it with `new MockHttpServletRequest("GET", "")`. See https://jira.spring.io/browse/SPR-16851[SPR_16851] for an issue that requests improving this. +==== If you must allow any HTTP method (not recommended), you can use `StrictHttpFirewall.setUnsafeAllowAnyHttpMethod(true)`. Doing so entirely disables validation of the HTTP method. @@ -139,7 +142,10 @@ This requirement can be relaxed or adjusted as necessary by using the following * `StrictHttpFirewall#setAllowedHeaderValues(Predicate)` * `StrictHttpFirewall#setAllowedParameterNames(Predicate)` -NOTE: Parameter values can be also controlled with `setAllowedParameterValues(Predicate)`. +[NOTE] +==== +Parameter values can be also controlled with `setAllowedParameterValues(Predicate)`. +==== For example, to switch off this check, you can wire your `StrictHttpFirewall` with `Predicate` instances that always return `true`: diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/hello/index.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/hello/index.adoc index 98bd31f5c4b..04c03084888 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/hello/index.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/hello/index.adoc @@ -3,8 +3,11 @@ This section covers the minimum setup for how to use Spring Security with Spring Boot. -NOTE: The completed application can be found at {gh-samples-url}/boot/helloworld[samples/boot/helloworld] +[NOTE] +==== +The completed application can be found at {gh-samples-url}/boot/helloworld[samples/boot/helloworld] For your convenience, you can download https://start.spring.io/starter.zip?type=maven-project&language=java&packaging=jar&jvmVersion=1.8&groupId=example&artifactId=hello-security&name=hello-security&description=Hello%20Security&packageName=example.hello-security&dependencies=web,security[a minimal Spring Boot + Spring Security application]. +==== [[servlet-hello-dependencies]] == Updating Dependencies diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/jsp-taglibs.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/jsp-taglibs.adoc index b0c1e3a5d9e..c1ba0748d91 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/jsp-taglibs.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/jsp-taglibs.adoc @@ -18,7 +18,10 @@ To use any of the tags, you must have the security taglib declared in your JSP: 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. -NOTE: The legacy options from Spring Security 2.0 are also supported, but discouraged. +[NOTE] +==== +The legacy options from Spring Security 2.0 are also supported, but discouraged. +==== The first approach uses a <>, which is specified in the `access` attribute of the tag. The expression evaluation is delegated to the `SecurityExpressionHandler` defined in the application context (you should have web expressions enabled in your `` namespace configuration to make sure this service is available). @@ -100,8 +103,11 @@ It checks a comma-separated list of required permissions for a specified domain If the current user has all of those permissions, the tag body is evaluated. If they do not, it is skipped. -CAUTION: In general this tag should be considered deprecated. -Instead use the <>. +[CAUTION] +==== +In general, this tag should be considered deprecated. +Instead, use the <>. +==== The following listing shows an example: diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/mvc.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/mvc.adoc index 020e209adff..1a12acb2698 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/mvc.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/mvc.adoc @@ -7,13 +7,19 @@ This section covers the integration in further detail. [[mvc-enablewebmvcsecurity]] === @EnableWebMvcSecurity -NOTE: As of Spring Security 4.0, `@EnableWebMvcSecurity` is deprecated. +[NOTE] +==== +As of Spring Security 4.0, `@EnableWebMvcSecurity` is deprecated. The replacement is `@EnableWebSecurity`, which adds the Spring MVC features, based upon the classpath. +==== To enable Spring Security integration with Spring MVC, add the `@EnableWebSecurity` annotation to your configuration. -NOTE: Spring Security provides the configuration by using Spring MVC's https://docs.spring.io/spring/docs/5.0.0.RELEASE/spring-framework-reference/web.html#mvc-config-customize[`WebMvcConfigurer`]. +[NOTE] +==== +Spring Security provides the configuration by using Spring MVC's https://docs.spring.io/spring/docs/5.0.0.RELEASE/spring-framework-reference/web.html#mvc-config-customize[`WebMvcConfigurer`]. This means that, if you use more advanced options, such as integrating with `WebMvcConfigurationSupport` directly, you need to manually provide the Spring Security configuration. +==== [[mvc-requestmatcher]] === MvcRequestMatcher @@ -273,8 +279,11 @@ public ModelAndView updateName(@AuthenticationPrincipal(expression = "@jpaEntity We can further remove our dependency on Spring Security by making `@AuthenticationPrincipal` a meta-annotation on our own annotation. The next example demonstrates how we could do so on an annotation named `@CurrentUser`. -NOTE: To remove the dependency on Spring Security, it is the consuming application that would create `@CurrentUser`. +[NOTE] +==== +To remove the dependency on Spring Security, it is the consuming application that would create `@CurrentUser`. This step is not strictly required but assists in isolating your dependency to Spring Security to a more central location. +==== ==== [source,java] @@ -325,8 +334,12 @@ return new Callable() { ==== .Associating SecurityContext to Callable's -NOTE: More technically speaking, Spring Security integrates with `WebAsyncManager`. + +[NOTE] +==== +More technically speaking, Spring Security integrates with `WebAsyncManager`. The `SecurityContext` that is used to process the `Callable` is the `SecurityContext` that exists on the `SecurityContextHolder` when `startCallableProcessing` is invoked. +==== There is no automatic integration with a `DeferredResult` that is returned by controllers. This is because `DeferredResult` is processed by the users and, thus, there is no way of automatically integrating with it. diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/servlet-api.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/servlet-api.adoc index c2a4f0a47e9..e34e8714fe4 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/servlet-api.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/integrations/servlet-api.adoc @@ -37,8 +37,11 @@ String lastName = userDetails.getLastName(); ---- ==== -NOTE: It is typically bad practice to perform logic throughout your application. +[NOTE] +==== +It is typically bad practice to perform logic throughout your application. Instead, you should centralize it to reduce any coupling of Spring Security and the Servlet API. +==== [[servletapi-user-in-role]] ==== HttpServletRequest.isUserInRole(String) @@ -83,7 +86,10 @@ httpServletRequest.login("user","password"); ---- ==== -NOTE: You need not catch the `ServletException` if you want Spring Security to process the failed authentication attempt. +[NOTE] +==== +You need not catch the `ServletException` if you want Spring Security to process the failed authentication attempt. +==== [[servletapi-logout]] ==== HttpServletRequest.logout() diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/java-configuration/index.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/java-configuration/index.adoc index a53ce7937b7..7aa6356174b 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/java-configuration/index.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/java-configuration/index.adoc @@ -6,7 +6,11 @@ Spring Security 3.2 introduced Java configuration to let users configure Spring If you are familiar with the <>, you should find quite a few similarities between it and Spring Security Java configuration. -NOTE: Spring Security provides https://github.com/spring-projects/spring-security-samples/tree/main/servlet/java-configuration[lots of sample applications] to demonstrate the use of Spring Security Java Configuration. +[NOTE] +==== +Spring Security provides https://github.com/spring-projects/spring-security-samples/tree/main/servlet/java-configuration[lots of sample applications] to demonstrate the use of Spring Security Java Configuration. +==== + [[jc-hello-wsca]] == Hello Web Security Java Configuration @@ -273,7 +277,10 @@ public class MyCustomDsl extends AbstractHttpConfigurer>. -NOTE: You can use multiple `` elements to define different access requirements for different sets of URLs, but they are evaluated in the order listed and the first match is used. +[NOTE] +==== +You can use multiple `` elements to define different access requirements for different sets of URLs, but they are evaluated in the order listed and the first match is used. So you must put the most specific matches at the top. You can also add a `method` attribute to limit the match to a particular HTTP method (`GET`, `POST`, `PUT`, and so on). +==== To add users, you can define a set of test data directly in the namespace: @@ -252,9 +255,12 @@ How can you do this with namespace configuration, since the filter chain is not The order of the filters is always strictly enforced when you use the namespace. When the application context is being created, the filter beans are sorted by the namespace handling code, and the standard Spring Security filters each have an alias in the namespace and a well-known position. -NOTE: In previous versions, the sorting took place after the filter instances had been created, during post-processing of the application context. +[NOTE] +==== +In previous versions, the sorting took place after the filter instances had been created, during post-processing of the application context. In version 3.0+, the sorting is now done at the bean metadata level, before the classes have been instantiated. This has implications for how you add your own filters to the stack, as the entire filter list must be known during the parsing of the `` element. As a result, the syntax changed slightly in version 3.0. +==== The filters, aliases, and namespace elements and attributes that create the filters are shown in the following table, in the order in which they occur in the filter chain: diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/oauth2/oauth2-client.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/oauth2/oauth2-client.adoc index c126a830203..6c1db413737 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/oauth2/oauth2-client.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/oauth2/oauth2-client.adoc @@ -264,12 +264,18 @@ As an alternative, you can use `ClientRegistrations.fromOidcIssuerLocation()` to The `ClientRegistrationRepository` serves as a repository for OAuth 2.0 / OpenID Connect 1.0 `ClientRegistration`(s). -NOTE: Client registration information is ultimately stored and owned by the associated Authorization Server. +[NOTE] +==== +Client registration information is ultimately stored and owned by the associated Authorization Server. This repository provides the ability to retrieve a subset of the primary client registration information, which is stored with the Authorization Server. +==== Spring Boot 2.x auto-configuration binds each of the properties under `spring.security.oauth2.client.registration._[registrationId]_` to an instance of `ClientRegistration` and then composes each of the `ClientRegistration` instance(s) within a `ClientRegistrationRepository`. -NOTE: The default implementation of `ClientRegistrationRepository` is `InMemoryClientRegistrationRepository`. +[NOTE] +==== +The default implementation of `ClientRegistrationRepository` is `InMemoryClientRegistrationRepository`. +==== The auto-configuration also registers the `ClientRegistrationRepository` as a `@Bean` in the `ApplicationContext` so that it is available for dependency injection, if needed by the application. @@ -385,15 +391,20 @@ class OAuth2ClientController { ---- ==== -NOTE: Spring Boot 2.x auto-configuration registers an `OAuth2AuthorizedClientRepository` or an `OAuth2AuthorizedClientService` `@Bean` in the `ApplicationContext`. +[NOTE] +==== +Spring Boot 2.x auto-configuration registers an `OAuth2AuthorizedClientRepository` or an `OAuth2AuthorizedClientService` `@Bean` in the `ApplicationContext`. However, the application can override and register a custom `OAuth2AuthorizedClientRepository` or `OAuth2AuthorizedClientService` `@Bean`. +==== The default implementation of `OAuth2AuthorizedClientService` is `InMemoryOAuth2AuthorizedClientService`, which stores `OAuth2AuthorizedClient` objects in-memory. Alternatively, you can configure the JDBC implementation `JdbcOAuth2AuthorizedClientService` to persist `OAuth2AuthorizedClient` instances in a database. -NOTE: `JdbcOAuth2AuthorizedClientService` depends on the table definition described in <>. - +[NOTE] +==== +`JdbcOAuth2AuthorizedClientService` depends on the table definition described in <>. +==== [[oauth2Client-authorized-manager-provider]] ==== OAuth2AuthorizedClientManager and OAuth2AuthorizedClientProvider @@ -616,12 +627,18 @@ This section describes Spring Security's support for authorization grants. [[oauth2Client-auth-code-grant]] ==== Authorization Code -NOTE: See the OAuth 2.0 Authorization Framework for further details on the https://tools.ietf.org/html/rfc6749#section-1.3.1[Authorization Code] grant. +[NOTE] +==== +See the OAuth 2.0 Authorization Framework for further details on the https://tools.ietf.org/html/rfc6749#section-1.3.1[Authorization Code] grant. +==== ===== Obtaining Authorization -NOTE: See the https://tools.ietf.org/html/rfc6749#section-4.1.1[Authorization Request/Response] protocol flow for the Authorization Code grant. +[NOTE] +==== +See the https://tools.ietf.org/html/rfc6749#section-4.1.1[Authorization Request/Response] protocol flow for the Authorization Code grant. +==== ===== Initiating the Authorization Request @@ -656,8 +673,11 @@ spring: Given the preceding properties, a request with the base path `/oauth2/authorization/okta` initiates the Authorization Request redirect by the `OAuth2AuthorizationRequestRedirectFilter` and ultimately starts the Authorization Code grant flow. -NOTE: The `AuthorizationCodeOAuth2AuthorizedClientProvider` is an implementation of `OAuth2AuthorizedClientProvider` for the Authorization Code grant, +[NOTE] +==== +The `AuthorizationCodeOAuth2AuthorizedClientProvider` is an implementation of `OAuth2AuthorizedClientProvider` for the Authorization Code grant, which also initiates the Authorization Request redirect by the `OAuth2AuthorizationRequestRedirectFilter`. +==== If the OAuth 2.0 Client is a https://tools.ietf.org/html/rfc6749#section-2.1[Public Client], configure the OAuth 2.0 Client registration as follows: @@ -704,7 +724,10 @@ spring: ---- ==== -NOTE: `+{baseUrl}+` resolves to `+{baseScheme}://{baseHost}{basePort}{basePath}+` +[NOTE] +==== +`+{baseUrl}+` resolves to `+{baseScheme}://{baseHost}{basePort}{basePath}+` +==== Configuring the `redirect-uri` with `URI` template variables is especially useful when the OAuth 2.0 Client is running behind a <>. Doing so ensures that the `X-Forwarded-*` headers are used when expanding the `redirect-uri`. @@ -716,7 +739,10 @@ One of the primary use cases an `OAuth2AuthorizationRequestResolver` can realize For example, OpenID Connect defines additional OAuth 2.0 request parameters for the https://openid.net/specs/openid-connect-core-1_0.html#AuthRequest[Authorization Code Flow] extending from the standard parameters defined in the https://tools.ietf.org/html/rfc6749#section-4.1.1[OAuth 2.0 Authorization Framework]. One of those extended parameters is the `prompt` parameter. -NOTE: The `prompt` parameter is optional. Space delimited, case sensitive list of ASCII string values that specifies whether the Authorization Server prompts the End-User for re-authentication and consent. The defined values are: `none`, `login`, `consent`, and `select_account`. +[NOTE] +==== +The `prompt` parameter is optional. Space delimited, case sensitive list of ASCII string values that specifies whether the Authorization Server prompts the End-User for re-authentication and consent. The defined values are: `none`, `login`, `consent`, and `select_account`. +==== The following example shows how to configure the `DefaultOAuth2AuthorizationRequestResolver` with a `Consumer` that customizes the Authorization Request for `oauth2Login()`, by including the request parameter `prompt=consent`. @@ -825,7 +851,10 @@ spring: The preceding example shows the common use case of adding a custom parameter on top of the standard parameters. Alternatively, if your requirements are more advanced, you can take full control in building the Authorization Request URI by overriding the `OAuth2AuthorizationRequest.authorizationRequestUri` property. -TIP: `OAuth2AuthorizationRequest.Builder.build()` constructs the `OAuth2AuthorizationRequest.authorizationRequestUri`, which represents the Authorization Request URI that includes all query parameters that use the `application/x-www-form-urlencoded` format. +[TIP] +==== +`OAuth2AuthorizationRequest.Builder.build()` constructs the `OAuth2AuthorizationRequest.authorizationRequestUri`, which represents the Authorization Request URI that includes all query parameters that use the `application/x-www-form-urlencoded` format. +==== The following example shows a variation of `authorizationRequestCustomizer()` from the preceding example and instead overrides the `OAuth2AuthorizationRequest.authorizationRequestUri` property: @@ -860,7 +889,10 @@ private fun authorizationRequestCustomizer(): Consumer, OAuth2AccessTokenResponse>` that is used for converting the OAuth 2.0 Access Token Response parameters to an `OAuth2AccessTokenResponse`. @@ -1025,12 +1066,18 @@ class OAuth2ClientSecurityConfig : WebSecurityConfigurerAdapter() { [[oauth2Client-refresh-token-grant]] ==== Refresh Token -NOTE: See the OAuth 2.0 Authorization Framework for further details on the https://tools.ietf.org/html/rfc6749#section-1.5[Refresh Token]. +[NOTE] +==== +See the OAuth 2.0 Authorization Framework for further details on the https://tools.ietf.org/html/rfc6749#section-1.5[Refresh Token]. +==== ===== Refreshing an Access Token -NOTE: See the https://tools.ietf.org/html/rfc6749#section-6[Access Token Request/Response] protocol flow for the Refresh Token grant. +[NOTE] +==== +See the https://tools.ietf.org/html/rfc6749#section-6[Access Token Request/Response] protocol flow for the Refresh Token grant. +==== The default implementation of `OAuth2AccessTokenResponseClient` for the Refresh Token grant is `DefaultRefreshTokenTokenResponseClient`, which uses a `RestOperations` when refreshing an access token at the Authorization Server’s Token Endpoint. @@ -1043,7 +1090,10 @@ If you need to customize the pre-processing of the Token Request, you can provid The default implementation (`OAuth2RefreshTokenGrantRequestEntityConverter`) builds a `RequestEntity` representation of a standard https://tools.ietf.org/html/rfc6749#section-6[OAuth 2.0 Access Token Request]. However, providing a custom `Converter` would let you extend the standard Token Request and add custom parameter(s). -IMPORTANT: The custom `Converter` must return a valid `RequestEntity` representation of an OAuth 2.0 Access Token Request that is understood by the intended OAuth 2.0 Provider. +[IMPORTANT] +==== +The custom `Converter` must return a valid `RequestEntity` representation of an OAuth 2.0 Access Token Request that is understood by the intended OAuth 2.0 Provider. +==== ===== Customizing the Access Token Response @@ -1073,7 +1123,10 @@ restTemplate.errorHandler = OAuth2ErrorResponseErrorHandler() ---- ==== -TIP: Spring MVC `FormHttpMessageConverter` is required, as it is used when sending the OAuth 2.0 Access Token Request. +[TIP] +==== +Spring MVC `FormHttpMessageConverter` is required, as it is used when sending the OAuth 2.0 Access Token Request. +==== `OAuth2AccessTokenResponseHttpMessageConverter` is a `HttpMessageConverter` for an OAuth 2.0 Access Token Response. You can provide `OAuth2AccessTokenResponseHttpMessageConverter.setTokenResponseConverter()` with a custom `Converter, OAuth2AccessTokenResponse>` that is used for converting the OAuth 2.0 Access Token Response parameters to an `OAuth2AccessTokenResponse`. @@ -1129,12 +1182,18 @@ If the `OAuth2AuthorizedClient.getRefreshToken()` is available and the `OAuth2Au [[oauth2Client-client-creds-grant]] ==== Client Credentials -NOTE: See the OAuth 2.0 Authorization Framework for further details on the https://tools.ietf.org/html/rfc6749#section-1.3.4[Client Credentials] grant. +[NOTE] +==== +See the OAuth 2.0 Authorization Framework for further details on the https://tools.ietf.org/html/rfc6749#section-1.3.4[Client Credentials] grant. +==== ===== Requesting an Access Token -NOTE: See the https://tools.ietf.org/html/rfc6749#section-4.4.2[Access Token Request/Response] protocol flow for the Client Credentials grant. +[NOTE] +==== +See the https://tools.ietf.org/html/rfc6749#section-4.4.2[Access Token Request/Response] protocol flow for the Client Credentials grant. +==== The default implementation of `OAuth2AccessTokenResponseClient` for the Client Credentials grant is `DefaultClientCredentialsTokenResponseClient`, which uses a `RestOperations` when requesting an access token at the Authorization Server’s Token Endpoint. @@ -1147,7 +1206,10 @@ If you need to customize the pre-processing of the Token Request, you can provid The default implementation (`OAuth2ClientCredentialsGrantRequestEntityConverter`) builds a `RequestEntity` representation of a standard https://tools.ietf.org/html/rfc6749#section-4.4.2[OAuth 2.0 Access Token Request]. However, providing a custom `Converter` would let you extend the standard Token Request and add custom parameter(s). -IMPORTANT: The custom `Converter` must return a valid `RequestEntity` representation of an OAuth 2.0 Access Token Request that is understood by the intended OAuth 2.0 Provider. +[IMPORTANT] +==== +The custom `Converter` must return a valid `RequestEntity` representation of an OAuth 2.0 Access Token Request that is understood by the intended OAuth 2.0 Provider. +==== ===== Customizing the Access Token Response @@ -1177,7 +1239,10 @@ restTemplate.errorHandler = OAuth2ErrorResponseErrorHandler() ---- ==== -TIP: Spring MVC `FormHttpMessageConverter` is required, as it is used when sending the OAuth 2.0 Access Token Request. +[TIP] +==== +Spring MVC `FormHttpMessageConverter` is required, as it is used when sending the OAuth 2.0 Access Token Request. +==== `OAuth2AccessTokenResponseHttpMessageConverter` is a `HttpMessageConverter` for an OAuth 2.0 Access Token Response. You can provide `OAuth2AccessTokenResponseHttpMessageConverter.setTokenResponseConverter()` with a custom `Converter, OAuth2AccessTokenResponse>` that is used for converting the OAuth 2.0 Access Token Response parameters to an `OAuth2AccessTokenResponse`. @@ -1220,8 +1285,12 @@ authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider) ---- ==== -NOTE: `OAuth2AuthorizedClientProviderBuilder.builder().clientCredentials()` configures a `ClientCredentialsOAuth2AuthorizedClientProvider`, +[NOTE] +==== +`OAuth2AuthorizedClientProviderBuilder.builder().clientCredentials()` configures a `ClientCredentialsOAuth2AuthorizedClientProvider`, which is an implementation of an `OAuth2AuthorizedClientProvider` for the Client Credentials grant. +==== + ===== Using the Access Token @@ -1354,19 +1423,28 @@ class OAuth2ClientController { ---- ==== -NOTE: `HttpServletRequest` and `HttpServletResponse` are both OPTIONAL attributes. +[NOTE] +==== +`HttpServletRequest` and `HttpServletResponse` are both OPTIONAL attributes. If not provided, they default to `ServletRequestAttributes` by using `RequestContextHolder.getRequestAttributes()`. +==== [[oauth2Client-password-grant]] ==== Resource Owner Password Credentials -NOTE: See the OAuth 2.0 Authorization Framework for further details on the https://tools.ietf.org/html/rfc6749#section-1.3.3[Resource Owner Password Credentials] grant. +[NOTE] +==== +See the OAuth 2.0 Authorization Framework for further details on the https://tools.ietf.org/html/rfc6749#section-1.3.3[Resource Owner Password Credentials] grant. +==== ===== Requesting an Access Token -NOTE: See the https://tools.ietf.org/html/rfc6749#section-4.3.2[Access Token Request/Response] protocol flow for the Resource Owner Password Credentials grant. +[NOTE] +==== +See the https://tools.ietf.org/html/rfc6749#section-4.3.2[Access Token Request/Response] protocol flow for the Resource Owner Password Credentials grant. +==== The default implementation of `OAuth2AccessTokenResponseClient` for the Resource Owner Password Credentials grant is `DefaultPasswordTokenResponseClient`, which uses a `RestOperations` when requesting an access token at the Authorization Server’s Token Endpoint. @@ -1379,7 +1457,10 @@ If you need to customize the pre-processing of the Token Request, you can provid The default implementation (`OAuth2PasswordGrantRequestEntityConverter`) builds a `RequestEntity` representation of a standard https://tools.ietf.org/html/rfc6749#section-4.3.2[OAuth 2.0 Access Token Request]. However, providing a custom `Converter` would let you extend the standard Token Request and add custom parameter(s). -IMPORTANT: The custom `Converter` must return a valid `RequestEntity` representation of an OAuth 2.0 Access Token Request that is understood by the intended OAuth 2.0 Provider. +[IMPORTANT] +==== +The custom `Converter` must return a valid `RequestEntity` representation of an OAuth 2.0 Access Token Request that is understood by the intended OAuth 2.0 Provider. +==== ===== Customizing the Access Token Response @@ -1409,7 +1490,10 @@ restTemplate.errorHandler = OAuth2ErrorResponseErrorHandler() ---- ==== -TIP: Spring MVC `FormHttpMessageConverter` is required, as it is used when sending the OAuth 2.0 Access Token Request. +[TIP] +==== +Spring MVC `FormHttpMessageConverter` is required, as it is used when sending the OAuth 2.0 Access Token Request. +==== `OAuth2AccessTokenResponseHttpMessageConverter` is a `HttpMessageConverter` for an OAuth 2.0 Access Token Response. You can provide `OAuth2AccessTokenResponseHttpMessageConverter.setTokenResponseConverter()` with a custom `Converter, OAuth2AccessTokenResponse>` that is used to convert the OAuth 2.0 Access Token Response parameters to an `OAuth2AccessTokenResponse`. @@ -1685,7 +1769,10 @@ restTemplate.errorHandler = OAuth2ErrorResponseErrorHandler() ---- ==== -TIP: Spring MVC `FormHttpMessageConverter` is required as it's used when sending the OAuth 2.0 Access Token Request. +[TIP] +==== +Spring MVC `FormHttpMessageConverter` is required as it's used when sending the OAuth 2.0 Access Token Request. +==== `OAuth2AccessTokenResponseHttpMessageConverter` is a `HttpMessageConverter` for an OAuth 2.0 Access Token Response. You can provide `OAuth2AccessTokenResponseHttpMessageConverter.setTokenResponseConverter()` with a custom `Converter, OAuth2AccessTokenResponse>` that is used for converting the OAuth 2.0 Access Token Response parameters to an `OAuth2AccessTokenResponse`. @@ -2246,8 +2333,10 @@ fun webClient(authorizedClientManager: OAuth2AuthorizedClientManager?): WebClien ---- ==== -WARNING: Be cautious with this feature, since all HTTP requests receive the access token. - +[WARNING] +==== +Be cautious with this feature, since all HTTP requests receive the access token. +==== Alternatively, if `setDefaultClientRegistrationId("okta")` is configured with a valid `ClientRegistration`, the `OAuth2AccessToken` associated with the `OAuth2AuthorizedClient` is used. The following code shows the specific configuration: @@ -2281,4 +2370,7 @@ fun webClient(authorizedClientManager: OAuth2AuthorizedClientManager?): WebClien ---- ==== -WARNING: Be cautious with this feature, since all HTTP requests receive the access token. +[WARNING] +==== +Be cautious with this feature, since all HTTP requests receive the access token. +==== diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/oauth2/oauth2-login.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/oauth2/oauth2-login.adoc index e2cd5bdde1e..e134815b6bf 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/oauth2/oauth2-login.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/oauth2/oauth2-login.adoc @@ -4,7 +4,10 @@ The OAuth 2.0 Login feature lets an application have users log in to the application by using their existing account at an OAuth 2.0 Provider (such as GitHub) or OpenID Connect 1.0 Provider (such as Google). OAuth 2.0 Login implements two use cases: "`Login with Google`" or "`Login with GitHub`". -NOTE: OAuth 2.0 Login is implemented by using the *Authorization Code Grant*, as specified in the https://tools.ietf.org/html/rfc6749#section-4.1[OAuth 2.0 Authorization Framework] and https://openid.net/specs/openid-connect-core-1_0.html#CodeFlowAuth[OpenID Connect Core 1.0]. +[NOTE] +==== +OAuth 2.0 Login is implemented by using the *Authorization Code Grant*, as specified in the https://tools.ietf.org/html/rfc6749#section-4.1[OAuth 2.0 Authorization Framework] and https://openid.net/specs/openid-connect-core-1_0.html#CodeFlowAuth[OpenID Connect Core 1.0]. +==== [[oauth2login-sample-boot]] @@ -25,7 +28,10 @@ This section shows how to configure the {gh-samples-url}/boot/oauth2login[*OAuth To use Google's OAuth 2.0 authentication system for login, you must set up a project in the Google API Console to obtain OAuth 2.0 credentials. -NOTE: https://developers.google.com/identity/protocols/OpenIDConnect[Google's OAuth 2.0 implementation] for authentication conforms to the https://openid.net/connect/[OpenID Connect 1.0] specification and is https://openid.net/certification/[OpenID certified]. +[NOTE] +==== +https://developers.google.com/identity/protocols/OpenIDConnect[Google's OAuth 2.0 implementation] for authentication conforms to the https://openid.net/connect/[OpenID Connect 1.0] specification and is https://openid.net/certification/[OpenID certified]. +==== Follow the instructions on the https://developers.google.com/identity/protocols/OpenIDConnect[OpenID Connect] page, starting in the "`Setting up OAuth 2.0`" section. @@ -39,11 +45,17 @@ The redirect URI is the path in the application that the end-user's user-agent i In the "`Set a redirect URI`" subsection, ensure that the *Authorized redirect URIs* field is set to `http://localhost:8080/login/oauth2/code/google`. -TIP: The default redirect URI template is `+{baseUrl}/login/oauth2/code/{registrationId}+`. +[TIP] +==== +The default redirect URI template is `+{baseUrl}/login/oauth2/code/{registrationId}+`. The `registrationId` is a unique identifier for the <>. +==== -IMPORTANT: If the OAuth Client runs behind a proxy server, you should check the <> to ensure the application is correctly configured. +[IMPORTANT] +==== +If the OAuth Client runs behind a proxy server, you should check the <> to ensure the application is correctly configured. Also, see the supported <> for `redirect-uri`. +==== [[oauth2login-sample-application-config]] @@ -144,7 +156,10 @@ The following table outlines the mapping of the Spring Boot 2.x OAuth Client pro |`providerDetails.userInfoEndpoint.userNameAttributeName` |=== -TIP: You can initially configure a `ClientRegistration` by using discovery of an OpenID Connect Provider's https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfig[Configuration endpoint] or an Authorization Server's https://tools.ietf.org/html/rfc8414#section-3[Metadata endpoint], by specifying the `spring.security.oauth2.client.provider._[providerId]_.issuer-uri` property. +[TIP] +==== +You can initially configure a `ClientRegistration` by using discovery of an OpenID Connect Provider's https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfig[Configuration endpoint] or an Authorization Server's https://tools.ietf.org/html/rfc8414#section-3[Metadata endpoint], by specifying the `spring.security.oauth2.client.provider._[providerId]_.issuer-uri` property. +==== [[oauth2login-common-oauth2-provider]] @@ -732,8 +747,11 @@ The following sections go into more detail on each of the configuration options By default, the OAuth 2.0 Login Page is auto-generated by the `DefaultLoginPageGeneratingFilter`. The default login page shows each configured OAuth Client with its `ClientRegistration.clientName` as a link, which is capable of initiating the Authorization Request (or OAuth 2.0 Login). -NOTE: For `DefaultLoginPageGeneratingFilter` to show links for configured OAuth Clients, the registered `ClientRegistrationRepository` needs to also implement `Iterable`. +[NOTE] +==== +For `DefaultLoginPageGeneratingFilter` to show links for configured OAuth Clients, the registered `ClientRegistrationRepository` needs to also implement `Iterable`. See `InMemoryClientRegistrationRepository` for reference. +==== The link's destination for each OAuth Client defaults to the following: @@ -805,7 +823,10 @@ class OAuth2LoginSecurityConfig : WebSecurityConfigurerAdapter() { ---- ==== -IMPORTANT: You need to provide a `@Controller` with a `@RequestMapping("/login/oauth2")` that is capable of rendering the custom login page. +[IMPORTANT] +==== +You need to provide a `@Controller` with a `@RequestMapping("/login/oauth2")` that is capable of rendering the custom login page. +==== [TIP] ===== @@ -828,8 +849,11 @@ The following line shows an example: The Redirection Endpoint is used by the Authorization Server for returning the Authorization Response (which contains the authorization credentials) to the client through the Resource Owner user-agent. -TIP: OAuth 2.0 Login leverages the Authorization Code Grant. +[TIP] +==== +OAuth 2.0 Login leverages the Authorization Code Grant. Therefore, the authorization credential is the authorization code. +==== The default Authorization Response `baseUri` (redirection endpoint) is `*/login/oauth2/code/**`, which is defined in `OAuth2LoginAuthenticationFilter.DEFAULT_FILTER_PROCESSES_URI`. @@ -1191,7 +1215,10 @@ class OAuth2LoginSecurityConfig : WebSecurityConfigurerAdapter() { `DefaultOAuth2UserService` is an implementation of an `OAuth2UserService` that supports standard OAuth 2.0 Provider's. -NOTE: `OAuth2UserService` obtains the user attributes of the end-user (the resource owner) from the UserInfo Endpoint (by using the access token granted to the client during the authorization flow) and returns an `AuthenticatedPrincipal` in the form of an `OAuth2User`. +[NOTE] +==== +`OAuth2UserService` obtains the user attributes of the end-user (the resource owner) from the UserInfo Endpoint (by using the access token granted to the client during the authorization flow) and returns an `AuthenticatedPrincipal` in the form of an `OAuth2User`. +==== `DefaultOAuth2UserService` uses a `RestOperations` instance when requesting the user attributes at the UserInfo Endpoint. @@ -1361,9 +1388,15 @@ fun idTokenDecoderFactory(): JwtDecoderFactory { ---- ==== -NOTE: For MAC-based algorithms (such as `HS256`, `HS384`, or `HS512`), the `client-secret` that corresponds to the `client-id` is used as the symmetric key for signature verification. +[NOTE] +==== +For MAC-based algorithms (such as `HS256`, `HS384`, or `HS512`), the `client-secret` that corresponds to the `client-id` is used as the symmetric key for signature verification. +==== -TIP: If more than one `ClientRegistration` is configured for OpenID Connect 1.0 Authentication, the JWS algorithm resolver may evaluate the provided `ClientRegistration` to determine which algorithm to return. +[TIP] +==== +If more than one `ClientRegistration` is configured for OpenID Connect 1.0 Authentication, the JWS algorithm resolver may evaluate the provided `ClientRegistration` to determine which algorithm to return. +==== [[oauth2login-advanced-oidc-logout]] @@ -1433,9 +1466,11 @@ public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter { ---- ==== -[subs="none"] -NOTE: `OidcClientInitiatedLogoutSuccessHandler` supports the `{baseUrl}` placeholder. +[NOTE] +==== +`OidcClientInitiatedLogoutSuccessHandler` supports the `+{baseUrl}+` placeholder. If used, the application's base URL, such as `https://app.example.org`, replaces it at request time. +==== .Kotlin ==== @@ -1470,6 +1505,8 @@ class OAuth2LoginSecurityConfig : WebSecurityConfigurerAdapter() { ---- ==== -[subs="none"] -NOTE: `OidcClientInitiatedLogoutSuccessHandler` supports the `{baseUrl}` placeholder. +[NOTE] +==== +`OidcClientInitiatedLogoutSuccessHandler` supports the `+{baseUrl}+` placeholder. If used, the application's base URL, such as `https://app.example.org`, replaces it at request time. +==== diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/oauth2/oauth2-resourceserver.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/oauth2/oauth2-resourceserver.adoc index f5b2ea6dc18..9f7fba6ae35 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/oauth2/oauth2-resourceserver.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/oauth2/oauth2-resourceserver.adoc @@ -13,7 +13,10 @@ This authorization server can be consulted by resource servers to authorize requ This section details how Spring Security provides support for OAuth 2.0 https://tools.ietf.org/html/rfc6750.html[Bearer Tokens]. -NOTE: Working samples for both {gh-samples-url}/boot/oauth2resourceserver[JWTs] and {gh-samples-url}/boot/oauth2resourceserver-opaque[Opaque Tokens] are available in the {gh-samples-url}[Spring Security repository]. +[NOTE] +==== +Working samples for both {gh-samples-url}/boot/oauth2resourceserver[JWTs] and {gh-samples-url}/boot/oauth2resourceserver-opaque[Opaque Tokens] are available in the {gh-samples-url}[Spring Security repository]. +==== Now we can consider how Bearer Token Authentication works within Spring Security. First, we see that, as with <>, the https://tools.ietf.org/html/rfc7235#section-4.1[WWW-Authenticate] header is sent back to an unauthenticated client: @@ -29,7 +32,10 @@ image:{icondir}/number_3.png[] Since the user is not authenticated, <> is an instance of {security-api-url}org/springframework/security/oauth2/server/resource/authentication/BearerTokenAuthenticationEntryPoint.html[`BearerTokenAuthenticationEntryPoint`], which sends a `WWW-Authenticate` header. The `RequestCache` is typically a `NullRequestCache` that does not save the request, since the client is capable of replaying the requests it originally requested. -NOTE: The preceding figure builds off of our <> diagram. +[NOTE] +==== +The preceding figure builds off of our <> diagram. +==== When a client receives the `WWW-Authenticate: Bearer` header, it knows it should retry with a bearer token. The following image shows the flow for the bearer token being processed: @@ -53,7 +59,10 @@ image:{icondir}/number_4.png[] If authentication is successful, then __Success__ * The <> is set on the <>. * The `BearerTokenAuthenticationFilter` invokes `FilterChain.doFilter(request,response)` to continue with the rest of the application logic. -NOTE: The preceding figure builds off our <> diagram. +[NOTE] +==== +The preceding figure builds off our <> diagram. +==== [[oauth2resourceserver-jwt-minimaldependencies]] === Minimal Dependencies for JWT @@ -88,8 +97,11 @@ spring: Resource Server uses this property to further self-configure, discover the authorization server's public keys, and, subsequently, validate incoming JWTs. -NOTE: To use the `issuer-uri` property, it must also be true that one of `https://idp.example.com/issuer/.well-known/openid-configuration`, `https://idp.example.com/.well-known/openid-configuration/issuer`, or `https://idp.example.com/.well-known/oauth-authorization-server/issuer` is a supported endpoint for the authorization server. +[NOTE] +==== +To use the `issuer-uri` property, it must also be true that one of `https://idp.example.com/issuer/.well-known/openid-configuration`, `https://idp.example.com/.well-known/openid-configuration/issuer`, or `https://idp.example.com/.well-known/oauth-authorization-server/issuer` is a supported endpoint for the authorization server. This endpoint is referred to as a https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfig[Provider Configuration] endpoint or a https://tools.ietf.org/html/rfc8414#section-3[Authorization Server Metadata] endpoint. +==== ==== Startup Expectations @@ -104,7 +116,10 @@ It achieves this through a deterministic startup process: A consequence of this process is that the authorization server must be up and receiving requests for Resource Server to successfully start up. -NOTE: If the authorization server is down when Resource Server queries it (given appropriate timeouts), startup fails. +[NOTE] +==== +If the authorization server is down when Resource Server queries it (given appropriate timeouts), startup fails. +==== ==== Runtime Expectations @@ -126,7 +141,10 @@ Given a well-formed JWT, Resource Server: . Validates the JWT's `exp` and `nbf` timestamps and the JWT's `iss` claim. . Maps each scope to an authority with the prefix `SCOPE_`. -NOTE: As the authorization server makes available new keys, Spring Security automatically rotates the keys used to validate JWTs. +[NOTE] +==== +As the authorization server makes available new keys, Spring Security automatically rotates the keys used to validate JWTs. +==== The resulting `Authentication#getPrincipal`, by default, is a Spring Security `Jwt` object, and `Authentication#getName` maps to the JWT's `sub` property, if one is present. @@ -180,12 +198,19 @@ spring: ---- ==== -NOTE: The JWK Set URI is not standardized, but you can typically find it in the authorization server's documentation. +[NOTE] +==== +The JWK Set URI is not standardized, but you can typically find it in the authorization server's documentation. +==== Consequently, Resource Server does not ping the authorization server at startup. We still specify the `issuer-uri` so that Resource Server still validates the `iss` claim on incoming JWTs. -NOTE: You can also supply this property directly on the <>. +[NOTE] +==== +You can also supply this property directly on the <>. +==== + [[oauth2resourceserver-jwt-sansboot]] === Overriding or Replacing Boot Auto Configuration @@ -300,7 +325,10 @@ fun jwtDecoder(): JwtDecoder { ---- ==== -NOTE: Calling `{security-api-url}org/springframework/security/oauth2/jwt/JwtDecoders.html#fromIssuerLocation-java.lang.String-[JwtDecoders#fromIssuerLocation]` invokes the Provider Configuration or Authorization Server Metadata endpoint, to derive the JWK Set URI. +[NOTE] +==== +Calling `{security-api-url}org/springframework/security/oauth2/jwt/JwtDecoders.html#fromIssuerLocation-java.lang.String-[JwtDecoders#fromIssuerLocation]` invokes the Provider Configuration or Authorization Server Metadata endpoint, to derive the JWK Set URI. +==== If the application does not expose a `JwtDecoder` bean, Spring Boot exposes the earlier default one. @@ -1074,6 +1102,8 @@ fun jwtDecoder(): JwtDecoder { [NOTE] By default, Resource Server configures a clock skew of 60 seconds. +==== + [[oauth2resourceserver-jwt-validation-custom]] ==== Configuring a Custom Validator @@ -1426,10 +1456,17 @@ fun jwtDecoder(cacheManager: CacheManager): JwtDecoder { When given a `Cache`, Resource Server uses the JWK Set URI as the key and the JWK Set JSON as the value. -NOTE: Spring is not a cache provider, so you need to make sure to include the appropriate dependencies, such as `spring-boot-starter-cache` and your favorite caching provider. +[NOTE] +==== +Spring is not a cache provider, so you need to make sure to include the appropriate dependencies, such as `spring-boot-starter-cache` and your favorite caching provider. +==== -NOTE: Whether it is socket or cache timeouts, you may instead want to work with Nimbus directly. +[NOTE] +==== +Whether it is socket or cache timeouts, you may instead want to work with Nimbus directly. To do so, remember that `NimbusJwtDecoder` ships with a constructor that takes Nimbus's `JWTProcessor`. +==== + [[oauth2resourceserver-opaque-minimaldependencies]] === Minimal Dependencies for Introspection @@ -1471,8 +1508,12 @@ Where `https://idp.example.com/introspect` is the introspection endpoint hosted Resource Server uses these properties to further self-configure and subsequently validate incoming JWTs. -NOTE: When using introspection, the authorization server's word is law. +[NOTE] +==== +When using introspection, the authorization server's word is law. If the authorization server responsed that the token is valid, it is. +==== + ==== Startup Expectations @@ -2377,7 +2418,10 @@ fun tokenAuthenticationManagerResolver(): AuthenticationManagerResolver>. +==== [[oauth2resourceserver-bearertoken-failure]] === Bearer Token Failure diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/saml2/saml2-login.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/saml2/saml2-login.adoc index 11ed3058b90..b93bd855087 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/saml2/saml2-login.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/saml2/saml2-login.adoc @@ -5,15 +5,21 @@ The SAML 2.0 Login feature provides an application with the ability 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, and others). -NOTE: SAML 2.0 Login is implemented by using the *Web Browser SSO Profile*, as specified in +[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 <>. -NOTE: A working sample for {gh-samples-url}/boot/saml2login[SAML 2.0 Login] is available in the {gh-samples-url}[Spring Security repository]. +[NOTE] +==== +A working sample for {gh-samples-url}/boot/saml2login[SAML 2.0 Login] is available in the {gh-samples-url}[Spring Security repository]. +==== We start by examining how SAML 2.0 Relying Party Authentication works within Spring Security. First, we see that, like <>, Spring Security takes the user to a third party for performing authentication. @@ -22,7 +28,10 @@ It does this through a series of redirects: .Redirecting to Asserting Party Authentication image::{figures}/saml2webssoauthenticationrequestfilter.png[] -NOTE: The preceding figure above builds off our <> and <> diagrams. +[NOTE] +==== +The preceding figure above builds off our <> and <> diagrams. +==== image:{icondir}/number_1.png[] First, a user makes an unauthenticated request to the `/private` resource, for which it is not authorized. @@ -46,7 +55,10 @@ The following image shows how Spring Security authenticates a `` .Authenticating a `` image::{figures}/saml2webssoauthenticationfilter.png[] -NOTE: The figure builds off our <> diagram. +[NOTE] +==== +The figure builds off our <> diagram. +==== image:{icondir}/number_1.png[] When the browser submits a `` to the application, it <>. This filter calls its configured `AuthenticationConverter` to create a `Saml2AuthenticationToken` by extracting the response from the `HttpServletRequest`. @@ -110,8 +122,11 @@ where: * `classpath:idp.crt` is the location on the classpath for the identity provider's certificate for verifying SAML responses. * `https://idp.example.com/issuer/sso` is the endpoint where the identity provider is expecting `AuthnRequest` instances. -NOTE: Identity Provider and Asserting Party are synonymous, as are Service Provider and Relying Party. +[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 @@ -158,7 +173,10 @@ For example, once your application receives a `SAMLResponse` and delegates to `S .Authenticating an OpenSAML `Response` image:{figures}/opensamlauthenticationprovider.png[] -NOTE: This figure builds off of the <>. +[NOTE] +==== +This figure builds off of the <>. +==== image:{icondir}/number_1.png[] The `Saml2WebSsoAuthenticationFilter` formulates the `Saml2AuthenticationToken` and invokes the <>. @@ -373,7 +391,10 @@ public RelyingPartyRegistrationRepository relyingPartyRegistrations() throws Exc ---- ==== -NOTE: `X509Support` is an OpenSAML class, used in the preceding snippet for brevity. +[NOTE] +==== +`X509Support` is an OpenSAML class, used in the preceding snippet for brevity. +==== [[servlet-saml2login-relyingpartyregistrationrepository-dsl]] Alternatively, you can directly wire up the repository by using the DSL, which also overrides the auto-configured `WebSecurityConfigurerAdapter`: @@ -418,8 +439,10 @@ class MyCustomSecurityConfiguration : WebSecurityConfigurerAdapter() { ---- ==== -NOTE: A relying party can be multi-tenant by registering more than one relying party in the `RelyingPartyRegistrationRepository`. - +[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`] @@ -458,10 +481,16 @@ RelyingPartyRegistration relyingPartyRegistration = RelyingPartyRegistration.wit ---- ==== -TIP: The top-level metadata methods are details about the relying party. +[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. +[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}+`. You need this value when you configure the asserting party to know about your relying party. @@ -543,7 +572,11 @@ try (InputStream is = resource.getInputStream()) { ---- ==== -TIP: When you specify the locations of these files as the appropriate Spring Boot properties, Spring Boot performs these conversions for you. +[TIP] +==== +When you specify the locations of these files as the appropriate Spring Boot properties, Spring Boot performs these conversions for you. +==== + [[servlet-saml2login-rpr-relyingpartyregistrationresolver]] ==== Resolving the Relying Party from the Request @@ -576,7 +609,10 @@ public class SingleRelyingPartyRegistrationResolver Then you can provide this resolver to the appropriate filters that <` instances>>, <` instances>>, and <` metadata>>. -NOTE: Remember that, if you have any placeholders in your `RelyingPartyRegistration`, your resolver implementation should resolve them. +[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 @@ -716,9 +752,12 @@ RelyingPartyRegistration relyingPartyRegistration = RelyingPartyRegistrations.fr ---- ==== -NOTE: The preceding snippet uses the OpenSAML `SignatureConstants` class to supply the algorithm name. +[NOTE] +==== +The preceding snippet uses the OpenSAML `SignatureConstants` class to supply the algorithm name. However, that is only 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 `` be POSTed. @@ -897,8 +936,11 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter { <3> Return a custom authentication that includes the user details ==== -NOTE: You need not call the default authentication converter of `OpenSamlAuthenticationProvider`. +[NOTE] +==== +You need not call the default authentication converter of `OpenSamlAuthenticationProvider`. It returns a `Saml2AuthenticatedPrincipal` that contains the attributes it extracted from `AttributeStatement` instances as well as the single `ROLE_USER` authority. +==== [[servlet-saml2login-opensamlauthenticationprovider-additionalvalidation]] ==== Performing Additional Validation @@ -938,8 +980,11 @@ provider.setAssertionValidator(assertionToken -> { ---- ==== -NOTE: While recommended, you need not call the default assertion validator of `OpenSamlAuthenticationProvider`. +[NOTE] +==== +While recommended, you need not call the default assertion validator of `OpenSamlAuthenticationProvider`. For example, you could skip it if you do not need to check the `` or the `` because you are doing those yourself. +==== [[servlet-saml2login-opensamlauthenticationprovider-decryption]] ==== Customizing Decryption @@ -971,9 +1016,12 @@ provider.setAssertionElementsDecrypter((assertionToken) -> decryptionService.dec ---- ==== -NOTE: We have two separate decrypters, because assertions can be signed separately from responses. +[NOTE] +==== +We have two separate decrypters, because 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 only the response, it is safe to decrypt all elements by using only the response decrypter. +==== [[servlet-saml2login-authenticationmanager-custom]] ==== Using a Custom Authentication Manager @@ -1027,8 +1075,12 @@ public class MainController { ---- ==== -TIP: Because the SAML 2.0 specification lets each attribute have multiple values, you can either call `getAttribute` to get the list of attributes or `getFirstAttribute` to get the first in the list. +[TIP] +==== +Because the SAML 2.0 specification lets each attribute 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 handy when you know that there is only one value. +==== + [[servlet-saml2login-metadata]] === Producing `` Metadata diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/test/index.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/test/index.adoc index ae8ef2de74a..2e3025847a5 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/test/index.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/test/index.adoc @@ -3,7 +3,10 @@ This section describes the testing support provided by Spring Security. -NOTE: To use the Spring Security test support, you must include `spring-security-test-{spring-security-version}.jar` as a dependency of your project. +[NOTE] +==== +To use the Spring Security test support, you must include `spring-security-test-{spring-security-version}.jar` as a dependency of your project. +==== include::method.adoc[] diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/test/method.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/test/method.adoc index 316cf6c4d04..aeb883cbcc5 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/test/method.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/test/method.adoc @@ -47,11 +47,14 @@ public class WithMockUserTests { <2> `@ContextConfiguration` instructs the Spring test configuration to use to create the `ApplicationContext`. Since no configuration is specified, the default configuration locations are tried. This is no different than using the existing Spring test support. For additional information, see the https://docs.spring.io/spring-framework/docs/4.0.x/spring-framework-reference/htmlsingle/#testcontext-ctx-management[Spring Reference]. ==== -NOTE: Spring Security hooks into Spring Test support through the `WithSecurityContextTestExecutionListener`, which ensures that our tests are run with the correct user. +[NOTE] +==== +Spring Security hooks into Spring Test support through the `WithSecurityContextTestExecutionListener`, which ensures that our tests are run with the correct user. It does this by populating the `SecurityContextHolder` prior to running our tests. If you use reactive method security, you also need `ReactorContextTestExecutionListener`, which populates `ReactiveSecurityContextHolder`. After the test is done, it clears out the `SecurityContextHolder`. If you need only Spring Security related support, you can replace `@ContextConfiguration` with `@SecurityTestExecutionListeners`. +==== Remember, we added the `@PreAuthorize` annotation to our `HelloMessageService`, so it requires an authenticated user to invoke it. If we run the tests, we expect the following test will pass: diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/test/mockmvc.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/test/mockmvc.adoc index aa380f4b33d..468bd091652 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/test/mockmvc.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/test/mockmvc.adoc @@ -6,7 +6,10 @@ Spring Security provides comprehensive integration with https://docs.spring.io/s [[test-mockmvc-setup]] === Setting Up MockMvc and Spring Security -NOTE: Spring Security's testing support requires spring-test-4.1.3.RELEASE or greater. +[NOTE] +==== +Spring Security's testing support requires spring-test-4.1.3.RELEASE or greater. +==== To use Spring Security with Spring MVC Test, add the Spring Security `FilterChainProxy` as a `Filter`. You also need to add Spring Security's `TestSecurityContextHolderPostProcessor` to support <>. From 252ef7842dfff01365b67989f4199b19a8079f61 Mon Sep 17 00:00:00 2001 From: Jay Bryant Date: Fri, 4 Jun 2021 14:57:43 -0500 Subject: [PATCH 7/7] Add missing delimiters I missed three block delimiters while restoring admonition formatting. --- .../asciidoc/_includes/reactive/oauth2/resource-server.adoc | 2 ++ .../_includes/servlet/oauth2/oauth2-resourceserver.adoc | 1 + 2 files changed, 3 insertions(+) diff --git a/docs/manual/src/docs/asciidoc/_includes/reactive/oauth2/resource-server.adoc b/docs/manual/src/docs/asciidoc/_includes/reactive/oauth2/resource-server.adoc index cc429e47658..af8d8304cf2 100644 --- a/docs/manual/src/docs/asciidoc/_includes/reactive/oauth2/resource-server.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/reactive/oauth2/resource-server.adoc @@ -844,7 +844,9 @@ fun jwtDecoder(): ReactiveJwtDecoder { ==== [NOTE] +==== By default, Resource Server configures a clock skew of 60 seconds. +==== [[webflux-oauth2resourceserver-validation-custom]] ==== Configuring a Custom Validator diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/oauth2/oauth2-resourceserver.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/oauth2/oauth2-resourceserver.adoc index 9f7fba6ae35..42d0c62ea18 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/oauth2/oauth2-resourceserver.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/oauth2/oauth2-resourceserver.adoc @@ -1101,6 +1101,7 @@ fun jwtDecoder(): JwtDecoder { ==== [NOTE] +==== By default, Resource Server configures a clock skew of 60 seconds. ====