Where should I place validation code that requires access to database? - java

I have a Spring MVC webpage that is used for password resets. This requires us to do the following validation workflow:
provide username OR email
if email is provided make sure it is valid format (ex: #Email)
Check that User exists by:
3a) Trying to load the user from the database via username
3b) if loading by username returns null, try to load the user from the database via email
After loading, check that user is not locked out: user.isLocked()
Currently I have all of these Validations inside a org.springframework.validation.Validator
However this requires my Validator to have access to the UserService object so it can load users. This causes the user to be loaded 2x, once by my validator and a second time by my Controller so it can invoke .resetPassword(User).
Question: Where should I be checking item #3 ?
Are those validations better suited for the Controller ? If I leave validation as is, can I return the User from the Validator (it has void method due to Validator interface)?

In my opinion, steps 3 and 4 don't belong to view layer (in particular, to validation performed by controller) at all.
These steps are essential parts of business logic for this scenario, therefore they should be implemented in service layer.
Your service layer should provide a method such as
public void resetPasswordByUsernameOrEmail(String usernameOrEmail) { ... }
and these steps should happen inside this method, along with resetPassword(User).
If you need, you can make controller aware of result of this method by throwing an exception, returning a boolean or an enum (if you want to distinguish between different error conditions).

To answer your questions in order:
You should do the checking for a User's existence in the UserDao.
No, these validations should not be in the Controller. The Controller shouldn't know anything about validation, otherwise it would be trying too do to much and we'd be guilty of low cohesion.
Since you're using an interface that defines a method with a void return, if you wanted to return a User you would have to do one of the following:
Create your own method in your Validator implementation. The disadvantage of this is that you could not use polymorphism as effectively since you would depend on a method not defined in the Interface.
Make your own Validator (possibly make your own Interface that extends Spring's Validator interface and defines the method you want). This is probably what I would choose.

Maybe that's a duplicate: Spring MVC Bean Validation
Another solution would be this:
In one of the projects I worked, we used to have a SpringBeanUtil class. It would get the WebApplicationContext, and get the bean needed through a static method.
It's kind of ugly, but helped on these kind of problems.
Use at you own risk.
public class SpringBeanUtil implements ApplicationContextAware{
private static ApplicationContext APPLICATION_CONTEXT;
#Override
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
APPLICATION_CONTEXT=applicationContext;
}
public static Object getBean(String name){
return APPLICATION_CONTEXT.getBean(name);
}
public static <T> T getBean(Class<T> type){
return APPLICATION_CONTEXT.getBean(type);
}
}

Related

Difference between javax.security.enterprise.SecurityContext and javax.ws.rs.core.SecurityContext?

I am struggling to understand when and how to use the different interfaces.
They seem to be quite similar, with some minor differences in method names to dynamically check security roles or retrieve the Principal, but - as far as I am currently understanding - are only accessible in their specific context.
I am trying to implement fine grained authorization with specific requirements.
Mainly the roles are not stored in the tokens, but must be read from a table in the database.
Therefore I have an implementation of IdentityStore that provides a CallerPrincipal with all available roles.
The IdentityStore is used by my HttpAuthenticationMechanism implementation, which is fairly simple, thus all it does is for valid requests to call HttpMessageContext.notifyContainerAboutLogin to push the CallerPrincipal into the SecurityContext - as far as I know.
Because there are a lot of generic endpoints in the codebase with path parameters, that decide which role has to be checked I need a generic way of checking if the user is in a role depending on the value of some path segments of the requested uri.
I created a method interceptor for that, where I want to access the SecurityContext, but both interfaces have their problems here:
#Interceptor
public class RolesAllowedInterceptor {
#Context
private UriInfo uriInfo;
// this injection is always null
#Context
private javax.security.enterprise.SecurityContext securityContext;
// this injection works
#Context
private javax.ws.rs.core.SecurityContext securityContext;
#AroundInvoke
public Object validate(InvocationContext ctx) throws Exception {
... // read path param to retrieve role and check SecurityContext.isUserInRole()
}
}
The injection of javax.security.enterprise.SecurityContext does not work. I assume the reason for this is, that the interceptor is called in a JAX-RS context.
The injection of javax.ws.rs.core.SecurityContext works (my assumption in 1. is based on this). But when SecurityContext.isUserInRole(String) is called, the debugger shows, that the Principal does not have any of the groups (roles in my business context) that were assigned via my IdentityStore implementation and thus the validation incorrectly fails.
I am currently using another approach with ContainerRequestFilter to set the javax.ws.rs.core.SecurityContext explicitly, which is working fine for the interceptor, but not with the javax.annotation.security.RolesAllowed annotation. For that I shifted the invocation of my IdentityStore into the filter, because I obviously do not want to call it twice.
I am not looking for complete code examples/solutions.
I am merely trying to understand why there are different interfaces of SecurityContext, as the Java Docs do not elaborate on that.
And therefore hopefully understand how I can use RolesAllowed for static endpoints and my interceptor for generic endpoints, without the need of a ContainerRequestFilter to set the SecurityContext for the later.
--
For context: I am using Payara Micro and jakartaee-api:8.0.0

Spring MVC: What's the right way to register custom Validator in REST controller

I'm trying to make sense of how validation works in Spring. So far I've learned that there are two ways to perform validation of user input data:
JSR-303 validation based on javax.validation.constraints annotations. This validation is best suitable for simple object fields validation. But you can also implement your custom type level annotations to perform more complicated validation based on checking values of multiple fields.
Spring Validation based on org.springframework.validation.Validator interface. Seems to be better suited for more complicated validation.
If I want to use both these approaches, what is the right way to register my custom validator in controller?
This is what I'm trying to do.
My custom validator.
public class PasswordPairValidator implements Validator {
#Override
public boolean supports(Class<?> clazz) {
return PasswordPair.class.equals(clazz);
}
#Override
public void validate(Object target, Errors errors) {
PasswordPair password = (PasswordPair) target;
if (!password.getPassword().equals(password.getRepeatPassword())) {
errors.reject("passwordField", "passwords don't match");
}
}
}
My controller.
#RestController
#RequestMapping("/api/v1/users")
public class UserController {
#InitBinder
protected void initBinder(WebDataBinder binder) {
binder.addValidators(new PasswordPairValidator());
}
#RequestMapping(method = RequestMethod.POST)
public ResponseEntity<UserInfo> createUser(
#RequestBody #Valid UserInfo userInfo) {
userInfo.setId(123);
URI location = ServletUriComponentsBuilder.fromCurrentRequest()
.path("/{id}").buildAndExpand(userInfo.getId()).toUri();
return ResponseEntity.created(location).body(userInfo);
}
#RequestMapping(value = "/change_password", method = RequestMethod.POST)
public ResponseEntity<UserInfo> changePassword(
#RequestBody #Valid PasswordPair password) {
UserInfo user = new UserInfo("test#gmail.com", "testuser");
user.setId(123);
return ResponseEntity.ok().body(user);
}
}
When I call createUser endpoint the code fails with the following error:
ERROR c.e.testapp.controller.GlobalExceptionHandler - Internal Server Error
java.lang.IllegalStateException: Invalid target for Validator [com.example.testapp.validation.PasswordPairValidator#49acd001]: com.example.testapp.domain.UserInfo#cae4750
The problem apparently is that Spring tries to apply PasswordPairValidator to UserInfo object, which was not my intention.
Why Spring doesn't use validator's supports() method to check to which objects validator can be applied?
In a different stackoverflow question I found out that I need to specify value for #InitBinder annotation to make it work and the value should be "passwordPair". But what is this value as it's not the class name ("PasswordPair") or method parameters value ("password")?
The second question is if I want to add several validators do I need to define multiple #InitBinder("value") methods or is there a less cumbersome way to do it?
And the final question, maybe it's better to use annotation based validation for everything, to validate separate fields and implement type level custom annotations with ConstraintValidator to perform more complicated validation? It's a bit confusing what are the pros and cons of these approaches.
You have to provided an argument to your #InitBinder annotation.
Please refer this question
Above question also answers your other question on registering multiple validators.
I believe the reason this happens is because the #InitBinder method will be called every time a request is being processed and thus for all the methods you have that correspond to HTTP verbs.
The only way I know that you can limit the times the method annotated with #InitBinder gets called is by using the value argument that the annotation takes. I admit that I am also a bit confused on what that value is or how it is interpreted.
Spring boot uses supports to check if a validator can be used every time initBinder() gets called but will throw an exception when it doesn't fit. This happens when initBinder() get called when a Request is processed. So even if you have multiple validators from which one is valid for the request body it will fail
If someone could help with how we can correctly apply validators in Spring boot I would also appreciate it. In C# I know that you can register beans as in middleware and based on the class you register the validator with, the correct validator gets called. (I am not well versed in C# but this is what I remember). Isn't something like this also possible in Java?

How to do something after the login with Spring Security?

I have a Spring web application which uses Spring SAML and Spring Security to manage the login process.
Now I need to do some tasks after the correct login occurs. In particular I have to store some data in the SecurityContext.getContext() object.
I have never worked with Spring Security/SAML and I don't know how it manages the return from the IdP.
Is there any place in the code where usually you can put your code after the login process ends correctly?
I mean, I know where the redirect page is set but I cannot put my custom code in the Controller of this redirect page because that page is accessed more than one time, and I need to run my custom code only once at login time.
The best approach is to implement interface SAMLUserDetailsService, which will automatically store object you return from its loadUserBySAML method in the Authentication object which you can later query from the SecurityContext.getContext(). The interface is called once after each authentication. See the manual for details and examples.
The other possibility is AuthenticationSuccessHandler. The login process calls method onAuthenticationSuccess which has access to the Authentication object, which will be stored in the SecurityContext.getContext().
Simply create your own class which implements interface AuthenticationSuccessHandler (you can also extend some of the existing classes, such as SimpleUrlAuthenticationSuccessHandler or AbstractAuthenticationTargetUrlRequestHandler). Then plug your implementation to the securityContext.xml by changing class in the existing successRedirectHandler bean.
The problem is, that the Authentication object tends to be immutable - so the first way might be better.
You can use AuthenticationSuccessEvent. Just register a bean that implements ApplicationListener.
#Component
public class SomeSpringBean implements
ApplicationListener<AuthenticationSuccessEvent> {
public onApplicationEvent(AuthenticationSuccessEvent event) {
String userName = ((UserDetails) event.getAuthentication().
//do stuff
}
}
And you need to register AuthenticationEventPublisher.
Take a look here: https://gist.github.com/msarhan/10834401
If you use custom authentication provider, you can also plug whatever you want there.
Are you using Spring's Java configs?
If so, then you probably have a class that overrides WebSecurityConfigurerAdapter in your project. Extending this class gives you access to override the method configure(HttpSecurity http).
You can use that provided HttpSecurity builder object to configure a lot of things, one of which is the authentication success handler. More or less, you can create a simple that class that implements AuthenticationSuccessHandler (Spring has a few classes already built for extension to make this easy), and you can call http.successHandler(yourSuccessHandler) to register it with Spring Security.
Implementing that interface gives you the hook to put custom code into the onAuthenticationSuccess( ... ) method. I think they have one for failures as well.

Using Aspect Oriented Programming for user authentification in Java?

I like to add an user authentification to my REST webservice (Guice + Jersey).
I first wanted to solve the authentification with the Google Guice method interceptions. For example:
#Path("user")
public class User {
#OnlyAdmin
#Post
public void addUser(String apiKey) {
}
}
But unfortunately Guice only support AOP for classes with a no-argument constructors.
Is it generally a good idea to use AOP for user authentification?
Are there other frameworks to build an user authentification?
Edit: Framework is maybe the wrong term. I'm only looking for a way to inject some code in every annotated method and this code should check the parameters of the method
The only important point for AOP to work in your case is that your classes get created by Guice.
If you have constructors with arguments, ensure that they are injectable (directly or with assisted injection).
It wouldn't be AOP but you could inject a current user role bound to the request scope wherever the user needed to be checked and use either method intercepts or explicit logic to check that the right user class is performing some action.

A facade to hide authentication details from Java web service

I'm building an UI client that uses a service API that behind the scene uses Web services. One of the API services looks like this:
interface UserService {
List<User> findUsers(User loggedInUser, UserSearchParameters searchParameters, PagingParameters pagingParameters) throws AuthenticationFault, InvalidIndexFault;
void removeUser(User loggedInUser, User userToRemove) throws AutheticationFault;
void addUser(User loggedInUser, User newUser) throws AuthenticationFault;
}
The loggedInUser is the user on who's behalf the method is called. AuthenticationFault is a checked exception. There's like 20 of these service interfaces. What I would like to do is implement a facade that hides the loggedInUser parameters and AuthenticationFault exceptions. The facade implementation would call these methods with the user that is currently logged in the client.
I would also like to do some cleaning with the other checked exceptions too. As you can see there is a InvalidIndexFault exception that is thrown when client tries to retrieve page -1 but that is a programmer error and I don't want to have it as a checked exception.
Currently what I've done is always rethrow a RuntimeException for exceptions that I don't like, but if I later change my mind it's a lot of work changing that later. This also feels like code duplication. Other programmers have just swallowed exceptions and logged them which is totally horrible. Most of the time if there is an exception I want to bubble it up to error handler in the ui that displays an error.
There's been a few solutions that have come to my mind:
Java dynamic proxy
Code generation
I haven't gotten around to try out those solutions and figured I might as well ask here first. How do you suggest I would implement this? The environment is Java 6 and build tool is Maven 3 if that helps.
PS. If you answer this, please say more than "pick number 2" :) Any tips and other implementation details are welcome.
As a clarification retrieving the currently logged in user is not an issue so you don't have to help me with it. I currently hide it behind an interface and use IoC to inject it around. Behind the scenes it uses ThreadLocals
I guess this would be the perfect use case for
Java Dynamic Proxys
Thread locals
To elucidate:
First, create your Facade Interface :
interface UserServiceFacede {
List findUsers(UserSearchParameters searchParameters, PagingParameters pagingParameters) throws AuthenticationFault, InvalidIndexFault;
void removeUser(User userToRemove) throws AutheticationFault;
void addUser(User newUser) throws AuthenticationFault;
}
Next you implement your InvocationHandler :
public class UserHandler implements InvocationHandler{
private final UserService service;
public UserHandler(UserService service) {
this.service = service;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
....
// Based on the method argument, call the appropriate function on the actual service
// object
....
}
}
You then create the Proxy object like so :
UserServiceFacade uProxy = (UserServiceFacade)Proxy.newProxyInstance(UserHandler.class.getClassLoader(),
new Class[] { UserServiceFacade.class},
new UserHandler(userService));
The first argument is the classloader, the second is the list of interfaces the Proxy must confirm to and the third is the handler object
Now the question is how do you get a handle onto your loggedinUser. This is where ThreadLocal comes in.
Create a ThreadLocal static variable that holds the loggedin user. Then set the current user into the ThreadLocal before invoking the proxy
private static final ThreadLocal loggedinUser = ...;
...
...
loggedinUser.set(currentUser);
// Create a user Proxy object as mentioned above..
uProxy.findUser(searchParams, ..);
...
Retrieve the User from the ThreadLocal inside the invoke function of the handler. Now inside the handler, you have access to both the loggedinUser (using loggedinUser.get()) as well as the user service object (You have passed in the service object into your handler's constructor)
As far as how you handle exceptions are concerned, WHat I would do is generally keep throwing a subclass of RuntimeExceptions. Then catch these at the periphery layer of your app. By periphery layer I mean, entry point into your app/library. If you were developing a webbApp this would be your Servlet.

Categories

Resources