Cast object when authenticating on tests - spring

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.

Related

How does SecurityContextHolder.getContext().getAuthentication() work?

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.

Spring controller method invocation advice

I have a controller that exposes the following endpoint:
#RequestMapping("/all-users")
List<User> getAllUsers() {
...
}
I have also an annotation that helps me out with versioning of those endpoints, which ends up on something like this:
#RequestMapping("/all-users")
#Version(version=1, latests=LATEST_ALL_USERS)
List<User> getAllUsers() {
...
}
Now I want to introduce an additional standard behavior to all handlers mapped wish method contains #Version annotation which will simply wrap the response object into another object which contains the current version and latest version of the invoked method. Some information to build this object are provided by #PathVariable parameters. I'm trying to find a hook that allows me that but no luck so far.
I tried first to have a custom RequestResponseBodyMethodProcessor but if I add it will not take any effect because the original RequestResponseBodyMethodProcessor comes before and I don't want to remove the ResponseBody from my endpoints.
Afterward I tried to go for the mapping instead, once I cannot handle it on the processor, maybe I could handle that on mapping time introducing my code pre and post method invocation, but got stuck on the point where mapping is registered where a method object is needed, not allowing me to introduce my advice code.
Is there any way to get this done?
Edit:
Some of the information needed to build the new returned object are provided as #PathVariables, and are available on end-point method call.

Kotlin instance variable is null when accessed by Spring proxied class

I have a service class that is being proxied by Spring, like so:
#Service
#Transactional
open class MyService { ... }
If I remove the open modifier, Spring complains that it needs to proxy the class to apply the #Transactional annotation tweaks.
However, this is causing issues when calling a function on the proxied service, which attempts to access a variable:
#Service
#Transactional
open class MyService {
protected val internalVariable = ...
fun doWork() {
internalVariable.execute() // NullPointerException
}
}
The internalVariable is assigned as part of its declaration, does not have any annotations (like #Autowired, etc.), and works fine when I remove the #Transactional annotation and the requirement for Spring to proxy the class.
Why is this variable null when Spring is proxying/subclassing my service class?
I hit a similar issue and the above comments by Rafal G & Craig Otis helped me-- so I'd like to propose that the following write up be accepted as an answer (or the comments above be changed to an answer and they be accepted).
The solution: open the method/field.
(I hit a similar case where it was a closed method that caused the problem. But whether it is a field/method the solution is the same, and I think the general cause is the same...)
Explanation:
Why this is the solution is more complicated and definitely has to do with Spring AOP, final fields/methods, CGLIB proxies, and how Spring+CGLIB attempts to deal with final methods (or fields).
Spring uses proxies to represent certain objects to handle certain concerns dealt with by Aspect Oriented Programming. This happens with services & controllers (especially when #Transactional or other advice is given that requires AOP solutions).
So a Proxy/Wrapper is needed with these beans, and Spring has 2 choices-- but only CGLIB is available when the parent class is not an interface.
When using CGLIB to proxy classes Spring will create a subclass called
something like myService$EnhancerByCGLIB. This enhanced class will
override some if not all of your business methods to apply
cross-cutting concerns around your actual code.
Here comes the real surprise. This extra subclass does not call super
methods of the base class. Instead it creates second instance of
myService and delegates to it. This means you have two objects now:
your real object and CGLIB enhanced object pointing to (wrapping) it.
From: spring singleton bean fields are not populated
Referenced By: Spring AOP CGLIB proxy's field is null
In Kotlin, classes & methods are final unless explicitly opened.
The magic of how Spring/CGLib when & how chooses to wrap a Bean in an EnhancerByCGLIB with a target delegate (so that it can use finalized methods/fields) I don't know. For my case, however the debugger showed me the 2 different structures. When the parent methods are open, it does not create a delegate (using subclassing instead) and works without NPE. However, when a particular methods is closed then for that closed method Spring/CGLIB uses a wrapped object with delegation to a properly initialized target delegate. For some reason, the actual invocation of the method is done with the context being the wrapper with its uninitialized field values (NULLs), causing NPE. (Had the method on the actual target/delegate been called, there should not have been a problem).
Craig was able to solve the problem by opening the property (not the method)-- which I suspect had a similar effect of allowing Spring/CGLib to either not use a delegate, or to somehow use the delegate correctly.

Spring: new() operator and autowired together

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.

Spring - Best approach to provide specific error messages in a validator from a DAO?

What is the best way to implement a validator in Spring that accesses a DAO object but needs to return different error messages based on the DAO error? Should the DAO method throw different exceptions that the validator turns into proper error messages? Should the DAO return an enumeration so the validator can handle each return type separately if necessary? I suppose the validator can pass the org.springframework.validation.Errors object to the DAO, but that seems to tie the two classes too closely together.
I believe the best approach is the enumeration approach to avoid the overhead of exceptions. Is there another way I should be considering?
Update
Actually, the enumeration would probably have to be a reference passed into the DAO as that method had to return the actual object. Is this still the best approach?
Update 2
The issue is I need to retrieve information from the database in this particular case, not store it. In the validation class, I was checking if the value already exists (which is why it needed the DAO), and if it already exists that is an error that I would show to the user on the page. I do need to validate that all fields on the form were filled in, so maybe that's the only thing I use the validator for. Then, how do I handle the error where the value already exists in the database? The DAO is the only thing that will know that - what is the best way to communicate that error from the DAO to the web layer?
The DAO method is currently returning the user object it is retrieving from the database - I can return null if there is an error, but that doesn't give me any granularity into the error details - it's essentially a boolean at that point indicating if the record was found or not, but not why.
Validator accessing DAO is valid.
I Would suggest throwing exception over passing enumeration.
If given one more option I would suggest not throwing exception but returning null.
You may design your DAO methods in such a way that they would return the populated object if available, if not just returns null.
Take following example:
DAO layer :
class UserInfoProvider {
public void createUser(User user) throws UserCreationException {
// throws UserCreationException when something goes wrong while updating database
}
public User findUser(String username) {
// return user object if found
// else just return null
}
}
Validation :
class UserValidator {
public void validate(command, errors) {
String username = command.getUsername();
UserInfoProvider userInfoProvider;
User user = userInfoProvider.findUser(username);
if (user == null) {
errors.rejectValue("username","User not found");
return;
}
}
}
You might consider using Spring security when you are using Spring MVC.
I suppose the validator can pass the org.springframework.validation.Errors object to the DAO, but that seems to tie the two classes too closely together.
I'm not understanding this. Why would you pass Errors to the DAO?
The point of validation is to prevent bad data from ever getting within sniffing distance of your database. You should be sending a response back to the source of the request informing them about any Errors you've encountered.
The only reason I can think of for passing such a thing to a database would be to track requests and responses as an auditing/tracking function.
If there are errors, the use case is done. The user needs to be informed, not your database.
UPDATE:
If you're checking something like a username that has to be unique in a database, by all means do that check. But I'd do it as an AJAX call, as soon as it was entered, and if it already existed I'd simply tell the user so.
DAO should not know about web tiers. Bad design - too coupled.
Let the web tier inquire through an intermediary. The intermediary will make the query and send back the appropriate result. Your web page should have a controller and/or service of some kind that can be that intermediary.
Checking the database in your validator is a valid thing to do.
I am a bit confused about what sort of errors you are expecting your DAO to return though. Typically it will either return the requested object or NULL, and it is up to the caller (your validator) to know the reason why.
If you need to check that multiple fields don't already exist in the database, then just make multiple DAO calls.

Resources