SpringMVC - Controller for all files with same file extension - java

I have a SpringMVC application, and I need to create a controller capable of handling all the request for files with a given extension.
So far I have this:
web.xml
<filter-mapping>
<filter-name>redirectFilter</filter-name>
<url-pattern>*.jhtml</url-pattern>
</filter-mapping>
spring-mvc.xml
<bean id="anotherViewResolver" class="org.springframework.web.servlet.view.UrlBasedViewResolver" >
<property name="viewClass" value="org.springframework.web.servlet.view.InternalResourceView"/>
<property name="prefix" value="/"/>
<property name="suffix" value=".jhtml"/>
</bean>
Dispatcher Servlet
<servlet>
<servlet-name>abc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring-mvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>abc</servlet-name>
<url-pattern>/abc/*</url-pattern>
</servlet-mapping>
How should I write the controller?

You can write a #Controller method like this
#RequestMapping(value = "**/*.jhtml")
public String handleExtensionRequest() {
return "viewName";
}
This will map to paths like
www.yourhost.com/abc/somePath.jhtml
www.yourhost.com/abc/asdasdasd/qweqwe1231/12312312/somePath.jhtml
going down any number of sub paths.
The problem with this is /abc/somePath and /abc/somePath.* are considered equivalent. If you have a #Controller handler method mapped to /somePath, it will probably get priority.
With Java config, you can declare a #Configuration class to extends WebMvcConfigurationSupport and add
#Override
#Bean
public RequestMappingHandlerMapping requestMappingHandlerMapping() {
RequestMappingHandlerMapping handlerMapping = super.requestMappingHandlerMapping();
handlerMapping.setUseSuffixPatternMatch(false);
return handlerMapping;
}
This setting decides
Whether to use suffix pattern match (".*") when matching patterns to
requests.
The RequestMappingHandlerMapping has other methods/settings you can play around with to set the right path.

I opted for the easiest way: since what I only need is to redirect those *.jhtml requests to somewhere else, I added a filter for them.
web.xml
<filter>
<description>Filter for *.jhtml requests</description>
<display-name>jhtmlRedirectFilter</display-name>
<filter-name>jhtmlRedirectFilter</filter-name>
<filter-class>com.mycompany.JHTMLRedirectFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>jhtmlRedirectFilter</filter-name>
<url-pattern>*.jhtml</url-pattern>
</filter-mapping>
JHTMLRedirectFilter class
public class JHTMLRedirectFilter implements Filter {
private static final Logger logger = Logger.getLogger(JHTMLRedirectFilter.class);
#Override
public void destroy() {
// TODO Auto-generated method stub
}
#Override
public void doFilter(ServletRequest req, ServletResponse res,
FilterChain chain) throws IOException, ServletException {
// Some logic here
}
#Override
public void init(FilterConfig arg0) throws ServletException {
// TODO Auto-generated method stub
}
}

Related

Preventing clickjacking attack

Currently, I'm working on a vaadin project where I'm working on preventing clickjacking attack on the project. After searching for the solution I've found that adding following snippet in web.xml would work:
<filter>
<filter-name>httpHeaderSecurity</filter-name>
<filter-class>org.apache.catalina.filters.HttpHeaderSecurityFilter</filter-class>
<async-supported>true</async-supported>
<init-param>
<param-name>antiClickJackingEnabled</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>antiClickJackingOption</param-name>
<param-value>SAMEORIGIN</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>httpHeaderSecurity</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
I've added following dependency in pom.xml:
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-catalina</artifactId>
<version>9.0.2</version>
</dependency>
I'm running the project on payara server.
The project runs but throw the following error:
Caused by: java.lang.ClassNotFoundException:
org.apache.catalina.filters.HttpHeaderSecurityFilter not found by
org.glassfish.main.web.core [69] at
org.apache.felix.framework.BundleWiringImpl.findClassOrResourceByDelegation(BundleWiringImpl.java:1532)
at
org.apache.felix.framework.BundleWiringImpl.access$400(BundleWiringImpl.java:75)
at
org.apache.felix.framework.BundleWiringImpl$BundleClassLoader.loadClass(BundleWiringImpl.java:1955)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357) at
org.apache.catalina.core.ApplicationFilterConfig.loadFilterClass(ApplicationFilterConfig.java:283)
at
org.apache.catalina.core.ApplicationFilterConfig.getFilter(ApplicationFilterConfig.java:253)
at
org.apache.catalina.core.ApplicationFilterConfig.(ApplicationFilterConfig.java:123)
... 50 more
Which means my solution for preventing clickjacking attack won't work :)
Any help will be appreciated :).
I've solved this in the following way using web.xml:
First created the following filter:
public class ClickjackingPreventionFilter implements Filter
{
private String mode = "DENY";
// Add X-FRAME-OPTIONS response header to tell any other browsers who not to display this //content in a frame.
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletResponse res = (HttpServletResponse)response;
res.addHeader("X-FRAME-OPTIONS", mode );
chain.doFilter(request, response);
}
#Override
public void destroy() {
}
#Override
public void init(FilterConfig filterConfig) {
String configMode = filterConfig.getInitParameter("mode");
if ( configMode != null ) {
mode = configMode;
}
}
}
Then configured that into web.xml like the following:
<filter>
<filter-name>ClickjackPreventionFilterDeny</filter-name>
<filter-class>com.groupbuilder.preventclickjacking.ClickjackingPreventionFilter</filter-class>
<init-param>
<param-name>mode</param-name><param-value>DENY</param-value></init-param>
</filter>
<filter-mapping>
<filter-name>ClickjackPreventionFilterDeny</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

filter that forwards to index page

I want to make a filter that would forward to /WEB-INF/index.html request to application that looks like this
http://localhost:8080/basic-application-web
Here is my filter
public class RootFilter implements Filter {
#Override
public void init(FilterConfig filterConfig) throws ServletException {}
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse resp = (HttpServletResponse) response;
if (req.getRequestURI().equals("/basic%2Dapplication%2Dweb/")) {
req.getRequestDispatcher("/WEB-INF/index.html").forward(req, resp);
}
chain.doFilter(request, response);
}
#Override
public void destroy() {}
}
My web.xml looks like this
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
xmlns='http://java.sun.com/xml/ns/javaee'
xmlns:web='http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd'
xsi:schemaLocation='http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaeeweb-app_2_5.xsd'
id='basic_web' version='2.5'>
<display-name>Basic web application</display-name>
<servlet>
<servlet-name>serviceServlet</servlet-name>
<servlet-class>com.pack.ServiceServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>serviceServlet</servlet-name>
<url-pattern>/messaging</url-pattern>
</servlet-mapping>
<filter>
<filter-name>rootFilter</filter-name>
<filter-class>com.pack.RootFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>rootFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
However from time to time I get some weird behaviour where tomcat (I use it to deploy the war) is unable to find basic-application-web when I try to access directly using URL.
Though through tomcat manager it works fine. What is the problem? Maybe due to missing root servlet?
I moved index.html outside WEB-INF so basically the layout started to look like this
webapp
WEB-INF\web.xml
index.html
And adjusted filter to forward to /index.html instead of WEB-INF/index.html
req.getRequestDispatcher("/WEB-INF/index.html").forward(req, resp);
It has helped.

JQuery invoking Spring Rest service: Cross-Origin issue vs ParseError

I am trying to invoke a REST service with jquery, but either I get a Cross Origin Problem (when I do not specify the datatype in jquery invocation) or a parseerror (when I do).
JQuery use:
function requestData() {
$.ajax({
url: 'http://xxx.xx.xx.xxx:8080/Project/api/',
type: 'GET',
dataType:"jsonp",
success: function(json) {
console.log("OK");
console.log(json);
},
error: function(xhr, status, error) {
console.log("NO");
console.log("STATUS:" + status);
}
});
}
Server side, I am using Spring REST this way:
#RequestMapping(value = "/", method = RequestMethod.GET)
public #ResponseBody List<Entity> getEntities() {
List<Entity> found = controller.findEntities();
return found;
}
The serialized data are correct, as invoking the REST API in the browser produces correct JSON.
I also added the following CORS filter, which does NOT seem to be executed, as "AA" is not printed:
#Component
public class SimpleCORSFilter implements Filter {
public void doFilter(ServletRequest req, ServletResponse res,
FilterChain chain) throws IOException, ServletException {
System.out.println("AA");
HttpServletResponse response = (HttpServletResponse) res;
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods",
"POST, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "x-requested-with");
chain.doFilter(req, res);
}
public void init(FilterConfig filterConfig) {}
public void destroy() { }
}
My web.xml:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/root-context.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>appServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/servlet-context.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>appServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<filter>
<filter-name>simpleCORSFilter</filter-name>
<filter-class>org.lh.xxx.web.SimpleCORSFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>simpleCORSFilter</filter-name>
<servlet-name>/*</servlet-name>
</filter-mapping>
<filter>
<filter-name>OpenSessionInViewFilter</filter-name>
<filter-class>org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>OpenSessionInViewFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
What's wrong with it?
The issue was strictly related to the filter not being executed: Spring Filter not getting invoked
When executing the filter, correct json is returned to the invoking client.

Session Filter usage

I need to do a session filter. localhost:8080/Project/faces/index.xhtml is the login. If login is successful, the user will be redirected for app/conta.xhtml, but if user writes localhost:8080/Project/faces/app/conta.xhtml directly in address bar and not logged in must be redirected for index.xhtml again.
All pages that are in app/* must not be accessed without successful login.
My class LoginFilter is in the package filtro
#WebFilter("/app/*")
public class LoginFilter implements Filter {
#Override
public void init(FilterConfig config) throws ServletException {
// If you have any <init-param> in web.xml, then you could get them
// here by config.getInitParameter("name") and assign it as field.
}
#Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
HttpSession session = request.getSession(false);
if (session == null || session.getAttribute("idUsuario") == null) {
response.sendRedirect(request.getContextPath() + "../index.xhtml"); // No logged-in user found, so redirect to login page.
} else {
chain.doFilter(req, res); // Logged-in user found, so just continue request.
}
}
#Override
public void destroy() {
// If you have assigned any expensive resources as field of
// this Filter class, then you could clean/close them here.
}
}
My web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
<context-param>
<param-name>javax.faces.PROJECT_STAGE</param-name>
<param-value>Development</param-value>
</context-param>
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>/faces/*</url-pattern>
</servlet-mapping>
<session-config>
<session-timeout>
30
</session-timeout>
</session-config>
<welcome-file-list>
<welcome-file>faces/index.xhtml</welcome-file>
</welcome-file-list>
<filter>
<filter-name>Login Filter</filter-name>
<filter-class>filtro.LoginFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>Login Filter</filter-name>
<url-pattern>/app/*</url-pattern>
</filter-mapping>
</web-app>
Despite all this, I can enter /faces/app/conta.xhtml and have normal access!
This is my code for Login Validation = validarLogin()
BeanUsuarios.java
#ManagedBean
#ViewScoped
public class BeanUsuarios {
private Usuario usuario;
public Usuario getUsuario() {
return usuario;
}
public void setUsuario(Usuario usuario) {
this.usuario = usuario;
}
#PostConstruct
public void BeanUsuario(){
if(getUsuario()==null){
usuario = new Usuario();
}
}
public void validarLogin(){
UsuarioJpaController cUsuario = new UsuarioJpaController();
cUsuario.getEntityManager().createNamedQuery("Usuario.findByLogin").setParameter("login", this.usuario.getLogin()).getSingleResult();
if(usuario != null){
if(usuario.getSenha().equals(this.usuario.getSenha())){
FacesContext fc = FacesContext.getCurrentInstance();
HttpSession session = (HttpSession) fc.getExternalContext().getSession(false);
session.setAttribute("idUsuario", this.usuario.getId());
try {
FacesContext.getCurrentInstance()
.getExternalContext()
.redirect("app/conta.xhtml");
} catch (IOException ex) {
Logger.getLogger(BeanUsuarios.class.getName()).log(Level.SEVERE, null, ex);
}
}else{
}
}
}
}
You have two options:
Change the filter URL mapping to /faces/app* since that's how you're accessing your pages.
In the web.xml file, get rid of the /faces/* servlet mapping and use *.xhtml instead. This would require to change your welcome file to index.xhtml only.
IMO I would use option 2 since I don't like the Faces Servlet process the non-JSF related requests as JavaScript, CSS and images files.

Filter not working

I basically have a filter and in it's doFilter method, i'm just printing a message to console and i have applied that filter to every page of my sample web app.
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
<filter>
<filter-name>LoginFilter</filter-name>
<filter-class>
com.mypkg.filters.LoginFilter
</filter-class>
</filter>
<filter-mapping>
<filter-name>LoginFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<welcome-file-list>
<welcome-file>utility.jsp</welcome-file>
and my filter code
LoginFilter.java
package com.mypkg.filters;
import java.io.IOException;
import javax.servlet.*;
import javax.servlet.http.HttpServletResponse;
//other imports
public class LoginFilter implements Filter {
#Override
public void init(FilterConfig config) throws ServletException {
System.out.println("Filter init ran!");
}
#Override
public void doFilter(ServletRequest request, ServletResponse response,FilterChain chain) throws IOException, ServletException {
System.out.println("Filter running!");
}
#Override
public void destroy(FilterConfig config) throws ServletException {
//System.out.println("Filter destoryed!");
}
Now when i first ran this filter, i got "Filter running" message but after that i included hibernate and other libraries, it stopped working, i removed them and same result. Filter doesn't run. Checked url pattern and everything.. Clueless!!
Any pointers?
First of all, in you doFilter method you should call the next filter in the chain:
chain.doFilter(request, response);
Without this your request will not be processed further after your filter.
This can be a reason of your problem.
EDIT:
Also your destroy() method is wrong. Here how you should rewrite it:
#Override
public void destroy() {
System.out.println("Filter destoryed!");
}
Maybe you have another Filter executed before yours, that does not call chain.doFilter(), thus preventing next filters (including yours) to be executed.

Categories

Resources