From 702cc1d2bba263ea5d2a3a78f274e5bcbd5d5d8a Mon Sep 17 00:00:00 2001 From: Rob Winch Date: Thu, 20 Feb 2020 14:51:32 -0600 Subject: [PATCH] Extract SecurityContextHolder Docs Issue gh-8005 --- .../architecture/security-context-holder.adoc | 67 +++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 docs/manual/src/docs/asciidoc/_includes/servlet/authentication/architecture/security-context-holder.adoc diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/architecture/security-context-holder.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/architecture/security-context-holder.adoc new file mode 100644 index 0000000000..a24ef96921 --- /dev/null +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/architecture/security-context-holder.adoc @@ -0,0 +1,67 @@ +[[servlet-authentication-securitycontextholder]] += SecurityContextHolder + +:figures: images/servlet/authentication/architecture + +At the heart of Spring Security's authentication model is the `SecurityContextHolder`. +It contains the <>. + +image::{figures}/securitycontextholder.png[] + +The `SecurityContextHolder` is where Spring Security stores the details of who is <>. +Spring Security does not care how the `SecurityContextHolder` is populated. +If it contains a value, then it is used as the currently authenticated user. + +The simplest way to indicate a user is authenticated is to set the `SecurityContextHolder` directly. + +.Setting `SecurityContextHolder` +==== +[source,java] +---- +SecurityContext context = SecurityContextHolder.createEmptyContext(); // <1> +Authentication authentication = + new TestingAuthenticationToken("username", "password", "ROLE_USER"); // <2> +context.setAuthentication(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. +Spring Security does not care what type of `Authentication` implementation is set on the `SecurityContext`. +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 <>. + +If you wish to obtain information about the authenticated principal, you can do so by accessing the `SecurityContextHolder`. + +.Access Currently Authenticated User +==== +[source,java] +---- +SecurityContext context = SecurityContextHolder.getContext(); +Authentication authentication = context.getAuthentication(); +String username = authentication.getName(); +Object principal = authentication.getPrincipal(); +Collection authorities = authentication.getAuthorities(); +---- +==== + +// FIXME: add links to 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 of execution, 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. +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. +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. +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 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.