I have a requirement to get the details of the current user who has been loggedIn. To get the details, we can use the SecurityContextHolder.getContext()
and extract the details. According to,
SecurityContextHolder, SecurityContext and Authentication Objects
By default, the SecurityContextHolder
uses a ThreadLocal
to store these details, which means that the security context is always available to methods in the same thread of execution. 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
. Of course, Spring Security takes care of this for you automatically so there is no need to worry about it.
Storing the SecurityContext between requests
In Spring Security, the responsibility for storing the SecurityContext
between requests falls to the SecurityContextPersistenceFilter
, which by default stores the context as an HttpSession
attribute between HTTP requests. It restores the context to the SecurityContextHolder
for each request and, crucially, clears the SecurityContextHolder when the request completes
Many other types of applications (for example, a stateless RESTful web service) do not use HTTP sessions and will re-authenticate on every request. However, it is still important that the SecurityContextPersistenceFilter
is included in the chain to make sure that the SecurityContextHolder
is cleared after each request.
Question is
I required the user details at multiple places at the service layer to return the information based on the user authority, So we have one static method which returns these details. The project consists of REST APIs and session creation policy as SessionCreationPolicy.STATELESS
with SecurityContextHolderStrategy
as ThreadLocal
. The service layer consists of @Transactional
.
Now consider the multiple concurrent requests to the APIs,
- How Spring Security will manage
SecurityContextPersistenceFilter
for STATELESS applications, is manual configurations are required? - Is it okay to use
SecurityContextHolderStrategy
asThreadLocal
? - Are there any chances to get wrong/invalid user details due to the
ThreadLocal
strategy and static method?
Environment:
Framework: Spring Boot
ORM: Hibernate
Database: Postgres
Architecture: Monolithic (which is going to migrate to microservices)
I will add more details if required
UPDATE:
Thanks @Macro, as mentioned, for SessionCreationPolicy.STATELESS
,
SessionManagementConfigurer
consist of isStateless()
method which return true for stateless policy. Based on that http set the shared object with NullSecurityContextRepository
and for request cache NullRequestCache
. Hence no value will be available within HttpSessionSecurityContextRepository
. So there might not be issue with invalid/wrong details for user with static method
- Does
SecurityContextHolderStrategy
have any impact on the user details with MODE_INHERITABLETHREADLOCAL, MODE_THREADLOCAL as no value will be set to shared object withHttpSessionSecurityContextRepository
?
Code:
if (stateless) { http.setSharedObject(SecurityContextRepository.class, new NullSecurityContextRepository()); } if (stateless) { http.setSharedObject(RequestCache.class, new NullRequestCache()); }
Code:
static method to get user details
public static Optional<String> getCurrentUserLogin() { SecurityContext securityContext = SecurityContextHolder.getContext(); return Optional.ofNullable(extractPrincipal(securityContext.getAuthentication())); } private static String extractPrincipal(Authentication authentication) { if (authentication == null) { return null; } else if (authentication.getPrincipal() instanceof UserDetails) { UserDetails springSecurityUser = (UserDetails) authentication.getPrincipal(); return springSecurityUser.getUsername(); } else if (authentication.getPrincipal() instanceof String) { return (String) authentication.getPrincipal(); } return null; } public static Optional<Authentication> getAuthenticatedCurrentUser() { log.debug("Request to get authentication for current user"); SecurityContext securityContext = SecurityContextHolder.getContext(); return Optional.ofNullable(securityContext.getAuthentication()); }
sessionManagement
.sessionManagement() .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
Notes
SecurityContextHolderStrategy as ThreadLocal
The service layer consists of @Transactional
.
Advertisement
Answer
Setting
.sessionManagement() .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
will lead to Spring Security using a NullSecurityContextRepository
, instead of the default HttpSessionSecurityContextRepository
.
It is a simple implementation, in that it will simply not save anything to the HTTP Session and, for every request, create a completely new and empty SecurityContext
, hence with no stored authentication etc.
So, answering your first question:
SecurityContextPersistenceFilter will just work as with the HttpSessionRepository, there’s no other manual configuration required.
To answer your second and third question, regarding Threadlocals.
Yes, that’s the whole point of using them and it’s the default strategy anyway. So, every thread has its own SecurityContext / Authentication objects. You are accessing the ThreadLocal with your static method, hence there’s no chance of accessing “wrong” user details. It would be a problem to use the “GlocalSecurityContextHolderStrategy” in your use-case, but that’s not what you are doing, anyway.
Also, keep in mind that all of this has nothing to do with @Transactionals.