/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.catalina.filters; import java.io.IOException; 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; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; /** * Implements HTTP Strict Transport Security (HSTS) according to RFC 6797. *
* The filter assumes that: *
* <web-app ...>
* ...
* <filter>
* <filter-name>HstsFilter</filter-name>
* <filter-class>org.apache.catalina.filters.HstsFilter</filter-class>
* <init-param>
* <param-name>maxAgeSeconds</param-name>
* <param-value>31536000</param-value>
* </init-param>
* <init-param>
* <param-name>includeSubDomains</param-name>
* <param-value>true</param-value>
* </init-param>
* </filter>
* ...
* <filter-mapping>
* <filter-name>HstsFilter</filter-name>
* <url-pattern>/*</url-pattern>
* </filter-mapping>
* ...
* </web-app>
*
* @author Jens Borgland
* @see RFC 6797
*/
public class HstsFilter extends FilterBase {
private static final String HEADER_NAME = "Strict-Transport-Security";
private static final String MAX_AGE_DIRECTIVE = "max-age=%s";
private static final String INCLUDE_SUB_DOMAINS_DIRECTIVE = "includeSubDomains";
private static final Log log = LogFactory.getLog(HstsFilter.class);
// The default is "0" like recommended in section 11.2 of RFC 6797
private int maxAgeSeconds = 0;
private boolean includeSubDomains = false;
private String directives;
public void setMaxAgeSeconds(int maxAgeSeconds) {
this.maxAgeSeconds = maxAgeSeconds;
}
public void setIncludeSubDomains(boolean includeSubDomains) {
this.includeSubDomains = includeSubDomains;
}
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
chain.doFilter(request, response);
// Note that the HSTS header must not be included in HTTP responses
// conveyed over non-secure transport
if (request.isSecure() && response instanceof HttpServletResponse) {
HttpServletResponse res = (HttpServletResponse) response;
res.addHeader(HEADER_NAME, this.directives);
}
}
@SuppressWarnings("boxing")
@Override
public void init(FilterConfig filterConfig) throws ServletException {
super.init(filterConfig);
if (this.maxAgeSeconds < 0) {
throw new ServletException(sm.getString(
"hsts.invalidParameterValue", this.maxAgeSeconds,
"maxAgeSeconds"));
}
this.directives = String.format(MAX_AGE_DIRECTIVE, this.maxAgeSeconds);
if (this.includeSubDomains) {
this.directives += (" ; " + INCLUDE_SUB_DOMAINS_DIRECTIVE);
}
}
@Override
protected Log getLogger() {
return log;
}
}