In my spring-3 application I have an AuthenticationInterceptor (which is basically an interceptor) that checks for the privileges for a user. I am using a Spring's MultipartResolver to try an upload a file to the server.
The problem that I now face is that I wish to perform different actions based on user privileges, in case of a MaxUploadSizeExceededException.
However I see that this exception is occurring at the DispatcherServlet level and is caught by HandlerExceptionResolver
I want to be able to call my AuthenticationInterceptor before any of this happens?
Is there a straightforward way.
The problem is that the exception occurs BEFORE the request is dispatched to a controller and because of that, your interceptor also never fires. I guess you have that part figured out already.
Want to get around that...
For starters, I would move the authentication mechanism out IN FRONT of the servlet by using servlet filters. This being said, it makes little or no sense to roll your own solution in that space when a great product like Spring Security can do that for you.
Once you transition to Spring Security (or similar), the user's SecurityContext (roles, permissions, etc.) will have been resolved by the time the exception occurs and is caught.
Now, if I'm reading your question correctly, it seems you might like to respond to the exception differently based on the user's roles, permissions, etc. That should be possible at this point. You'd implement a custom HandlerExceptionResolver that inspects the SecurityContext to see if the user has a certain role or permission and then respond accordingly.
Hope that helps!
There are two basic ways to handle doing something in-stream before the Handler code gets called:
Implement the HandlerInterceptor interface, and code the code you want to run in the preHandle method
Create an Aspect using #Aspect and configure a pointcut to run #Before the method call
In either case, you could check the logged-in user's Roles using SecurityContextHolder.getContext().getAuthentication().getAuthorities() and then decide what to do based on Role membership.
Related
I am currently coding a spring-mvc (jsp) project with three layers (controller -> service -> dao) and I am wondering what is the correct way of handling expected exceptions from dao invocations (e.g trying to persist an User that already exists, if it exists then call the register view again with a message saying that the user already exists), at first I thought it would be a good idea to catch the exception in the dao (e.g DataIntegrityViolationException) and throw my arbitrary checked exception so then I can do an exception handler for it in the controller but I fear if I do this then I might have conflicts if I want to make my service methods #Transactional later on since spring won't know how to rollback the transaction.
If this is correct then I have two ideas:
try/catch DataAccessException in the controller when I invoke the service call userService.register(..)
Use something among the lines like userService.findByUsername(username) in the controller (which returns an Optional) and if its present I notify the user before even calling userService.register(..)
Also, our teacher emphasizes on following DDD behavior and trying to avoid leaking business logic in our controllers and I fear both of this solutions do that but I don't really know how to handle it otherwise.
Spring already converts checked JDBC exceptions into more informative unchecked exceptions, which play well with service layer transactions. All your custom checked exceptions do is force you to type more. Spring gives you reasonable defaults, take advantage of them.
Create an exception handler. Spring has multiple ways to implement this, none of them involve writing catch blocks for exceptions in your controller.
Put the business logic in the service, not the controller. It seems like your findByUsername and register can be combined in one transactional service method.
I am creating a Spring Boot web application, but i am confused why people use Global Exception handlers(#ControllerAdvice) when there is Error Page Registrar which is neater and more explicit. Please can someone explain more and is it possible to call an Error page registrar from a global Exception Handler Class( class annoted with #ControllerAdvice, with an #Exceptionhandler method).
As Brian answer, I think you can do this. I got a sample to prove this one in here if you still need to refer: https://github.com/kennytai/SampleSpringbootExceptionHandler
At this sample, I use the #ControllerAdvice in class GlobalExceptionHandler to manage all exceptions from TestController.
Hope this help.
It's actually the opposite the error pages mechanism in Spring Boot is the global one; it's catching all exceptions unhandled by the application. Note that in a Servlet environment, it's even dispatching the request back into the container on the /error path.
You're right though, this mechanism is really powerful and you can achieve a lot with it.
The other exception handling mechanisms you're mentioning are provided by Spring MVC itself. They're executed during the handling of the request and don't require an additional dispatch to the container. In some cases, they can be more limited because they offer less features than the full ErrorController (which is an MVC Controller).
But unlike error pages, you can configure those to focus on only specific errors:
You can declare an #ExceptionHandler within a Controller and specify the type of Exception you'd like to handle
You can configure the #ControllerAdvice annotation to only apply to specific packages, Controllers extending a specific interface or annotated with a specific annotation
I'd say the latter are quite useful when you want to deal with business exceptions at the controller level. You can do that with error pages, but you might end up with a single error controller dealing with too many things.
When i am trying to use #PreAuthorize("#accessControl.hasActivity('abc')") on spring controller method i am getting Authentication object was not found in security context.
After debugging found that DispactcherServlet is throwing this exception.
i have set SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_THREADLOCAL);
when i first create Authentication object and set in security context
Also tried with SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_INHERITABLETHREADLOCAL); but no luck still it does not work.
I am not able to understand why spring is servlet is throwing this exception
First, doing authentication in a Spring MVC interceptor is odd. Consider using a filter before DispatcherServlet. There is a lot of documented examples.
Secondly, SecurityContextHolder.setStrategyName re-initializes the strategy and possibly makes all previously authentications inaccessible so you must only call it once (if any time), before any authentication is made.
Thirdly, if you want to set the current authentication to be used by #PreAuthorize and are sure what you are doing, use SecurityContextHolder.getContext().setAuthentication(anAuthentication);. In most cases, there is a suitable filter in the API that already does this for you.
I have a simple auditing requirement for my JPA entities : keep the creation and last modification date and author. The author should be the currently logged-in user.
I would like to implement this using #PrePersist and #PreUpdate annotations on a base class, or a JPA interceptor (no additional framework).
However, in both cases, I need a way to access the currently logged in user, which is stored in the HttpSession.
How can I access this information from a method on my base entity class or from a JPA interceptor ?
Is there any best practice or any tested method on how to achieve that ?
I was thinking, maybe add a web interceptor that, for each request, puts the logged-in user object into a globally reachable ThreadLocal (e.g. inside a Spring singleton service), which would make it possible to look it up from anywhere...
Does that sound like a good idea ?
Any suggestion welcome !
Edit: found similar question here (found it only after posting my own through suggestions on the right) : Setting createdBy and updatedBy in JPA entities automatically
The conclusion seems to go in the direction of ThreadLocal... still, any feedback welcome !
If you do not use remote (EJB) calls then the idea to use ThreadLocal should work, as most containers use one thread for each request processed. You need to be careful when you put the user and when you delete it, as the container probably uses a thread pool and you don't want to leave the user object attached to a thread that might be used to process another request.
I've been doing some comparisons between Apache Shiro and Spring Security - I'm really loving the security model that Shiro uses and believe it to be far cleaner that Spring Security.
However, one big nice-to-have would be to be able to reference method parameters from within the method-level security annotations. For example, right now I could so something like:
#RequiresPermissions("account:send:*")
public void sendEmail( EmailAccount account, String to, String subject, String message) { ... }
Within the context of this example, this means that the authenticated user must have the permission to send emails on email accounts.
However, this is not fine-grained enough, as I want instance level permissions! In this context, assume that users can have permissions on instances of email accounts. So, I'd like to write the previous code something like this:
#RequiresPermissions("account:send:${account.id}")
public void sendEmail( EmailAccount account, String to, String subject, String message) { ... }
In this way, the permission string is referencing a parameter passed into the method such that the method can be secured against a particular instance of EmailAccount.
I know I could easily do this from plain Java code within the method, but it would be great to achieve the same thing using annotations - I know Spring Security supports Spring EL expressions in its annotations.
Is this definitely not a feature of Shiro and thus will I have to write my own custom annotations?
Thanks,
Andrew
Look at the classes in http://shiro.apache.org/static/current/apidocs/org/apache/shiro/authz/aop/package-summary.html, especially PermissionAnnotationHandler. There you can see that all Shiro does when encountering the #RequiresPermissions annotation is call getSubject().isPermitted(permission) and does no substitution inside the annotation value at all. You would have to somehow override that handler if you wanted this kind of functionality.
So to answer your question: yes, this is definitely not a feature of Shiro and you have to either write your own annotation or somehow override that handler.
This feature is currently not supported by Shiro. Multiple people have requested this feature. Perhaps we can vote for the issue?
https://issues.apache.org/jira/browse/SHIRO-484
https://issues.apache.org/jira/browse/SHIRO-77
https://issues.apache.org/jira/browse/SHIRO-417
https://issues.apache.org/jira/browse/SHIRO-331