Handling addtional exceptions and throwing custom error message in Spring security - spring

I am using Spring 2.5 .I want to do the following:
In the overriden loadUserByUsername method of spring UserDetailsService I want to throw a custom exception and on that exception give a custom error message on the login page.
Could anyone suggest how can I handle this custom exception.

You can extend AbstractHandlerExceptionResolver and handle your exception in this class. Code is not full, but you can understand the idea from that part.
public class ExceptionResolver extends AbstractHandlerExceptionResolver {
#Override
protected ModelAndView doResolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
ModelAndView mav;
if(ex instanceof YourException){
mav = loginController.showLoginPage();
mav.addObject("errorMessage","Some error message text.");
\\also you can change response code here or add some logic
}
else {
\\some another page
}
return mav;
}
Also add this to applicationContext.xml(or another file with your spring context configuration):
<bean class="com.mycompany.ExceptionResolver" />

Related

Http status code from a global #ExceptionHandler with the #ControllerAdvice annotation

I'm implementing a global exception handler inside a Spring Boot App, with the #ControllerAdvice annotation, and I'd like to know, how could I get the http status code for showing a different message when it's 404 and to persist a log with the error, in other cases.
This is a simplified version of the code:
#ControllerAdvice
public class GlobalExceptionHandler {
#ExceptionHandler(RuntimeException.class)
public ModelAndView handleException(Exception ex, HttpServletRequest request, HttpServletResponse response) {
...
ModelAndView model = new ModelAndView();
model.addObject("message", ex.getMessage());
model.addObject("trace", trace);
model.addObject("path", path);
//model.addObject("status", response.getStatus());
model.setViewName("error");
return model;
}
I've tried this approach, without success:
Object status = request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE);
Integer statusCode = Integer.valueOf(status.toString());
To get the request attribute, this other name; javax.servlet.error.status_code doesn't work either.
You have to set your own status code corresponding every exception that you are handling. If any exception missed, default will be 5.x.x server error.
I remember doing this by extracting the expected exception to a separate class that extends Exception.
By doing this, you can add #ResponseStatus to set your required status code.
This custom exception can be thrown in your controller needed.
#ResponseStatus(value=HttpStatus.NOT_FOUND, reason="Person Not Found")
public class PersonNotFoundException extends Exception {
public PersonNotFoundException (int id){
super("PersonNotFoundException with id="+id);
}
}
Instead of specifying the generic RunTime exception, handle the PersonNotFoundException in your #ExceptionHandler and add the exception object to your ModelAndView.

#ControllerAdvice handler not being called from Spring Cloud custom filter

I have created the following custom filter to be used for authorization in a Spring Cloud application. Here is the apply() method from that filter, from which an exception is thrown should the authorization check fail:
#Override
public GatewayFilter apply(Config config) {
return (exchange, chain) -> {
HttpStatus status = HttpStatus.FORBIDDEN;
try {
String authRequest = exchange.getRequest().getHeaders().getFirst(
Constants.SESSION_HEADER_NAME);
HttpHeaders headers = new HttpHeaders();
HttpEntity<String> entity = new HttpEntity<String>(authRequest, headers);
// make REST call to authorization module
status = restTemplate.postForEntity(authURL, entity, String.class).getStatusCode();
}
catch (Exception e) {
LOGGER.error("Something went wrong during authorization", e);
}
// throw an exception if anything went
// wrong with authorization
if (!HttpStatus.OK.equals(status)) {
throw new ResponseStatusException(HttpStatus.FORBIDDEN);
}
return chain.filter(exchange);
};
}
I have defined the following #ControllerAdvice class to catch all exceptions thrown by the above Gateway Cloud filter:
#ControllerAdvice
public class RestExceptionHandler {
#ExceptionHandler(value = ResponseStatusException.class)
public final ResponseEntity<Object> handleException(ResponseStatusException ex) {
return new ResponseEntity<>("UNAUTHORIZED", HttpStatus.FORBIDDEN);
}
}
What I currently observe is the following:
The above custom filter's ResponseStatusException is not being caught by the #ControllerAdvice mapping method.
Yet, throwing this exception from elsewhere in the Spring Boot application, e.g. the regular controller we use as an authentication endpoint, is caught by the #ControllerAdvice method.
For now, this is more of a nuisance than a blocker, because in fact throwing a ResponseStatusException from the Cloud filter with a custom error code in fact does return that error code to the caller. But, it would be nice to handle all exceptions in a single place.
Can anyone shed some light on this problem?
From ControllerAdvice javadocs:
Classes with #ControllerAdvice can be declared explicitly as Spring beans or auto-detected via classpath scanning.
You didn't show full class for your filter, but I bet it isn't Spring Bean scanned on classpath. Typically servlet filters are explicitly plugged into Spring Security configuration. Therefore ControllerAdvice processing is ignoring it.
I assume that by Filter you mean javax.servlet.Filter.
In that case, #ControllerAdvice cannot work. It is used to handle exceptions from Controllers. But you throw Exception before it can even propagate to Controller (by not calling the chain.filter(exchange) method.
Try throwing exceptions in controller, not in filter.
Edit: If you don't want to handle exceptions on #Controller, you must implement terminal handler in javax.servlet.Filter directly. That means change the incoming request' response directly like this:
HttpServletResponse httpResponse = (HttpServletResponse) exchange.getResponse();
// either format the response by yourself
httpResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
httpResponse.setHeader(...)
...
// or let populate error directly
httpResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED);
... which is something what #ControllerAdvice does internally.

Spring MVC handling exceptions

I've built a spring mvc application using the controller->service->dao architecture. The DAO objects are using hibernate. The services are annotated #Transactional.
I'm trying to catch dao exceptions in the service, wrap them up and then throw them to my controller:
Service
#Override
public Entity createEntity(Entity ent) throws ServiceException {
try {
return entityDAO.createEntity(ent);
} catch (DataAccessException dae) {
LOG.error("Unable to create entity", dae);
throw new ServiceException("We were unable to create the entity for the moment. Please try again later.", dae);
}
}
Controller
#RequestMapping(value = "/create", method = RequestMethod.POST)
public String createEntity(#ModelAttribute(value = "newEntity") Entity newEntity, RedirectAttributes redirectAttributes) {
try {
entityService.createEntity(newEntity);
} catch (ServiceException se) {
redirectAttributes.addFlashAttribute("error", se.getMessage());
}
}
return "redirect:/entity/manage";
}
However, even though the DataAccessException is caught at the service level, it keeps bubbling up to my controller somehow.
If for example I don't meet a unique field criteria on the database level I get an HTTP Error 500 with the following:
org.hibernate.AssertionFailure: null id in com.garmin.pto.domain.Entity entry (don't flush the Session after an exception occurs)
Code is caching DataAccessException not HibernateException, try caching HibernateException
Is there a way to translate HibernateException to something else, then DataAccessException in sping
If you want to handle the exception in the Controller, don't catch it in the Service.
Service
#Override
public Entity createEntity(Entity ent) throws DataAccessException {
return entityDAO.createEntity(ent);
}
Controller
#RequestMapping(value = "/create", method = RequestMethod.POST)
public String createEntity(#ModelAttribute(value = "newEntity") Entity newEntity, RedirectAttributes redirectAttributes) {
try {
entityService.createEntity(newEntity);
} catch (DataAccessException e) {
redirectAttributes.addFlashAttribute("error", e.getMessage());
}
return "redirect:/entity/manage";
}
Or if you want to leverage Spring the handle the exception, use ExceptionHandler annotation. You can find good tutorial online, for example, Spring MVC #ExceptionHandler Example.
To make exception translation working
You have to annotate your DAO with #Repository
Make sure you have declared this bean <bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor" />
Here is a beautiful post on different ways to handle exceptions on a Spring MVC project.
Among those, I find using #ControllerAdvice classes, to handle all the exceptions at one place globally, the most convenient in general. Spring Lemon's source code could serve as a good concrete example.

How does spring handle exceptions in MVC

Spring MVC exception handle
In my opinion there are different kinds of exceptions in a Spring MVC application.
For example, the service or dao layer may throw exceptions once errors occured. Or the spring itself may throw exceptions if it can not find a right handler to handle the request.
And now I try to use the ControllerAdvice to handle the exceptions:
#ControllerAdvice
public class GlobalExceptionHandler {
private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);
#ExceptionHandler(Exception.class)
public ModelAndView myError(Exception exception) {
log.error(exception.getMessage());
ModelAndView mav = new ModelAndView();
mav.addObject("exception", exception);
mav.setViewName("error");
return mav;
}
}
However once I visit a wrong page, I will get the 404 error page from tomcat, rather than the error view defined in the ControllerAdvice.
So how did spring handle the exceptions?
I Think you rather put the error page in Web.xml, whenever you will visit the wrong page it will be redirected to this error page. Also this is less cumbersome and easy to manage.
Does this answers your question

How can I bypass Grails exception handling, in order to use Spring Oauth2?

I am trying to port an Oauth2 client based on Oauth for Spring Security from plain Java/Spring to Grails, and have run into a problem. The crux of the issue appears to be the fact that the design of the Spring Oauth client implementation relies on the assumption that an exception thrown from the Oauth2RestTemplate will be caught in a catch block of the OAuth2ClientContextFilter, thus allowing the filter to issue a redirect response (to send an authorization request to the oath provider).
This works fine in plain Java/Spring but in Grails, the GrailsDispatcherServlet is configured to handle all exceptions via HandlerExceptionResolvers. Thus the exception thrown in the Oauth2RestTemplate (invoked inside a Grails controller) is caught by the GrailsExceptionResolver and is never seen by the OAuth2ClientContextFilter, thus defeating the desired redirect behavior.
All discussions I have found of customizing Grails exception handling all seem to assume that the purpose of the customization is to map the exception to an HTTP error code or to a error page view. But is there some way to tell Grails to simply allow a particular exception to flow through unhandled, so that it can be caught by the servlet filter? Or is it possible to insert a custom HandlerExceptionResolver that re-throws the exception rather than returning a ModelAndView (as is the standard expectation for a HandlerExceptionResolver)? Or is there some other better way to get the Oauth for Spring Security client working inside Grails?
Here's what I eventually came up with. Not sure if it is the best solution but it seems to work:
Create a new MyDispatcherServlet.groovy:
package org.example.com
import org.codehaus.groovy.grails.web.servlet.GrailsDispatcherServlet
import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletResponse
import org.springframework.web.servlet.ModelAndView
import org.springframework.security.oauth2.client.UserRedirectRequiredException
class MyDispatcherServlet extends GrailsDispatcherServlet {
#Override
protected ModelAndView processHandlerException(HttpServletRequest request,
HttpServletResponse response, Object handler, Exception ex) throws Exception {
def e = ex
while (e) {
if (e instanceof UserRedirectRequiredException) {
throw ex
}
e = e.cause
}
return super.processHandlerException(request, response, handler, ex)
}
}
Run grails install-templates and modify the web.xml to use MyDispatcherServlet instead of the default GrailsDispatcherServlet
The result is that MyDispatcherServlet will re-throw an exception that contains a UserRedirectRequiredException so that it can be caught by the OAuth2ClientContextFilter, but other exceptions will be passed on and handled as before by the GrailsExceptionResolver.
I think you can declare exceptionHandler in resources.groovy by defining your custom exception resolver. This custom exception resolver can (optionally) override GrailsExceptionResolver
exceptionHandler(MyExceptionResolver) {
exceptionMappings = ['java.lang.Exception': '/error']
}
class MyExceptionResolver extends GrailsExceptionResolver {
#Override
ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response,
Object handler, Exception ex) {
//your custom code
return super.resolveException(request, response, handler, ex)
}
}

Resources