package org.ovirt.engine.core.utils.servlet;
import java.io.IOException;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;
/**
* This filter automatically adds headers to the response of a {@code HttpServletResponse}. To enable
* this filter you must add the following to your web.xml
* <pre>
* <filter>
* <filter-name>HeaderFilter</filter-name>
* <filter-class>org.ovirt.engine.core.utils.servlet.HeaderFilter</filter-class>
* </filter>
*
* <filter-mapping>
* <filter-name>HeaderFilter</filter-name>
* <url-pattern>/*</url-pattern>
* </filter-mapping>
*
* </pre>
* There are 3 default headers that are added to the response.
* <ul>
* <li>X-frame-options (To prevent click jacking)</li>
* <li>X-content-type-options (To prevent mime sniffing attacks)</li>
* <li>X-XSS-protection (To enable IE XSS filter)</li>
* </ul>
* It is possible to override the default values for these by adding an init param to the filter definition in your
* web.xml. For instance:
* <pre>
* <filter>
* <filter-name>HeaderFilter</filter-name>
* <filter-class>org.ovirt.engine.core.utils.servlet.HeaderFilter</filter-class>
* <init-param>
* <param-name>X-frame-options</param-name>
* <param-value>DENY</param-value>
* </init-param>
* </filter>
* </pre>
* This will set the value to DENY instead of the default SAMEORIGIN. Using the same technique one can add any
* number of extra headers.
*/
public class HeaderFilter implements Filter {
/**
* X-frame-options string constant.
*/
private static final String X_FRAME_OPTIONS = "X-FRAME-OPTIONS"; //$NON-NLS-1$
/**
* X-frame-options default value string constant.
*/
// This has to be SAMEORIGIN otherwise GWT won't work.
private static final String X_FRAME_OPTIONS_DEFAULT = "SAMEORIGIN"; //$NON-NLS-1$
/**
* X-content-type-options string constant.
*/
private static final String X_CONTENT_TYPE_OPTIONS = "X-CONTENT-TYPE-OPTIONS"; //$NON-NLS-1$
/**
* X-content-type-options default value string constant.
*/
private static final String X_CONTENT_TYPE_OPTIONS_DEFAULT = "NOSNIFF"; //$NON-NLS-1$
/**
* X-XSS-protection string constant.
*/
private static final String X_XSS_PROTECTION = "X-XSS-PROTECTION"; //$NON-NLS-1$
/**
* X-XSS-protection default value string constant.
*/
private static final String X_XSS_PROTECTION_DEFAULT = "1; MODE=BLOCK"; //$NON-NLS-1$
/**
* The map that contains the header name and value pairs to be added to each response.
*/
private final Map<String, String> headerValueMap = new HashMap<>();
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException,
ServletException {
HttpServletResponse res = (HttpServletResponse) response;
for (Map.Entry<String, String> entry: headerValueMap.entrySet()) {
res.addHeader(entry.getKey(), entry.getValue());
}
chain.doFilter(request, response);
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
Enumeration<String> headerNames = filterConfig.getInitParameterNames();
addDefaultsToMap();
while (headerNames.hasMoreElements()) {
String name = headerNames.nextElement();
//This allows for overriding the defaults.
headerValueMap.put(name.toUpperCase(), filterConfig.getInitParameter(name));
}
}
/**
* These are headers each response should have.
*/
private void addDefaultsToMap() {
headerValueMap.put(X_FRAME_OPTIONS, X_FRAME_OPTIONS_DEFAULT);
headerValueMap.put(X_CONTENT_TYPE_OPTIONS, X_CONTENT_TYPE_OPTIONS_DEFAULT);
headerValueMap.put(X_XSS_PROTECTION, X_XSS_PROTECTION_DEFAULT);
}
@Override
public void destroy() {
// Do nothing.
}
}