You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@felix.apache.org by fm...@apache.org on 2013/10/18 14:28:15 UTC

svn commit: r1533418 - in /felix/trunk/http/sslfilter/src: main/java/org/apache/felix/http/sslfilter/internal/ test/java/org/apache/felix/http/sslfilter/internal/

Author: fmeschbe
Date: Fri Oct 18 12:28:14 2013
New Revision: 1533418

URL: http://svn.apache.org/r1533418
Log:
FELIX-4230 Convert X-Forwarded-SSL-Certificate header to javax.servlet.request.X509Certificate request attribute for consumption by the web application.

Modified:
    felix/trunk/http/sslfilter/src/main/java/org/apache/felix/http/sslfilter/internal/SslFilter.java
    felix/trunk/http/sslfilter/src/main/java/org/apache/felix/http/sslfilter/internal/SslFilterRequest.java
    felix/trunk/http/sslfilter/src/test/java/org/apache/felix/http/sslfilter/internal/SslFilterRequestTest.java

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=1533418&r1=1533417&r2=1533418&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 Fri Oct 18 12:28:14 2013
@@ -19,7 +19,6 @@
 package org.apache.felix.http.sslfilter.internal;
 
 import java.io.IOException;
-
 import javax.servlet.Filter;
 import javax.servlet.FilterChain;
 import javax.servlet.FilterConfig;
@@ -37,6 +36,9 @@ public class SslFilter implements Filter
     // value indicating an SSL endpoint proxy
     private static final String X_FORWARD_SSL_VALUE = "on";
 
+    // request header indicating an SSL client certificate (if available)
+    private static final String X_FORWARD_SSL_CERTIFICATE_HEADER = "X-Forwarded-SSL-Certificate";
+
     public void init(FilterConfig config)
     {
     }
@@ -44,15 +46,25 @@ public class SslFilter implements Filter
     public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException,
         ServletException
     {
-
         HttpServletRequest httpReq = (HttpServletRequest) req;
-
         if (X_FORWARD_SSL_VALUE.equalsIgnoreCase(httpReq.getHeader(X_FORWARD_SSL_HEADER)))
         {
-            httpReq = new SslFilterRequest(httpReq);
+            httpReq = new SslFilterRequest(httpReq, httpReq.getHeader(X_FORWARD_SSL_CERTIFICATE_HEADER));
         }
 
-        chain.doFilter(httpReq, res);
+        // forward the request making sure any certificate is removed
+        // again after the request processing gets back here
+        try
+        {
+            chain.doFilter(httpReq, res);
+        }
+        finally
+        {
+            if (httpReq instanceof SslFilterRequest)
+            {
+                ((SslFilterRequest) httpReq).done();
+            }
+        }
     }
 
     public void destroy()

Modified: felix/trunk/http/sslfilter/src/main/java/org/apache/felix/http/sslfilter/internal/SslFilterRequest.java
URL: http://svn.apache.org/viewvc/felix/trunk/http/sslfilter/src/main/java/org/apache/felix/http/sslfilter/internal/SslFilterRequest.java?rev=1533418&r1=1533417&r2=1533418&view=diff
==============================================================================
--- felix/trunk/http/sslfilter/src/main/java/org/apache/felix/http/sslfilter/internal/SslFilterRequest.java (original)
+++ felix/trunk/http/sslfilter/src/main/java/org/apache/felix/http/sslfilter/internal/SslFilterRequest.java Fri Oct 18 12:28:14 2013
@@ -18,6 +18,15 @@
  */
 package org.apache.felix.http.sslfilter.internal;
 
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.util.Collection;
+import java.util.regex.Pattern;
+
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletRequestWrapper;
 
@@ -30,11 +39,59 @@ class SslFilterRequest extends HttpServl
     // The HTTP scheme prefix in an URL
     private static final String HTTP_SCHEME_PREFIX = "http://";
 
+    // pattern to convert the header to a PEM certificate for parsing
+    // by replacing spaces with line breaks
+    private static Pattern HEADER_TO_CERT = Pattern.compile("(?! CERTIFICATE)(?= ) ");
+
+    // character encoding for the client certificate header
+    private static final String UTF_8 = "UTF-8";
+
+    /**
+     * If there is an SSL certificate associated with the request, it must be
+     * exposed by the servlet container to the servlet programmer as an array of
+     * objects of type java.security.cert.X509Certificate and accessible via a
+     * ServletRequest attribute of javax.servlet.request.X509Certificate.
+     * <p>
+     * The order of this array is defined as being in ascending order of trust.
+     * The first certificate in the chain is the one set by the client, the next
+     * is the one used to authenticate the first, and so on.
+     */
+    private static final String ATTR_SSL_CERTIFICATE = "javax.servlet.request.X509Certificate";
+
     private String requestURL;
 
-    SslFilterRequest(HttpServletRequest request)
+    SslFilterRequest(final HttpServletRequest request, final String clientCertHeader)
     {
         super(request);
+
+        if (clientCertHeader != null && clientCertHeader.length() > 0)
+        {
+
+            final String clientCert = HEADER_TO_CERT.matcher(clientCertHeader).replaceAll("\n");
+
+            try
+            {
+                InputStream instream = new ByteArrayInputStream(clientCert.getBytes(UTF_8));
+                CertificateFactory fac = CertificateFactory.getInstance("X.509");
+                @SuppressWarnings("unchecked")
+                Collection<X509Certificate> certs = (Collection<X509Certificate>) fac.generateCertificates(instream);
+                request.setAttribute(ATTR_SSL_CERTIFICATE, certs.toArray(new X509Certificate[certs.size()]));
+            }
+            catch (CertificateException e)
+            {
+                // TODO Auto-generated catch block
+                e.printStackTrace();
+            }
+            catch (UnsupportedEncodingException e)
+            {
+                // TODO Auto-generated catch block
+                e.printStackTrace();
+            }
+        }
+    }
+
+    void done() {
+        getRequest().removeAttribute(ATTR_SSL_CERTIFICATE);
     }
 
     public String getScheme()
@@ -64,4 +121,8 @@ class SslFilterRequest extends HttpServl
 
         return new StringBuffer(this.requestURL);
     }
+
+    private final void provideCertificate(final HttpServletRequest request) throws UnsupportedEncodingException
+    {
+    }
 }

Modified: felix/trunk/http/sslfilter/src/test/java/org/apache/felix/http/sslfilter/internal/SslFilterRequestTest.java
URL: http://svn.apache.org/viewvc/felix/trunk/http/sslfilter/src/test/java/org/apache/felix/http/sslfilter/internal/SslFilterRequestTest.java?rev=1533418&r1=1533417&r2=1533418&view=diff
==============================================================================
--- felix/trunk/http/sslfilter/src/test/java/org/apache/felix/http/sslfilter/internal/SslFilterRequestTest.java (original)
+++ felix/trunk/http/sslfilter/src/test/java/org/apache/felix/http/sslfilter/internal/SslFilterRequestTest.java Fri Oct 18 12:28:14 2013
@@ -34,7 +34,7 @@ public class SslFilterRequestTest
     public void test_isSecure()
     {
         HttpServletRequest req = Mockito.mock(HttpServletRequest.class);
-        SslFilterRequest sreq = new SslFilterRequest(req);
+        SslFilterRequest sreq = new SslFilterRequest(req, null);
 
         when(req.isSecure()).thenReturn(false);
         TestCase.assertFalse(req.isSecure());
@@ -51,7 +51,7 @@ public class SslFilterRequestTest
     public void test_getScheme()
     {
         HttpServletRequest req = Mockito.mock(HttpServletRequest.class);
-        SslFilterRequest sreq = new SslFilterRequest(req);
+        SslFilterRequest sreq = new SslFilterRequest(req, null);
 
         when(req.getScheme()).thenReturn("http");
         TestCase.assertEquals("http", req.getScheme());
@@ -68,7 +68,7 @@ public class SslFilterRequestTest
     public void test_getRequestURL()
     {
         HttpServletRequest req = Mockito.mock(HttpServletRequest.class);
-        SslFilterRequest sreq = new SslFilterRequest(req);
+        SslFilterRequest sreq = new SslFilterRequest(req, null);
 
         when(req.getRequestURL()).thenReturn(new StringBuffer("http://some/page"));
         TestCase.assertEquals("http://some/page", req.getRequestURL().toString());