From aac1261f0cd87a46a6a99d12474e25b59af02952 Mon Sep 17 00:00:00 2001 From: Rob Winch Date: Thu, 27 Oct 2022 15:12:45 -0500 Subject: [PATCH] Document Migration to SecurityContextHolderFilter Closes gh-12098 --- docs/modules/ROOT/pages/migration.adoc | 15 ++++ .../servlet/authentication/persistence.adoc | 25 +----- .../security-context-explicit.adoc | 76 +++++++++++++++++++ 3 files changed, 93 insertions(+), 23 deletions(-) create mode 100644 docs/modules/ROOT/partials/servlet/architecture/security-context-explicit.adoc diff --git a/docs/modules/ROOT/pages/migration.adoc b/docs/modules/ROOT/pages/migration.adoc index 52353959c9..8fca4f3d6c 100644 --- a/docs/modules/ROOT/pages/migration.adoc +++ b/docs/modules/ROOT/pages/migration.adoc @@ -13,6 +13,21 @@ endif::[] == Servlet +=== Explicit Save SecurityContextRepository + +In Spring Security 5, the default behavior is for the xref:servlet/authentication/architecture.adoc#servlet-authentication-securitycontext[`SecurityContext`] to automatically be saved to the xref:servlet/authentication/persistence.adoc#securitycontextrepository[`SecurityContextRepository`] using the xref:servlet/authentication/persistence.adoc#securitycontextpersistencefilter[`SecurityContextPersistenceFilter`]. +Saving must be done just prior to the `HttpServletResponse` being committed and just before `SecurityContextPersistenceFilter`. +Unfortunately, automatic persistence of the `SecurityContext` can surprise users when it is done prior to the request completing (i.e. just prior to committing the `HttpServletResponse`). +It also is complex to keep track of the state to determine if a save is necessary causing unnecessary writes to the `SecurityContextRepository` (i.e. `HttpSession`) at times. + +In Spring Security 6, the default behavior is that the xref:servlet/authentication/persistence.adoc#securitycontextholderfilter[`SecurityContextHolderFilter`] will only read the `SecurityContext` from `SecurityContextRepository` and populate it in the `SecurityContextHolder`. +Users now must explicitly save the `SecurityContext` with the `SecurityContextRepository` if they want the `SecurityContext` to persist between requests. +This removes ambiguity and improves performance by only requiring writing to the `SecurityContextRepository` (i.e. `HttpSession`) when it is necessary. + +To opt into the new Spring Security 6 default, the following configuration can be used. + +include::partial$servlet/architecture/security-context-explicit.adoc[] + [[requestcache-query-optimization]] === Optimize Querying of `RequestCache` diff --git a/docs/modules/ROOT/pages/servlet/authentication/persistence.adoc b/docs/modules/ROOT/pages/servlet/authentication/persistence.adoc index 6d88332634..3f17e9b39a 100644 --- a/docs/modules/ROOT/pages/servlet/authentication/persistence.adoc +++ b/docs/modules/ROOT/pages/servlet/authentication/persistence.adoc @@ -144,29 +144,8 @@ image::{figures}/securitycontextholderfilter.png[] <1> Before running the rest of the application, `SecurityContextHolderFilter` loads the `SecurityContext` from the `SecurityContextRepository` and sets it on the `SecurityContextHolder`. <2> Next, the application is ran. -Unlike, xref:servlet/authentication/persistence.adoc#securitycontextpersistencefilter[`SecurityContextPersisteneFilter`], `SecurityContextHolderFilter` only loads the `SecurityContext` it does not save the `SecurityContext`. +Unlike, xref:servlet/authentication/persistence.adoc#securitycontextpersistencefilter[`SecurityContextPersistenceFilter`], `SecurityContextHolderFilter` only loads the `SecurityContext` it does not save the `SecurityContext`. This means that when using `SecurityContextHolderFilter`, it is required that the `SecurityContext` is explicitly saved. -.Explicit Saving of SecurityContext -==== -.Java -[source,java,role="primary"] ----- -public SecurityFilterChain filterChain(HttpSecurity http) { - http - // ... - .securityContext((securityContext) -> securityContext - .requireExplicitSave(true) - ); - return http.build(); -} ----- -.XML -[source,xml,role="secondary"] ----- - - - ----- -==== \ No newline at end of file +include::partial$servlet/architecture/security-context-explicit.adoc[] \ No newline at end of file diff --git a/docs/modules/ROOT/partials/servlet/architecture/security-context-explicit.adoc b/docs/modules/ROOT/partials/servlet/architecture/security-context-explicit.adoc new file mode 100644 index 0000000000..2f2179c614 --- /dev/null +++ b/docs/modules/ROOT/partials/servlet/architecture/security-context-explicit.adoc @@ -0,0 +1,76 @@ +.Explicit Saving of SecurityContext +==== +.Java +[source,java,role="primary"] +---- +public SecurityFilterChain filterChain(HttpSecurity http) { + http + // ... + .securityContext((securityContext) -> securityContext + .requireExplicitSave(true) + ); + return http.build(); +} +---- + +.Kotlin +[source,kotlin,role="secondary"] +---- +@Bean +open fun springSecurity(http: HttpSecurity): SecurityFilterChain { + http { + securityContext { + requireExplicitSave = true + } + } + return http.build() +} +---- + +.XML +[source,xml,role="secondary"] +---- + + + +---- +==== + + +Upon using the configuration, it is important that any code that sets the `SecurityContextHolder` with a `SecurityContext` also saves the `SecurityContext` to the `SecurityContextRepository` if it should be persisted between requests. + +For example, the following code: + +.Setting `SecurityContextHolder` with `SecurityContextPersistenceFilter` +==== +.Java +[source,java,role="primary"] +---- +SecurityContextHolder.setContext(securityContext); +---- + +.Kotlin +[source,kotlin,role="secondary"] +---- +SecurityContextHolder.setContext(securityContext) +---- +==== + +should be replaced with + +.Setting `SecurityContextHolder` with `SecurityContextHolderFilter` +==== +.Java +[source,java,role="primary"] +---- +SecurityContextHolder.setContext(securityContext); +securityContextRepository.saveContext(securityContext, httpServletRequest, httpServletResponse); +---- + +.Kotlin +[source,kotlin,role="secondary"] +---- +SecurityContextHolder.setContext(securityContext) +securityContextRepository.saveContext(securityContext, httpServletRequest, httpServletResponse) +---- +==== \ No newline at end of file