SecurityContextHolder.getContext().getAuthentication() obtains the currently authenticated principal, or an authentication request token, but in which context should we use it? Is it thread safe? For example, if we use a static helper method like:
public static UserEntity getCurrentUser() {
return (UserEntity)SecurityContextHolder.getContext().getAuthentication().getPrincipal();
}
Will it be safe to use? Or should we only use it under request scoped bean?
From Spring Security Document:
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. Spring
Security’s FilterChainProxy ensures that the SecurityContext is always
cleared.
As per this blog :
The Java ThreadLocal class enables you to create variables that can
only be read and written by the same thread. Thus, even if two threads
are executing the same code, and the code has a reference to the same
ThreadLocal variable, the two threads cannot see each other's
ThreadLocal variables. Thus, the Java ThreadLocal class provides a
simple way to make code thread safe that would not otherwise be so.
Putting these together answers the question that is it safe to have a static util method to get the currently logged in user from SecurityContextHolder, Which is, yes it is safe.
Related
Please note: someone seems to be serially DVing my questions without explanation. This question is on topic, is not a duplicate, shows research and provides an SSCCE. If you wish to DV or CV it, that's fine, but please provide a comment as to why so I can have a chance to address your concerns...
Spring Boot 2.3.x and Spring Security here.
I have some pretty complicated authorization logic, and so I believe I need to write my own AccessDecisionManager impl and wire it into my WebSecurityConfigurerAdapter impl (if that's wrong or misunderstood in any way, please correct me!).
So then, to implement your own AccessDecisionManager you need to implement 3 methods, one of which is:
public class MyCustomAccessDecisionManager implements AccessDecisionManager {
#Override
public void decide(
Authentication authentication,
Object object,
Collection<ConfigAttribute> configAttributes) throws AccessDeniedException, InsufficientAuthenticationException {
// TODO
}
}
I have scoured the Google Gods high and low, and for the life of me I cannot find a meaningful, real world example of what the Object object and Collection<ConfigAttribute> configAttributes arguments are, what they are used for, how they are intended on being used, and what some real world (concrete) examples of them will be at runtime.
The Authentication argument is obvious: it is my auth token and will contain the principal, possibly their credential, and a list of GrantedAuthorities (permissions) associated with the principal.
But the other two arguments (object and configAttributes ) are absolute mysteries to me.
Does anybody know what these arguments are, what some real world use cases of them are, and how they are intended to be used?
As JavaDoc for AccessDecisionManager says:
object – the secured object being called
Usually, it's an instance of the MethodInvocation interface and it represents the method for which call security decision should be performed.
configAttributes - the configuration attributes associated with the secured object being invoked
It's a collection of metadata attributes related to the security object (Method). For example, it can contain information about annotations related to this method, such as #PermitAll, #PreAuthorize, #PostFilter, etc.
I am creating a String based on some input parameters when a rest call is executed. I have created my own Annotation to intercept certain methods which will be called later on (within the same request). The Interceptor needs to know the String created at the beginning. My initial thought was to add the String into the Spring context like this:
ConfigurableListableBeanFactory beanFactory = ((ConfigurableApplicationContext) context).getBeanFactory();
beanFactory.registerSingleton("myValue", "generatedString");
And just inject it to the interceptor. However i can only add it once this way and i really dont want it to be a singleton. Each request has its own "generatedString". I could not find a suitable way of solving this. What i actually want is to register an object on runtime for the current thread so i can inject it later on. When the Thread is done it should disappear.
If I use Spring, which of these two methods is more correct.
Can I use the new() operator even if I use dipendency injection?.Can I mix both?
I would like to have some clarification on these concepts.
Thanks
First method:
#RequestMapping(method=RequestMethod.GET)
public String create(Model model){
model.addAttribute(new User());
return "index";
}
Second Method:
#Autowired
User user;
#RequestMapping(method=RequestMethod.GET)
public String create(Model model){
model.addAttribute(user);
return "index";
}
By using dependency injection does not mean that the use of new operator is automatically prohibited throughout your code. It's just different approaches applied to different requirements.
A web application in spring is composed of a number of collaborating beans that are instantiated by the framework and (unless overriding the default scope) are singletons. This means that they must not preserve any state since they are shared across all requests (threads). In other words if you autowire the User object (or any other model attribute), it is created on application context initialization and the same instance is given to any user request. This also means that if a request modifies the object, other requests will see the modification as well. Needless to say this is erroneous behavior in multithreaded applications because your User object (or other model attribute) belongs to the request, so it must have the very narrow scope of a method invocation, or session at most.
You can also have spring create beans with different scopes for you, but for a simple scenario of a model attribute initialization, the new operator is sufficient. See the following documentation if interested in bean scopes : Bean scopes
So in your use case, the second method is totally wrong.
But you can also delegate the creation of your model attributes to spring if they are used as command objects (i.e. if you want to bind request parameters to them). Just add it in the method signature (with or without the modelattribute annotation).
So you may also write the above code as
#RequestMapping(method=RequestMethod.GET)
public String create(#ModelAttribute User user){
return "index";
}
see also : Supported method argument types
If you want your beans to be "managed" by Spring (for e.g. to use with Dependency Injection or PropertySources or any other Spring-related functionality), then you do NOT create new objects on your own. You declare them (via XML or JavaConfig) and let Spring create and manage them.
If the beans don't need to be "managed" by Spring, you can create a new instance using new operator.
In your case, is this particular object - User - used anywhere else in code? Is it being injected into any other Spring bean? Or is any other Spring bean being injected in User? How about any other Spring-based functionality?
If the answer to all these questions is "No", then you can use the first method (create a new object and return it). As soon as the create() method execution is complete, the User object created there would go out of scope and will be marked for GC. The User object created in this method will eventually be GC-ed.
Things can be injected in two ways in a Spring MVC applications. And yes, you can you can mix injection and creation if doing right.
Components like the controller in your example are singletons managed by the application context. If you inject anything to them it is global, not per request or session! So a user is not the right thing to inject, a user directory can be. Be aware of this as you are writing a multithreaded application!
Request related things can be injected to the method like the used locale, the request, the user principal may be injected as parameters, see a full list at Spring MVC Documentation.
But if you create a model attribute you may use new() to create it from scratch. I will not be filled by spring but to be used by your view to display data created by the controller. When created in the request mapped method that is ok.
I have following method in my Spring application
public static String getCurrentUserStudentId() {
return ((LdapPerson) SecurityContextHolder.getContext().getAuthentication().getPrincipal()).getID();
}
This works on the application run, but when I run a test calling this method, it gives
org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken cannot be cast to fi.utu.security.ldap.userdetails.LdapPerson
I'm not that familiar with Spring Security to give all the files this could be related, but ask me. I hope someone can tell what to do with this.
SecurityContextHolder keeps a reference to a "strategy" in a static variable which means that this detail leaks from test to test.
You have several options:
In your test, set the correct strategy using one of the setters of SecurityContextHolder
Create a mock implementation for getCurrentUserStudentId which returns a fixed result for the test.
Put the code to get the current user id into a bean and inject that instead of calling SecurityContextHolder. Implement two versions of this bean: One which calls SecurityContextHolder and another which returns a string.
I am using Spring 3 AOP, and I have an aspect that requires access to the HttpServletRequest. It looks something like this:
#Aspect
public class MyAspect {
#Autowired
private HttpServletRequest httpServletRequest;
public void init() {
// Do something once...
}
#Before("my pointcut here...")
private void myMethod() {
// I need the httpServletRequest...
}
#After("my pointcut here...")
private void myOtherMethod() {
// I need the httpServletRequest...
}
}
And is configured like this:
<bean id="myAspect" class="com.some.package.MyAspect" init-method="init" />
Is the init method only called once per IoC container, even though this is an aspect, and is the httpServletRequest thread safe? If it is not, what is the best way to get at it during execution of the advice and have it be thread safe? If at all possible I prefer not to use a thread local.
Is the init method only called once per IoC container
It is called once per every bean instance. If bean has a singleton scope (which is the default case for aspects as well), it will only be called once. However you won't have access to the httpServletRequest inside init() method - there is no request yet!
is the httpServletRequest thread safe
It is not but don't worry. This is actually much more complex than it looks like. You are injecting HTTP servlet request (and obviously there can be several requests available at the same time) into a singleton object. Which one is injected? None (all?) of them! Spring creates some sophisticated proxy (called scoped proxy) and every time you access methods of injected httpServletRequest it delegates them to current (to thread) request. This way you can safely run your aspects in several threads - each will operate on a different physical request.
This whole behaviour is described in great details in 4.5.4.5 Scoped beans as dependencies:
[...] If you want to inject (for example) an HTTP request scoped bean into another bean, you must inject an AOP proxy in place of the scoped bean. That is, you need to inject a proxy object that exposes the same public interface as the scoped object but that can also retrieve the real, target object from the relevant scope (for example, an HTTP request) and delegate method calls onto the real object.
About ThreadLocal:
I prefer not to use a thread local.
Fortunately - Spring is using one for you. If you understand how ThreadLocal works - Spring puts current request into a thread local and delegates to thread-local instance when you access httpServletRequest proxy.