Endless loop in Spring MVC Interceptor - spring

I have written a custom interceptor PreventScreenInterceptor extends HandlerInterceptorAdapter
in preHandle I am checking some conditions, and based on that, I am redirecting using
response.sendRedirect("/myapp/user/noaccess");
Now, whenever I am hitting /myapp/user/noaccess , it is going into endless loop as I am not able to come out of this interceptor. Its getting called again and again.
My Application context has :
<mvc:interceptor>
<mvc:mapping path="/myapp/user/**"/>
<bean class="com.mypackage.interceptors.PreventScreenInterceptor" />
</mvc:interceptor>

You have to use request.getRequestURI() to check that the URI being called is not "/myapp/user/noaccess", before sending your redirect.

You must check that the if the request is not coming with the action where you are redirecting from Interceptor , otherwise it will recall itself again and again.
for reference use this code -
#Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
String uri = request.getRequestURI();
logger.debug("inside interceptor and uri = "+uri);
if (!uri.endsWith("/noaccess") ) {
logger.info("request is coming from other than /myapp/user/noaccess");
response.sendRedirect("/myapp/user/noaccess");
}
return true;
}

Related

Spring Session not working on Tomcat 8 when using Tiles - SESSION Cookie is not set as response is already included

I am using Spring Session 1.2.0.RELEASE on a Spring Boot Project. This is packaged as a war and deployed on Tomcat 8.
I have followed Spring Session documentation and configured it properly. The problem is that the entry point to the application is a controller that sets some value on session but the SESSION cookie is not sent to the browser.
Debugging I see that:
org.springframework.session.web.http.CookieHttpSessionStrategy.onNewSession() tries to write the cookie:
this.cookieSerializer
.writeCookieValue(new CookieValue(request, response, cookieValue));
org.springframework.session.web.http.DefaultCookieSerializer.writeCookieValue() sets the cookie in the response:
response.addCookie(sessionCookie);
The cookie isn't actually written. The underlying response object is org.apache.catalina.core.ApplicationHttpResponse. Its addCookie() method is:
/**
* Disallow <code>addCookie()</code> calls on an included response.
* #param cookie The new cookie
*/
#Override
public void addCookie(Cookie cookie) {
if (!included)
((HttpServletResponse) getResponse()).addCookie(cookie);
}
The problem is that included attribute, which at some point is set true, preventing the cookie from being added.
This happens when the jsp (using tiles) is being serviced:
UPDATE:
This is the moment when the response is being marked as included (when standard.jsp tiles layout is inserting an attribute:
<tiles:insertAttribute name="header" ignore="false"/>
To work around this problem I ended up creating a filter to enforce the creation of the session.
As seen, the first call to the controller didn't add the cookie because during the Tiles-JSP rendering the response was already marked as included. What I do is forcing the creation of the session in the filter and redirecting asking the very same requestURI. This way, since the call doesn't involve a tiles rendering the cookie is created and can be used right away in the next calls.
#Bean
#ConditionalOnExpression("${sessionEnforcerFilter.enabled:true}")
public FilterRegistrationBean sessionEnforcerFilter(){
logger.info("Registering sessionEnforcerFilter");
FilterRegistrationBean frb = new FilterRegistrationBean();
frb.setName("sessionEnforcerFilter");
frb.setFilter(new SessionEnforcerFilter());
frb.setUrlPatterns(Arrays.asList(new String[]{"/*"}));
return frb;
}
public class SessionEnforcerFilter implements Filter{
#Override
public void init(FilterConfig filterConfig) throws ServletException {}
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)throws IOException, ServletException {
HttpServletRequest httpServletRequest = (HttpServletRequest)request;
HttpServletResponse httpServletResponse = (HttpServletResponse)response;
if(httpServletRequest.getSession(false)==null){
logger.debug("sessionEnforcerFilter.doFilter () - Session is null - forcing its creation");
httpServletRequest.getSession();
String requestURI = httpServletRequest.getRequestURI();
logger.debug("sessionEnforcerFilter.doFilter () - Repeating request [{}]", requestURI);
httpServletResponse.sendRedirect(requestURI);
}else{
chain.doFilter(httpServletRequest, response);
}
}
#Override
public void destroy() {}
}
summary
Hold breakPoint in SessionRepositoryResponseWrapper.onResponseCommitted().
Check that the response object inside the SessionRepositoryRequestWrapper is a non-wrapped response. (included = false)
If it is a wrapped response object, make sure that the sessionRepositoryFilter comes first.
================
Spring-session is already handling the problem when 'DispatcherType.INCLUDE (included = true)'.
SessionRepositoryResponseWrapper.onResponseCommitted() is trying to addCookie to the original response object.
The sessionRepositoryFilter must be in the first position to wrap the original applicationHttpResponse passed by tomcat.
Problem Situation
The SessionRepositoryRequestWrapper receives the wrapped response and holds it.
When executing doInclude() in the servlet container, find the original reponse and wrap it with ApplicationHttpResponse (included = true).
Then, SetResponse (new wrapping response) to the innermost wrapper.
http://grepcode.com/file/repo1.maven.org/maven2/org.apache.tomcat.embed/tomcat-embed-core/8.0.24/org/apache/catalina/core/ApplicationDispatcher.java#ApplicationDispatcher.doInclude%28javax.servlet.ServletRequest%2Cjavax.servlet.ServletResponse%29
http://grepcode.com/file/repo1.maven.org/maven2/org.apache.tomcat.embed/tomcat-embed-core/8.0.24/org/apache/catalina/core/ApplicationDispatcher.java#ApplicationDispatcher.wrapResponse%28org.apache.catalina.core.ApplicationDispatcher.State%29
Spring-session does an addCookie on the response (expecting the original response) stored in SessionRepositoryResponseWrapper.onResponseCommitted(), but it can not because it is set to 'included = true'.

Building a façade with spring which calls another server and returns its response

For an application I need to create a security façade in Spring 4.x.
This thiny layer must accepts any request from our mobile application and execute a security check for the provided token (with openId and Oauth).
Upon a successful validation, the request needs to be forwarded to the backend application, which does not need to be aware of the security token mechanism.
Thus, the flow will be something like this:
security_facade_url/path/of/the/request
With a header that indicates the backend to invoke upon successful validation of the token
Upon successful validation the security façade sends a request to the backend URL
backend_application_url/path/of/the/request
The façade must not have a controller which maps to any possible path of the request, but must call the request on the correct backend server, based on a value in the header of the request. Then return this response to the user.
What I have so far is an implementation of the HandlerInterceptor. This interceptor works, however, I am not really happy with the way I need to avoid the afterCompletion by throwing an exception in the postHandle method.
If I do not throw an error, the default error page is appended to the correct response in the afterCompletion step.
This is my code so far:
public class RequestProcessingInterceptor implements HandlerInterceptor {
private final Logger log = LoggerFactory.getLogger(RequestProcessingInterceptor.class);
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
log.info("Doing some security stuff now ...");
log.warn("... security ok ... since I am not really checking stuff");
return true;
}
public void postHandle(HttpServletRequest request,
HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
log.info("Forwarding request and sending that info back ...");
ClientConfig config = new DefaultClientConfig();
Client client = Client.create(config);
WebResource service = client.resource(UriBuilder.fromUri("http://localhost:8080").build());
response.setContentType("application/json");
response.getWriter().write(service.path(modelAndView.getModel().get("path").toString()).accept("application/json").get(String.class));
response.setStatus(200);
throw new Exception("Need to avoid the execution of the afterCompletion. Only way to do so is by throwing an exception...");
}
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
}
}
Is there a more proper way to intervene with the Spring livecycle or obtain the behaviour as described above?
Found a better solution. For what I need, I do not need to manipulate the results in an interceptor.
A much cleaner way is to define a Controller which maps with the request methods.
#RequestMapping(method = {RequestMethod.GET, RequestMethod.PUT, RequestMethod.POST})
public void handleRequest(HttpServletRequest request, HttpServletResponse response) { // code omitted }
You should not try to avoid the call to afterCompletion. Just implement an empty method and let SpringFramework call it.
Provided your controller returns null indicating that no view has to be called, it should work with a smoother Spring integration.
But I cannot understand why you use Spring MVC here. As you only interact with low level HttpServletRequest and HttpServletResponse, you could as well use :
a dedicated servlet in charge to relay the request and response to the backend and write the returned value in the response
a filter that would do the security stuff before passing request to filter chain

Spring aspects forward and cancel previous request

Here is my question
I want to intercept request before any spring controller call, check and modify request URI. After that it has to call another SPRING controller method.
I used mvc:interceptors however I want to configure it with annotations thats why I need a solution for #Aspect. Everything is working but controller called twice, for the original request and for the new request. Using interceptors I return false and it cancels it, how do I do about Aspect classes? Thank you
Here is my code:
#Component
#Aspect
public class TestAspect {
#Before("execution(* mycontroller.*(..)) &&" + "args(request,response)")
public void interceptUrl(HttpServletRequest request, HttpServletResponse response) {
System.out.println("#Aspect is running!");
System.out.println(request.getRequestURI());
if (request.getAttribute("client") == null) {
request.setAttribute("client", "test");
request.getRequestDispatcher("/newpath/contact").forward(request, response);
}
}
}
You should consider #Around advice instead of #Before. In this case you can simply not execute original request chain.

How to add Precall method in Spring MVC Controller

I have one requirement to fulfill.
Actually when ever user Login into my application , i will save the logged in user name in session attribute like .
session.setAttribute("LOGIN_USER", userName);
So that, if user tries to access my method links directly with out coming from Login page i can check in controller method whether this session has the specific attributive value as below and i can restrict user to access that page and redirect him to login page.
if(request.getSession(false).getAttribute("LOGIN_USER")==null)
//redirect to login page
Now,my requirement is if i have 50 methods in controller i can't add this condition in each method.I think there is a way we can add some sort of filters or any method in controller class like ex #preExecuteMethod to first execute this method and proceed for the actual call if success.
Yes, you can use a HandlerInterceptor for this. See the docs here and here.
Interceptor is the solution. It has methods preHandler which will be called before each request. You can hook into each HTTPServletRequest object and do the nnecessary stuff.
here is a sample code:
#Component
public class AuthCodeInterceptor extends HandlerInterceptorAdapter {
#Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
// set few parameters to handle ajax request from different host
response.addHeader("Access-Control-Allow-Origin", "*");
response.addHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS");
response.addHeader("Access-Control-Max-Age", "1000");
response.addHeader("Access-Control-Allow-Headers", "Content-Type");
response.addHeader("Cache-Control", "private");
String reqUri = request.getRequestURI();
String serviceName = reqUri.substring(reqUri.lastIndexOf("/") + 1,
reqUri.length());
if(request.getSession(false).getAttribute("LOGIN_USER")==null) {
//redirect to login page
}
return super.preHandle(request, response, handler);
}
#Override
public void postHandle(HttpServletRequest request,
HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
super.postHandle(request, response, handler, modelAndView);
}
}
Maybe you could use an AOP #Before aspect giving the pointcut to the methods in your handler class ? See the reference here or you could create a normal filter via the delegatingFilterProxy explained here . I think overall #skaffman gives a better idea .

Exception handler for REST controller in spring

I want to handle exceptions so the URL information is automatically shown to the client. Is there an easy way to do this?
<bean id="outboundExceptionAdapter" class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerExceptionResolver">
<!-- what property to set here? -->
</bean>
You have two choices:
Spring Reference 15.9.1 HandlerExceptionResolver
Spring HandlerExceptionResolvers ease the pain of unexpected
exceptions that occur while your request is handled by a controller
that matched the request. HandlerExceptionResolvers somewhat resemble
the exception mappings you can define in the web application
descriptor web.xml. However, they provide a more flexible way to
handle exceptions. They provide information about which handler was
executing when the exception was thrown. Furthermore, a programmatic
way of handling exceptions gives you more options for responding
appropriately before the request is forwarded to another URL (the same
end result as when you use the servlet specific exception mappings).
The HandlerExceptionResolver has one method, containing everything you need:
HandlerExceptionResolver.resolveException(HttpServletRequest request,
HttpServletResponse response,
Object handler, Exception ex)
Or if you need different handlers for different controllers: Spring Reference Chapter 15.9.2 #ExceptionHandler
#ExceptionHandler(IOException.class)
public String handleIOException(IOException ex, HttpServletRequest request) {
return "every thing you asked for: " + request;
}
Short question short answer
I'm doing the following trick:
#ExceptionHandler(Exception.class)
public ModelAndView handleMyException(Exception exception) {
ModelAndView mv = new ModelAndView("redirect:errorMessage?error="+exception.getMessage());
return mv;
}
#RequestMapping(value="/errorMessage", method=RequestMethod.GET)
#Responsebody
public String handleMyExceptionOnRedirect(#RequestParamter("error") String error) {
return error;
}
Works flawless.

Resources