Spring 3.0 unable to forward request from HandlerInterceptorAdapter - spring

I want to redirect to home page if session get invalid.
My spring-servlet.xml is
<mvc:interceptors>
<bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor" />
<mvc:interceptor>
<mvc:mapping path="/**" />
<bean class="com.xxx.MyInterceptor" />
</mvc:interceptor>
</mvc:interceptors>
Interceptor :
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
if ((null == request.getSession(false))
|| (null == request.getSession(false).getAttribute(
"user"))) {
System.out.println("user logged out...");
RequestDispatcher rd = request.getRequestDispatcher("loginForm.htm");
rd.forward(request, response);
return false;
}
return super.preHandle(request, response, handler);
}
But its not working...
Whenever application get started, the message get printed multiple times and at the end it gives stack overflow..
Thank You.

It seems like the problem is in your mapping path. Since its mapped with /** your loginForm.htm is also getting intercepted. You have two solutions available to resolve this problem.
Either define <mvc:resources location="/resources/" mapping="/resources/**" /> so that the *.htm requests will not be intercepted. Replace the location and mapping values as per your path where the *.htm files are.
And another option is to change your mapping in intercepter with something like /*.do or something else.
Hope this helps you. Cheers.

Related

JasperReportsViewResolver and Spring MVC - Set filename

I need help with JasperReports and Spring MVC. I can export everything, but I can't set the filename in the output PDF/Excel that my software exports.
In my dispatcher-servlet I have this bean :
<!-- ViewResolver JasperReports -->
<bean id="jasperViewResolver" class="org.springframework.web.servlet.view.jasperreports.JasperReportsViewResolver">
<property name="prefix" value="classpath:/jasper/" />
<property name="reportDataKey" value="dataSource" />
<property name="suffix" value=".jrxml" />
<property name="viewNames" value="Report_*" />
<property name="viewClass">
<value>org.springframework.web.servlet.view.jasperreports.JasperReportsMultiFormatView</value>
</property>
<property name="order" value="1" />
</bean>
That is the ViewResolver provided by Spring MVC.
I have a function in my BaseController ( abstract controller extended by all the #Controller ) :
protected String exportReport(String reportName, String formatoReport, Model model, JRDataSource dataSource) {
model.addAttribute("dataSource", dataSource);
model.addAttribute("format", formatoReport);
return reportName;
}
So, what I do is simply returning this view name from all my #RequestMapping :
#RequestMapping(..something)
public String functionName(...something else) {
.. do some stuff
return exportReport("Report_docIngresso", EFormatoReport.XLS, model, jrDataSource);
}
This works. The export is perfect, but I didn't find the way to set the filename of the exported pdf/excel, that comes out like the latest part of the URL I called before exporting the report.
I already tried to set in the HttpServletResponse the content-disposition with the filename, but it didn't work.
Thanks a lot,
Marco
Try setting the Content-Disposition HTTP response header:
#RequestMapping(..something)
public String functionName(HttpServletResponse response, ...something else) {
.. do some stuff
String header = "inline; filename=myfile.xls";
response.setHeader("Content-Disposition", header);
return exportReport("Report_docIngresso", EFormatoReport.XLS, model, jrDataSource);
}
(Note I saw just now your concluding comment that you tried without success to set the content disposition header. Well.. I can only say it worked for me in a similar setup.)

View not getting resolved in Spring mvc gradle application

web application is made with gradle sts project
i've added view Resolver like this
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/view/" />
<property name="suffix" value=".html" />
</bean>
it is hitting the url but wont return any view
#Controller
public class HomeController {
#RequestMapping(value = DatahubClientConstant.CLIENT_URL , method = RequestMethod.GET )
public ModelAndView getTestPage(HttpServletRequest request, HttpServletResponse response) throws Exception {
//System.out.println("Hello World");
return new ModelAndView("home");
}
}
Tried to sysout it works
It doesnt return any view?
After Some Research i have found out that InternalViewResolver does not resolve html pages directly that's why i was not able to get the view.
Spring MVC ViewResolver not mapping to HTML files
This was a helpful question in resolving the issue. All it is doing is loading the html as static content.

Set custom response in Spring interceptor

Here is my interceptor method where i want to set custom response to tell the UI what happened
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
HttpSession session = request.getSession(false);
if (session != null)
return true;
else{
response.sendError(HttpServletResponse.SC_REQUEST_TIMEOUT)
return false;
}
}
And in web.xml
<error-page>
<error-code>408</error-code>
<location>/error.html</location>
</error-page>
spring-servlet.xml
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**" />
<mvc:exclude-mapping path="/login" />
<bean class="com.example.CustomInterceptor" />
</mvc:interceptor>
</mvc:interceptors>
When the session is timed out its not sending any response after return false.
Even the below is not working
response.sendRedirect("http://localhost:8080/home");
You can try very simple thing. Change your mvc:interceptros structure to
<mvc:interceptors>
<bean class="com.example.CustomInterceptor" />
</mvc:interceptors>
This essentially mean apply the interceptor to all applicable requests. I will come in a moment to why I say applicable in a moment. If above works then the issue is with your mapping.
Now as you know interceptors are configured at the level of HandlerMapping and it will be RequestMappingHandlerMapping (Spring 3.1+ with mvc:annotation-driven) or DefaultAnnotationHandlerMapping in your case.
Now as you have use <mvc:mapping path="/**" /> will map to all requests (including subpaths) as long as they are valid mappings. So lets say you have controller
#RequestMapping(value="/home", method = RequestMethod.GET)
public String welcome() {
return "welcome";
}
you cannot hit http://localhost:8080/yourProjectName/home/test and expect it to hit the interceptor. So you have to hit http://localhost:8080/yourProjectName/home as that is a valid HandlerMapping.
As to to response first debug if your interceptor is getting hit for any requests. If it does work then
response.sendError(HttpServletResponse.SC_REQUEST_TIMEOUT);
should redirect you to error.html as you have used
<error-page>
<error-code>408</error-code>
<location>/error.html</location>
</error-page>

Spring Security Error Pages using Forward

I want to display a custom error page on authentication denial (I am using a pre-authenticated secnario) and also access denial from Spring Security 3.0.X
Understand we can use the following to perform this:
<beans:bean id="authenticationEntryPoint" class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
<beans:property name="loginFormUrl" value="/error.jsp"/>
</beans:bean>
<beans:bean id="accessDeniedHandler" class="org.springframework.security.web.access.AccessDeniedHandlerImpl">
<beans:property name="errorPage" value="/error.jsp"/>
</beans:bean>
but doing this results in a redirect and not a forward to the error page. Anyway to perform forward to an error page (so that we can set some attributes in the request)
Thanks
In my security-context.xml, for authentication failure I do like this (pay attention to the authentication-failure-url attribute):
<security:form-login login-page="/auth/login"
authentication-failure-url="/auth/login?error=true"
default-target-url="/mvc/home"
always-use-default-target="true" />
And for access denied I use this:
<security:access-denied-handler error-page="/auth/access-denied"/>
Both tags inside <security:http use-expressions="true">. For me works like a charm, I don't know why you are trying to configure it in the way you are doing when Spring provides such nice tags easy to use.
I don't know if it answers your question, I hope it helps.
EDIT:
Using the configuration provided above, means that you are using the default authentication failure handler (SimpleUrlAuthenticationFailureHandler) at the background. You can change the default behavior (which as default performs a redirect when a failed authentication is produced) by changing the attribute forwardToDestination value. This is what SimpleUrlAuthenticationFailureHandler does:
/**
* Performs the redirect or forward to the {#code defaultFailureUrl} if set, otherwise returns a 401 error code.
* <p>
* If redirecting or forwarding, {#code saveException} will be called to cache the exception for use in
* the target view.
*/
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
AuthenticationException exception) throws IOException, ServletException {
if (defaultFailureUrl == null) {
logger.debug("No failure URL set, sending 401 Unauthorized error");
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Authentication Failed: " + exception.getMessage());
} else {
saveException(request, exception);
if (forwardToDestination) {
logger.debug("Forwarding to " + defaultFailureUrl);
request.getRequestDispatcher(defaultFailureUrl).forward(request, response);
} else {
logger.debug("Redirecting to " + defaultFailureUrl);
redirectStrategy.sendRedirect(request, response, defaultFailureUrl);
}
}
}
So I guess that I you declare your SimpleUrlAuthenticationFailureHandler in your security-context.xml and set the mentioned property value using the setUseForward(boolean forwardToDestination) method it should work. Could be something like:
<bean id="simpleUrlAuthenticationFailureHandler" class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler">
<property name="useForward" value="true">
</bean>
And then:
<security:form-login login-page="/auth/login"
authentication-failure-handler-ref="simpleUrlAuthenticationFailureHandler"
default-target-url="/mvc/home"
always-use-default-target="true" />
Good luck.

How to manually log out a user with spring security?

Probably the answer is simple: How can I manually logout the currently logged in user in spring security?
Is it sufficient to call:
SecurityContextHolder.getContext().getAuthentication().setAuthenticated(false);
?
It's hard for me to say for sure if your code is enough. However standard Spring-security's implementation of logging out is different. If you took a look at SecurityContextLogoutHandler you would see they do:
SecurityContextHolder.clearContext();
Moreover they optionally invalidate the HttpSession:
if (invalidateHttpSession) {
HttpSession session = request.getSession(false);
if (session != null) {
session.invalidate();
}
}
You may find more information in some other question about logging out in Spring Security and by looking at the source code of org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler.
In Servlet 3.0 container Spring logout functionality is integrated with servlet and you just invoke logout() on your HttpServletRequest. Still need to write valid response content.
According to documentation (Spring 3.2):
The HttpServletRequest.logout() method can be used to log the current user out.
Typically this means that the SecurityContextHolder will be cleared
out, the HttpSession will be invalidated, any "Remember Me"
authentication will be cleaned up, etc.
I use the same code in LogoutFilter, reusing the LogoutHandlers as following:
public static void myLogoff(HttpServletRequest request, HttpServletResponse response) {
CookieClearingLogoutHandler cookieClearingLogoutHandler = new CookieClearingLogoutHandler(AbstractRememberMeServices.SPRING_SECURITY_REMEMBER_ME_COOKIE_KEY);
SecurityContextLogoutHandler securityContextLogoutHandler = new SecurityContextLogoutHandler();
cookieClearingLogoutHandler.logout(request, response, null);
securityContextLogoutHandler.logout(request, response, null);
}
You can also use SessionRegistry as:
sessionRegistry.getSessionInformation(sessionId).expireNow();
If you want to force logout in all sessions of a user then use getAllSessions method and call expireNow of each session information.
Edit
This requires ConcurrentSessionFilter (or any other filter in the chain), that checks SessionInformation and calls all logout handlers and then do redirect.
To log out a user in a web application you can also redirect him to the logout page. The LogoutFilter is then doing all the work for you.
The url of the logout page is set in the security configuration:
<sec:http ...>
...
<sec:logout logout-url="/logout" logout-success-url="/login?logout_successful=1" />
...
</sec:http>
new SecurityContextLogoutHandler().logout(request, null, null);
Right Oledzki, I am using the following for example inside my controller to logout and redirect the user to the login page in spring security 4.2.3
SecurityContextHolder.clearContext();
if(session != null)
session.invalidate();
return "redirect:/login";
Simply do like this (the ones commented by "concern you") :
Authentication auth = SecurityContextHolder.getContext().getAuthentication(); // concern you
User currUser = userService.getUserById(auth.getName()); // some of DAO or Service...
SecurityContextLogoutHandler ctxLogOut = new SecurityContextLogoutHandler(); // concern you
if( currUser == null ){
ctxLogOut.logout(request, response, auth); // concern you
}
Recently we had to implement logout functionality using Spring-security 3.0.5. Although this question is already answered above, I will post the complete code which would definitely help novice user like me :)
Configuration in Spring-security.xml
<http auto-config="false" lowercase-comparisons="false" use-expressions="true">
<custom-filter position="LOGOUT_FILTER" ref="logoutFilter" />
</http>
<beans:bean id="logoutFilter" class="org.springframework.security.web.authentication.logout.LogoutFilter">
<beans:constructor-arg name="logoutSuccessHandler" ref="xxxLogoutSuccessHandler" />
<beans:constructor-arg name="handlers">
<beans:list>
<beans:ref bean="securityContextLogoutHandler"/>
<beans:ref bean="xxxLogoutHandler"/>
</beans:list>
</beans:constructor-arg>
<beans:property name="filterProcessesUrl" value="/logout"/>
</beans:bean>
<beans:bean id="XXXLogoutSuccessHandler" class="com.tms.dis.sso.XXXLogoutSuccessHandler"/>
<beans:bean id="securityContextLogoutHandler" class="org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler">
<beans:property name="invalidateHttpSession" value="true"/>
</beans:bean>
<beans:bean id="XXXLogoutHandler" class="com.tms.dis.sso.XXXLogoutHandler"/>
Here i have created two custom classes
XXXLogoutHandler which will implement org.springframework.security.web.authentication.logout.LogoutHandler and will override the logout() method.
XXXLogoutSuccessHandler which will implement org.springframework.security.web.authentication.logout.LogoutSuccessHanlder and will override onLoguoutSuccess() method. Within the XXXLogoutSuccessHandler.onLogoutSuccess() method call the redirectStrategy.sendRedirect() method which logout the user to the particular targetURL.
org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler does the task of invalidating the user session.
Hope this would help and give the correct direction to the starter
Note: Intentionally have not posted code for custom implementation.
Very simple, to logout of spring security manually,
just make use of the Servlet request itself.
i.e. As below :
#PostMapping("/manualLogout")
public String customLogut(Model models, HttpServletRequest request) throws ServletException
{
request.logout();
return "redirect:/";
}
Thanks for the question.
In you controller >> signOut method do not return "/logout" but redirect to the /logout method in the spring security context: return "redirect:/logout";

Resources