Return-Path: X-Original-To: apmail-felix-commits-archive@www.apache.org Delivered-To: apmail-felix-commits-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 8D8E611E20 for ; Tue, 20 May 2014 12:49:09 +0000 (UTC) Received: (qmail 18272 invoked by uid 500); 20 May 2014 12:49:09 -0000 Delivered-To: apmail-felix-commits-archive@felix.apache.org Received: (qmail 18229 invoked by uid 500); 20 May 2014 12:49:09 -0000 Mailing-List: contact commits-help@felix.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@felix.apache.org Delivered-To: mailing list commits@felix.apache.org Received: (qmail 18222 invoked by uid 99); 20 May 2014 12:49:09 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 20 May 2014 12:49:09 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=5.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 20 May 2014 12:49:07 +0000 Received: from eris.apache.org (localhost [127.0.0.1]) by eris.apache.org (Postfix) with ESMTP id 4F2B92388868; Tue, 20 May 2014 12:48:47 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r1596230 - in /felix/trunk/http/sslfilter: ./ src/main/java/org/apache/felix/http/sslfilter/internal/ src/main/resources/OSGI-INF/ src/main/resources/OSGI-INF/metatype/ Date: Tue, 20 May 2014 12:48:47 -0000 To: commits@felix.apache.org From: jawi@apache.org X-Mailer: svnmailer-1.0.9 Message-Id: <20140520124847.4F2B92388868@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org Author: jawi Date: Tue May 20 12:48:46 2014 New Revision: 1596230 URL: http://svn.apache.org/r1596230 Log: FELIX-4330 - Make SSL headers configurable: - applied a slightly different approach as suggested by [~fmeschbe] by splitting the header name and value into 2 different configuration properties allowing any header variant to be supported; - also made the header used to obtain forwarded client certificates configurable, as it appears to have at least one other representation in the wild; - added metatype description for the managed service to document the configuration properties. Added: felix/trunk/http/sslfilter/src/main/resources/OSGI-INF/ felix/trunk/http/sslfilter/src/main/resources/OSGI-INF/metatype/ felix/trunk/http/sslfilter/src/main/resources/OSGI-INF/metatype/org.apache.felix.http.sslfilter.SslFilter.properties (with props) felix/trunk/http/sslfilter/src/main/resources/OSGI-INF/metatype/org.apache.felix.http.sslfilter.SslFilter.xml (with props) Modified: felix/trunk/http/sslfilter/pom.xml felix/trunk/http/sslfilter/src/main/java/org/apache/felix/http/sslfilter/internal/HttpServiceTracker.java felix/trunk/http/sslfilter/src/main/java/org/apache/felix/http/sslfilter/internal/SslFilter.java Modified: felix/trunk/http/sslfilter/pom.xml URL: http://svn.apache.org/viewvc/felix/trunk/http/sslfilter/pom.xml?rev=1596230&r1=1596229&r2=1596230&view=diff ============================================================================== --- felix/trunk/http/sslfilter/pom.xml (original) +++ felix/trunk/http/sslfilter/pom.xml Tue May 20 12:48:46 2014 @@ -44,6 +44,13 @@ + maven-compiler-plugin + + 1.5 + 1.5 + + + org.apache.felix maven-bundle-plugin true @@ -52,6 +59,13 @@ org.apache.felix.http.sslfilter.internal.SslFilterActivator + + org.osgi.service.cm;resolution:=optional, + * + + + org.osgi.service.cm;version="[1.2,2)" + ) @@ -77,7 +91,7 @@ org.apache.felix org.apache.felix.http.api - 2.3.0-SNAPSHOT + ${felix.http.api.version} Modified: felix/trunk/http/sslfilter/src/main/java/org/apache/felix/http/sslfilter/internal/HttpServiceTracker.java URL: http://svn.apache.org/viewvc/felix/trunk/http/sslfilter/src/main/java/org/apache/felix/http/sslfilter/internal/HttpServiceTracker.java?rev=1596230&r1=1596229&r2=1596230&view=diff ============================================================================== --- felix/trunk/http/sslfilter/src/main/java/org/apache/felix/http/sslfilter/internal/HttpServiceTracker.java (original) +++ felix/trunk/http/sslfilter/src/main/java/org/apache/felix/http/sslfilter/internal/HttpServiceTracker.java Tue May 20 12:48:46 2014 @@ -18,15 +18,24 @@ */ package org.apache.felix.http.sslfilter.internal; -import java.util.HashMap; +import java.util.ArrayList; +import java.util.Dictionary; import java.util.Hashtable; -import java.util.Map; +import java.util.List; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; import javax.servlet.ServletException; import org.apache.felix.http.api.ExtHttpService; +import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; +import org.osgi.framework.Constants; +import org.osgi.framework.ServiceFactory; import org.osgi.framework.ServiceReference; +import org.osgi.framework.ServiceRegistration; +import org.osgi.service.cm.ConfigurationException; +import org.osgi.service.cm.ManagedService; import org.osgi.service.log.LogService; import org.osgi.util.tracker.ServiceTracker; @@ -35,13 +44,56 @@ import org.osgi.util.tracker.ServiceTrac */ public class HttpServiceTracker extends ServiceTracker { - private final Map filters; + private final ConcurrentMap filters; + private ServiceRegistration configReceiver; + + @SuppressWarnings("serial") public HttpServiceTracker(BundleContext context) { super(context, ExtHttpService.class.getName(), null); - this.filters = new HashMap(); + this.filters = new ConcurrentHashMap(); + } + + @Override + public void open(boolean trackAllServices) + { + Dictionary props = new Hashtable(); + props.put(Constants.SERVICE_PID, SslFilter.PID); + + this.configReceiver = super.context.registerService(ManagedService.class.getName(), new ServiceFactory() + { + public Object getService(Bundle bundle, ServiceRegistration registration) + { + return new ManagedService() + { + public void updated(@SuppressWarnings("rawtypes") Dictionary properties) throws ConfigurationException + { + configureFilters(properties); + } + }; + } + + public void ungetService(Bundle bundle, ServiceRegistration registration, Object service) + { + // Nop + } + }, props); + + super.open(trackAllServices); + } + + @Override + public void close() + { + super.close(); + + if (this.configReceiver != null) + { + this.configReceiver.unregister(); + this.configReceiver = null; + } } public Object addingService(ServiceReference reference) @@ -54,7 +106,7 @@ public class HttpServiceTracker extends { service.registerFilter(filter, ".*", new Hashtable(), 0, null); - this.filters.put(reference, filter); + this.filters.putIfAbsent(reference, filter); SystemLogger.log(LogService.LOG_DEBUG, "SSL filter registered..."); } @@ -69,7 +121,7 @@ public class HttpServiceTracker extends public void removedService(ServiceReference reference, Object service) { - SslFilter filter = (SslFilter) this.filters.remove(reference); + SslFilter filter = this.filters.remove(reference); if (filter != null) { ((ExtHttpService) service).unregisterFilter(filter); @@ -79,4 +131,13 @@ public class HttpServiceTracker extends super.removedService(reference, service); } + + void configureFilters(@SuppressWarnings("rawtypes") final Dictionary properties) throws ConfigurationException + { + List filters = new ArrayList(this.filters.values()); + for (SslFilter sslFilter : filters) + { + sslFilter.configure(properties); + } + } } Modified: felix/trunk/http/sslfilter/src/main/java/org/apache/felix/http/sslfilter/internal/SslFilter.java URL: http://svn.apache.org/viewvc/felix/trunk/http/sslfilter/src/main/java/org/apache/felix/http/sslfilter/internal/SslFilter.java?rev=1596230&r1=1596229&r2=1596230&view=diff ============================================================================== --- felix/trunk/http/sslfilter/src/main/java/org/apache/felix/http/sslfilter/internal/SslFilter.java (original) +++ felix/trunk/http/sslfilter/src/main/java/org/apache/felix/http/sslfilter/internal/SslFilter.java Tue May 20 12:48:46 2014 @@ -20,6 +20,7 @@ package org.apache.felix.http.sslfilter. import java.io.IOException; import java.security.cert.CertificateException; +import java.util.Dictionary; import javax.servlet.Filter; import javax.servlet.FilterChain; @@ -29,33 +30,45 @@ import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; +import org.osgi.service.cm.ConfigurationException; import org.osgi.service.log.LogService; public class SslFilter implements Filter { - // request header indicating an SSL endpoint proxy - private static final String X_FORWARD_SSL_HEADER = "X-Forwarded-SSL"; + public static final String PID = "org.apache.felix.http.sslfilter.SslFilter"; - // value indicating an SSL endpoint proxy - private static final String X_FORWARD_SSL_VALUE = "on"; + private static final String DEFAULT_SSL_HEADER = "X-Forwarded-SSL"; + private static final String DEFAULT_SSL_VALUE = "on"; + private static final String DEFAULT_CERT_HEADER = "X-Forwarded-SSL-Certificate"; - // request header indicating an SSL client certificate (if available) - private static final String X_FORWARD_SSL_CERTIFICATE_HEADER = "X-Forwarded-SSL-Certificate"; + 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"; - public void init(FilterConfig config) + private volatile ConfigHolder config; + + SslFilter() + { + this.config = new ConfigHolder(DEFAULT_SSL_HEADER, DEFAULT_SSL_VALUE, DEFAULT_CERT_HEADER); + } + + public void destroy() { - // No explicit initialization needed... + // No explicit destroy needed... } public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { + final ConfigHolder cfg = this.config; + HttpServletRequest httpReq = (HttpServletRequest) req; - if (X_FORWARD_SSL_VALUE.equalsIgnoreCase(httpReq.getHeader(X_FORWARD_SSL_HEADER))) + if (cfg.sslValue.equalsIgnoreCase(httpReq.getHeader(cfg.sslHeader))) { try { - // In case this fails, we fall back to the original HTTP request, which is better than nothing... - httpReq = new SslFilterRequest(httpReq, httpReq.getHeader(X_FORWARD_SSL_CERTIFICATE_HEADER)); + // 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) { @@ -78,8 +91,65 @@ public class SslFilter implements Filter } } - public void destroy() + public void init(FilterConfig config) { - // No explicit destroy needed... + // make sure there is some configuration + } + + void configure(@SuppressWarnings("rawtypes") final Dictionary properties) throws ConfigurationException + { + String certHeader = DEFAULT_CERT_HEADER; + String sslHeader = DEFAULT_SSL_HEADER; + String sslValue = DEFAULT_SSL_VALUE; + + if (properties != null) + { + certHeader = getOptionalString(properties, PROP_SSL_CERT_KEY); + sslHeader = getMandatoryString(properties, PROP_SSL_HEADER); + sslValue = getMandatoryString(properties, PROP_SSL_VALUE); + } + + this.config = new ConfigHolder(sslHeader, sslValue, certHeader); + + SystemLogger.log(LogService.LOG_INFO, "SSL filter (re)configured with: " + "SSL forward header = '" + sslHeader + "'; SSL forward value = '" + sslValue + "'; SSL certificate header = '" + + certHeader + "'."); + } + + private String getOptionalString(@SuppressWarnings("rawtypes") 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(@SuppressWarnings("rawtypes") 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; + + public ConfigHolder(String sslHeader, String sslValue, String certHeader) + { + this.sslHeader = sslHeader; + this.sslValue = sslValue; + this.certHeader = certHeader; + } } } Added: felix/trunk/http/sslfilter/src/main/resources/OSGI-INF/metatype/org.apache.felix.http.sslfilter.SslFilter.properties URL: http://svn.apache.org/viewvc/felix/trunk/http/sslfilter/src/main/resources/OSGI-INF/metatype/org.apache.felix.http.sslfilter.SslFilter.properties?rev=1596230&view=auto ============================================================================== --- felix/trunk/http/sslfilter/src/main/resources/OSGI-INF/metatype/org.apache.felix.http.sslfilter.SslFilter.properties (added) +++ felix/trunk/http/sslfilter/src/main/resources/OSGI-INF/metatype/org.apache.felix.http.sslfilter.SslFilter.properties Tue May 20 12:48:46 2014 @@ -0,0 +1,24 @@ +# 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. +name=Apache Felix Http Service SSL Filter +description=Configuration for the Http Service SSL Filter. Please consult the documentation of your proxy for the actual headers and values to use. +ssl-forward.header.name=SSL forward header +ssl-forward.header.description=HTTP Request header name that indicates a request is a SSL request terminated at a proxy between the client and the originating server. The default value is 'X-Forwarded-SSL' as is customarily used in the wild. Other commonly used names are\: 'X-Forwarded-Proto' (Amazon ELB), 'X-Forwarded-Protocol' (alternative), and 'Front-End-Https' (Microsoft IIS). +ssl-forward.value.name=SSL forward value +ssl-forward.value.description=HTTP Request header value that indicates a request is a SSL request terminated at a proxy. The default value is 'on'. Another commonly used value is 'https'. +ssl-forward-cert.header.name=SSL client header +ssl-forward-cert.header.description=HTTP Request header name that contains the client certificate forwarded by a proxy. The default value is 'X-Forwarded-SSL-Certificate'. Another commonly used value is 'X-Forwarded-SSL-Client-Cert'. Propchange: felix/trunk/http/sslfilter/src/main/resources/OSGI-INF/metatype/org.apache.felix.http.sslfilter.SslFilter.properties ------------------------------------------------------------------------------ svn:eol-style = native Added: felix/trunk/http/sslfilter/src/main/resources/OSGI-INF/metatype/org.apache.felix.http.sslfilter.SslFilter.xml URL: http://svn.apache.org/viewvc/felix/trunk/http/sslfilter/src/main/resources/OSGI-INF/metatype/org.apache.felix.http.sslfilter.SslFilter.xml?rev=1596230&view=auto ============================================================================== --- felix/trunk/http/sslfilter/src/main/resources/OSGI-INF/metatype/org.apache.felix.http.sslfilter.SslFilter.xml (added) +++ felix/trunk/http/sslfilter/src/main/resources/OSGI-INF/metatype/org.apache.felix.http.sslfilter.SslFilter.xml Tue May 20 12:48:46 2014 @@ -0,0 +1,32 @@ + + + + + + + + + + + + Propchange: felix/trunk/http/sslfilter/src/main/resources/OSGI-INF/metatype/org.apache.felix.http.sslfilter.SslFilter.xml ------------------------------------------------------------------------------ svn:eol-style = native Propchange: felix/trunk/http/sslfilter/src/main/resources/OSGI-INF/metatype/org.apache.felix.http.sslfilter.SslFilter.xml ------------------------------------------------------------------------------ svn:mime-type = text/xml