blob: 86a6951f8739d3c811461a492c3e255fbc270cfe [file] [log] [blame]
/*
* 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.felix.http.sslfilter.internal;
import static org.apache.felix.http.sslfilter.internal.SslFilterConstants.HDR_X_FORWARDED_SSL;
import static org.apache.felix.http.sslfilter.internal.SslFilterConstants.HDR_X_FORWARDED_SSL_CERTIFICATE;
import java.io.IOException;
import java.security.cert.CertificateException;
import java.util.Dictionary;
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.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.osgi.service.cm.ConfigurationException;
import org.osgi.service.http.whiteboard.Preprocessor;
import org.osgi.service.log.LogService;
@SuppressWarnings("rawtypes")
public class SslFilter implements Preprocessor
{
public static final String PID = "org.apache.felix.http.sslfilter.SslFilter";
private static final String DEFAULT_SSL_HEADER = HDR_X_FORWARDED_SSL;
private static final String DEFAULT_SSL_VALUE = "on";
private static final String DEFAULT_CERT_HEADER = HDR_X_FORWARDED_SSL_CERTIFICATE;
private static final boolean DEFAULT_REWRITE_ABSOLUTE_URLS = false;
private static final String PROP_SSL_HEADER = "ssl-forward.header";
private static final String PROP_SSL_VALUE = "ssl-forward.value";
private static final String PROP_SSL_CERT_KEY = "ssl-forward-cert.header";
private static final String PROP_REWRITE_ABSOLUTE_URLS = "rewrite.absolute.urls";
private volatile ConfigHolder config;
SslFilter()
{
this.config = new ConfigHolder(DEFAULT_SSL_HEADER,
DEFAULT_SSL_VALUE,
DEFAULT_CERT_HEADER,
DEFAULT_REWRITE_ABSOLUTE_URLS);
}
@Override
public void destroy()
{
// No explicit destroy needed...
}
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException
{
final ConfigHolder cfg = this.config;
HttpServletRequest httpReq = (HttpServletRequest) req;
HttpServletResponse httpResp = (HttpServletResponse) res;
if (cfg.sslValue.equalsIgnoreCase(httpReq.getHeader(cfg.sslHeader)))
{
try
{
httpResp = new SslFilterResponse(httpResp, httpReq, cfg);
// In case this fails, we fall back to the original HTTP request, which is better than nothing...
httpReq = new SslFilterRequest(httpReq, httpReq.getHeader(cfg.certHeader));
}
catch (CertificateException e)
{
SystemLogger.log(LogService.LOG_WARNING, "Failed to create SSL filter request! Problem parsing client certificates?! Client certificate will *not* be forwarded...", e);
}
}
// forward the request making sure any certificate is removed again after the request processing gets back here
try
{
chain.doFilter(httpReq, httpResp);
}
finally
{
if (httpReq instanceof SslFilterRequest)
{
((SslFilterRequest) httpReq).done();
}
}
}
@Override
public void init(FilterConfig config)
{
// make sure there is some configuration
}
void configure(Dictionary properties) throws ConfigurationException
{
String certHeader = DEFAULT_CERT_HEADER;
String sslHeader = DEFAULT_SSL_HEADER;
String sslValue = DEFAULT_SSL_VALUE;
boolean rewriteUrls = DEFAULT_REWRITE_ABSOLUTE_URLS;
if (properties != null)
{
certHeader = getOptionalString(properties, PROP_SSL_CERT_KEY);
sslHeader = getMandatoryString(properties, PROP_SSL_HEADER);
sslValue = getMandatoryString(properties, PROP_SSL_VALUE);
rewriteUrls = getOptionalBoolean(properties, PROP_REWRITE_ABSOLUTE_URLS, rewriteUrls);
}
this.config = new ConfigHolder(sslHeader, sslValue, certHeader, rewriteUrls);
SystemLogger.log(LogService.LOG_INFO, "SSL filter (re)configured with: " + "SSL forward header = '" + sslHeader + "'; SSL forward value = '" + sslValue + "'; SSL certificate header = '"
+ certHeader + "'.");
}
private boolean getOptionalBoolean(Dictionary properties,
String key,
boolean defaultValue) throws ConfigurationException
{
Object raw = properties.get(key);
if (raw == null)
{
return defaultValue;
}
if ( raw instanceof Boolean )
{
return (Boolean)raw;
}
if (!(raw instanceof String))
{
throw new ConfigurationException(key, "invalid value");
}
return Boolean.valueOf((String)raw);
}
private String getOptionalString(Dictionary properties, String key) throws ConfigurationException
{
Object raw = properties.get(key);
if (raw == null || "".equals(((String) raw).trim()))
{
return null;
}
if (!(raw instanceof String))
{
throw new ConfigurationException(key, "invalid value");
}
return ((String) raw).trim();
}
private String getMandatoryString(Dictionary properties, String key) throws ConfigurationException
{
String value = getOptionalString(properties, key);
if (value == null)
{
throw new ConfigurationException(key, "missing value");
}
return value;
}
static class ConfigHolder
{
final String certHeader;
final String sslHeader;
final String sslValue;
final boolean rewriteAbsoluteUrls;
public ConfigHolder(String sslHeader, String sslValue, String certHeader,
boolean rewriteAbsoluteUrls)
{
this.sslHeader = sslHeader;
this.sslValue = sslValue;
this.certHeader = certHeader;
this.rewriteAbsoluteUrls = rewriteAbsoluteUrls;
}
}
}