You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by cz...@apache.org on 2011/08/03 09:49:45 UTC

svn commit: r1153377 - in /sling/trunk/contrib/extensions/security/src: main/java/org/apache/sling/security/impl/ReferrerFilter.java main/resources/OSGI-INF/metatype/metatype.properties test/java/org/apache/sling/security/impl/ReferrerFilterTest.java

Author: cziegeler
Date: Wed Aug  3 07:49:44 2011
New Revision: 1153377

URL: http://svn.apache.org/viewvc?rev=1153377&view=rev
Log:
SLING-2141 : Update localhost and server handling

Modified:
    sling/trunk/contrib/extensions/security/src/main/java/org/apache/sling/security/impl/ReferrerFilter.java
    sling/trunk/contrib/extensions/security/src/main/resources/OSGI-INF/metatype/metatype.properties
    sling/trunk/contrib/extensions/security/src/test/java/org/apache/sling/security/impl/ReferrerFilterTest.java

Modified: sling/trunk/contrib/extensions/security/src/main/java/org/apache/sling/security/impl/ReferrerFilter.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/security/src/main/java/org/apache/sling/security/impl/ReferrerFilter.java?rev=1153377&r1=1153376&r2=1153377&view=diff
==============================================================================
--- sling/trunk/contrib/extensions/security/src/main/java/org/apache/sling/security/impl/ReferrerFilter.java (original)
+++ sling/trunk/contrib/extensions/security/src/main/java/org/apache/sling/security/impl/ReferrerFilter.java Wed Aug  3 07:49:44 2011
@@ -17,6 +17,18 @@
 package org.apache.sling.security.impl;
 
 import java.io.IOException;
+import java.net.Inet4Address;
+import java.net.Inet6Address;
+import java.net.InetAddress;
+import java.net.MalformedURLException;
+import java.net.NetworkInterface;
+import java.net.SocketException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
 
 import javax.servlet.Filter;
 import javax.servlet.FilterChain;
@@ -45,56 +57,144 @@ public class ReferrerFilter implements F
     private final Logger logger = LoggerFactory.getLogger(this.getClass());
 
     /** Default value for allow empty. */
-    private static final boolean DEFAULT_ALLOW_EMPTY = true;
+    private static final boolean DEFAULT_ALLOW_EMPTY = false;
 
     /** Allow empty property. */
     @Property(boolValue=DEFAULT_ALLOW_EMPTY)
     private static final String PROP_ALLOW_EMPTY = "allow.empty";
 
-    /** Default value for allow localhost. */
-    private static final boolean DEFAULT_ALLOW_LOCALHOST = true;
-
-    /** Allow localhost property. */
-    @Property(boolValue=DEFAULT_ALLOW_LOCALHOST)
-    private static final String PROP_ALLOW_LOCALHOST = "allow.localhost";
-
     /** Allow empty property. */
     @Property(unbounded=PropertyUnbounded.ARRAY)
     private static final String PROP_HOSTS = "allow.hosts";
 
+    /** Allow empty property. */
+    @Property(unbounded=PropertyUnbounded.ARRAY, value={"POST", "PUT", "DELETE"})
+    private static final String PROP_METHODS = "filter.methods";
+
     /** Do we allow empty referrer? */
     private boolean allowEmpty;
 
-    /** Do we allow localhost referrer? */
-    private boolean allowLocalhost;
+    /** Allowed referrers */
+    private URL[] allowedReferrers;
+
+    /** Methods to be filtered. */
+    private String[] filterMethods;
+
+    /**
+     * Create a default list of referrers
+     */
+    private Set<String> getDefaultAllowedReferrers() {
+        final Set<String> referrers = new HashSet<String>();
+        try {
+            final Enumeration<NetworkInterface> ifaces = NetworkInterface.getNetworkInterfaces();
+
+            while(ifaces.hasMoreElements()){
+                final NetworkInterface iface = ifaces.nextElement();
+                logger.info("Adding Allowed referers for Interface:" + iface.getDisplayName());
+                final Enumeration<InetAddress> ias = iface.getInetAddresses();
+                while(ias.hasMoreElements()){
+                    final InetAddress ia = ias.nextElement();
+                    final String address = ia.getHostAddress().trim().toLowerCase();
+                    final String name = ia.getHostName().trim().toLowerCase();
+                    if ( ia instanceof Inet4Address ) {
+                        referrers.add("http://" + address + ":0");
+                        referrers.add("https://" + address + ":0");
+                        referrers.add("http://" + name + ":0");
+                        referrers.add("https://" + name + ":0");
+                        if (name.indexOf('.')>-1){
+                            int index = name.indexOf('.');
+                            String host = name.substring(0, index);
+                            referrers.add("http://" + host.trim().toLowerCase() + ":0");
+                            referrers.add("https://" + host.trim().toLowerCase() + ":0");
+                        }
+                    }
+                    if ( ia instanceof Inet6Address ) {
+                        referrers.add("http://[" + address + "]" + ":0");
+                        referrers.add("https://[" + address + "]" + ":0");
+                        referrers.add("http://[" + name + "]" + ":0");
+                        referrers.add("https://[" + name + "]" + ":0");
+                    }
+                }
+            }
+        } catch ( final SocketException se) {
+            logger.error("Unable to detect network interfaces", se);
+        }
+        referrers.add("http://localhost" + ":0");
+        referrers.add("http://127.0.0.1" + ":0");
+        referrers.add("http://[::1]" + ":0");
+        referrers.add("https://localhost" + ":0");
+        referrers.add("https://127.0.0.1" + ":0");
+        referrers.add("https://[::1]" + ":0");
+        return referrers;
+    }
 
-    /** Allowed hosts */
-    private String[] allowHosts;
+    private void add(final List<URL> urls, final String ref) {
+        try {
+            final URL u  = new URL(ref);
+            urls.add(u);
+        } catch (final MalformedURLException mue) {
+            logger.warn("Unable to create URL from " + ref + " : " + mue.getMessage());
+        }
+    }
+
+    /**
+     * Create URLs out of the referrer list
+     */
+    private URL[] createReferrerUrls(final Set<String> referrers) {
+        final List<URL> urls = new ArrayList<URL>();
+
+        for(final String ref : referrers) {
+            final int pos = ref.indexOf("://");
+            // valid url?
+            if ( pos != -1 ) {
+                this.add(urls, ref);
+            } else {
+                this.add(urls, "http://" + ref + ":0");
+                this.add(urls, "https://" + ref + ":0");
+            }
+        }
+        return urls.toArray(new URL[urls.size()]);
+    }
 
     /**
      * Activate
      */
     protected void activate(final ComponentContext ctx) {
         this.allowEmpty = OsgiUtil.toBoolean(ctx.getProperties().get(PROP_ALLOW_EMPTY), DEFAULT_ALLOW_EMPTY);
-        this.allowHosts = OsgiUtil.toStringArray(ctx.getProperties().get(PROP_HOSTS));
-        this.allowLocalhost = OsgiUtil.toBoolean(ctx.getProperties().get(PROP_ALLOW_LOCALHOST), DEFAULT_ALLOW_LOCALHOST);
-        if ( this.allowHosts != null ) {
-            if ( this.allowHosts.length == 0 ) {
-                this.allowHosts = null;
-            } else if ( this.allowHosts.length == 1 && this.allowHosts[0].trim().length() == 0 ) {
-                this.allowHosts = null;
+        String[] allowHosts = OsgiUtil.toStringArray(ctx.getProperties().get(PROP_HOSTS));
+        if ( allowHosts != null ) {
+            if ( allowHosts.length == 0 ) {
+                allowHosts = null;
+            } else if ( allowHosts.length == 1 && allowHosts[0].trim().length() == 0 ) {
+                allowHosts = null;
+            }
+        }
+        final Set<String> allowedReferrers = this.getDefaultAllowedReferrers();
+        if ( allowHosts != null ) {
+            for(final String host : allowHosts) {
+                allowedReferrers.add(host);
+            }
+        }
+        this.allowedReferrers = this.createReferrerUrls(allowedReferrers);
+        this.filterMethods = OsgiUtil.toStringArray(ctx.getProperties().get(PROP_METHODS));
+        if ( this.filterMethods != null && this.filterMethods.length == 1 && (this.filterMethods[0] == null || this.filterMethods[0].trim().length() == 0) ) {
+            this.filterMethods = null;
+        }
+        if ( this.filterMethods != null ) {
+            for(int i=0; i<filterMethods.length; i++) {
+                filterMethods[i] = filterMethods[i].toUpperCase();
             }
         }
     }
 
     private boolean isModification(final HttpServletRequest req) {
         final String method = req.getMethod();
-        if ("POST".equals(method)) {
-            return true;
-        } else if ("PUT".equals(method)) {
-            return true;
-        } else if ("DELETE".equals(method)) {
-            return true;
+        if ( filterMethods != null ) {
+            for(final String m : filterMethods) {
+                if ( m.equals(method) ) {
+                    return true;
+                }
+            }
         }
         return false;
     }
@@ -119,12 +219,21 @@ public class ReferrerFilter implements F
         chain.doFilter(req, res);
     }
 
-    String getHost(final String referrer) {
+    final static class HostInfo {
+        public String host;
+        public String scheme;
+        public int port;
+    }
+
+    HostInfo getHost(final String referrer) {
         final int startPos = referrer.indexOf("://") + 3;
         if ( startPos == 2 ) {
             // we consider this illegal
             return null;
         }
+        final HostInfo info = new HostInfo();
+        info.scheme = referrer.substring(0, startPos - 3);
+
         final int paramStart = referrer.indexOf('?');
         final String hostAndPath = (paramStart == -1 ? referrer : referrer.substring(0, paramStart));
         final int endPos = hostAndPath.indexOf('/', startPos);
@@ -132,9 +241,17 @@ public class ReferrerFilter implements F
         final int hostNameStart = hostPart.indexOf('@') + 1;
         final int hostNameEnd = hostPart.lastIndexOf(':');
         if (hostNameEnd < hostNameStart ) {
-            return hostPart.substring(hostNameStart);
+            info.host = hostPart.substring(hostNameStart);
+            if ( info.scheme.equals("http") ) {
+                info.port = 80;
+            } else if ( info.scheme.equals("https") ) {
+                info.port = 443;
+            }
+        } else {
+            info.host = hostPart.substring(hostNameStart, hostNameEnd);
+            info.port = Integer.valueOf(hostPart.substring(hostNameEnd + 1));
         }
-        return hostPart.substring(hostNameStart, hostNameEnd);
+        return info;
     }
 
     boolean isValidRequest(final HttpServletRequest request) {
@@ -151,33 +268,22 @@ public class ReferrerFilter implements F
             return true;
         }
 
-        final String host = getHost(referrer);
-        if ( host == null ) {
+        final HostInfo info = getHost(referrer);
+        if ( info == null ) {
             // if this is invalid we just return invalid
             this.logger.info("Rejected illegal referrer header for {} request to {} : {}",
                     new Object[] {request.getMethod(), request.getRequestURI(), referrer});
             return false;
         }
-        final boolean valid;
-        boolean isValidLocalHost = false;
-        if ( this.allowLocalhost ) {
-            if ( "localhost".equals(host) || "127.0.0.1".equals(host) ) {
-                isValidLocalHost = true;
-            }
-        }
-        if ( isValidLocalHost ) {
-            valid = true;
-        } else if ( this.allowHosts == null ) {
-            valid = host.equals(request.getServerName());
-        } else {
-            boolean flag = false;
-            for(final String allowHost : this.allowHosts) {
-                if ( host.equals(allowHost) ) {
-                    flag = true;
+
+        boolean valid = false;
+        for(final URL ref : this.allowedReferrers) {
+            if ( info.host.equals(ref.getHost()) && info.scheme.equals(ref.getProtocol()) ) {
+                if ( ref.getPort() == 0 || info.port == ref.getPort() ) {
+                    valid = true;
                     break;
                 }
             }
-            valid = flag;
         }
         if ( !valid) {
             this.logger.info("Rejected referrer header for {} request to {} : {}",

Modified: sling/trunk/contrib/extensions/security/src/main/resources/OSGI-INF/metatype/metatype.properties
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/security/src/main/resources/OSGI-INF/metatype/metatype.properties?rev=1153377&r1=1153376&r2=1153377&view=diff
==============================================================================
--- sling/trunk/contrib/extensions/security/src/main/resources/OSGI-INF/metatype/metatype.properties (original)
+++ sling/trunk/contrib/extensions/security/src/main/resources/OSGI-INF/metatype/metatype.properties Wed Aug  3 07:49:44 2011
@@ -31,8 +31,8 @@ allow.empty.name = Allow Empty
 allow.empty.description = Allow an empty or missing referrer
 
 allow.hosts.name = Allow Hosts
-allow.hosts.description = List of allowed hosts for the referrer. If this is empty only the server\
- host is allowed. If this is set, it must include the server host name!
+allow.hosts.description = List of allowed hosts for the referrer. If this is empty only the default\
+ hosts are allowed.
 
-allow.localhost.name = Allow Localhost
-allow.localhost.description = If this is enabled, 'localhost' and '127.0.0.1' are always allowed.
\ No newline at end of file
+filter.methods.name = Filter Methods
+filter.methods.description = These methods are filtered by the filter.
\ No newline at end of file

Modified: sling/trunk/contrib/extensions/security/src/test/java/org/apache/sling/security/impl/ReferrerFilterTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/security/src/test/java/org/apache/sling/security/impl/ReferrerFilterTest.java?rev=1153377&r1=1153376&r2=1153377&view=diff
==============================================================================
--- sling/trunk/contrib/extensions/security/src/test/java/org/apache/sling/security/impl/ReferrerFilterTest.java (original)
+++ sling/trunk/contrib/extensions/security/src/test/java/org/apache/sling/security/impl/ReferrerFilterTest.java Wed Aug  3 07:49:44 2011
@@ -42,20 +42,20 @@ public class ReferrerFilterTest {
     }
 
     @Test public void testHostName() {
-        Assert.assertEquals("somehost", filter.getHost("http://somehost"));
-        Assert.assertEquals("somehost", filter.getHost("http://somehost/somewhere"));
-        Assert.assertEquals("somehost", filter.getHost("http://somehost:4242/somewhere"));
-        Assert.assertEquals("somehost", filter.getHost("http://admin@somehost/somewhere"));
-        Assert.assertEquals("somehost", filter.getHost("http://admin@somehost/somewhere?invald=@gagga"));
-        Assert.assertEquals("somehost", filter.getHost("http://admin@somehost:1/somewhere"));
-        Assert.assertEquals("somehost", filter.getHost("http://admin:admin@somehost/somewhere"));
-        Assert.assertEquals("somehost", filter.getHost("http://admin:admin@somehost:4343/somewhere"));
-        Assert.assertEquals("localhost", filter.getHost("http://localhost"));
-        Assert.assertEquals("127.0.0.1", filter.getHost("http://127.0.0.1"));
-        Assert.assertEquals("localhost", filter.getHost("http://localhost:535"));
-        Assert.assertEquals("127.0.0.1", filter.getHost("http://127.0.0.1:242"));
-        Assert.assertEquals("localhost", filter.getHost("http://localhost:256235/etewteq.ff"));
-        Assert.assertEquals("127.0.0.1", filter.getHost("http://127.0.0.1/wetew.qerq"));
+        Assert.assertEquals("somehost", filter.getHost("http://somehost").host);
+        Assert.assertEquals("somehost", filter.getHost("http://somehost/somewhere").host);
+        Assert.assertEquals("somehost", filter.getHost("http://somehost:4242/somewhere").host);
+        Assert.assertEquals("somehost", filter.getHost("http://admin@somehost/somewhere").host);
+        Assert.assertEquals("somehost", filter.getHost("http://admin@somehost/somewhere?invald=@gagga").host);
+        Assert.assertEquals("somehost", filter.getHost("http://admin@somehost:1/somewhere").host);
+        Assert.assertEquals("somehost", filter.getHost("http://admin:admin@somehost/somewhere").host);
+        Assert.assertEquals("somehost", filter.getHost("http://admin:admin@somehost:4343/somewhere").host);
+        Assert.assertEquals("localhost", filter.getHost("http://localhost").host);
+        Assert.assertEquals("127.0.0.1", filter.getHost("http://127.0.0.1").host);
+        Assert.assertEquals("localhost", filter.getHost("http://localhost:535").host);
+        Assert.assertEquals("127.0.0.1", filter.getHost("http://127.0.0.1:242").host);
+        Assert.assertEquals("localhost", filter.getHost("http://localhost:256235/etewteq.ff").host);
+        Assert.assertEquals("127.0.0.1", filter.getHost("http://127.0.0.1/wetew.qerq").host);
         Assert.assertEquals(null, filter.getHost("http:/admin:admin@somehost:4343/somewhere"));
     }
 
@@ -64,20 +64,17 @@ public class ReferrerFilterTest {
         when(request.getMethod()).thenReturn("POST");
         when(request.getRequestURI()).thenReturn("http://somehost/somewhere");
         when(request.getHeader("referer")).thenReturn(referrer);
-        when(request.getServerName()).thenReturn("me");
         return request;
     }
 
     @Test public void testValidRequest() {
-        Assert.assertEquals(true, filter.isValidRequest(getRequest(null)));
+        Assert.assertEquals(false, filter.isValidRequest(getRequest(null)));
         Assert.assertEquals(true, filter.isValidRequest(getRequest("relative")));
         Assert.assertEquals(true, filter.isValidRequest(getRequest("/relative/too")));
         Assert.assertEquals(true, filter.isValidRequest(getRequest("/relative/but/[illegal]")));
         Assert.assertEquals(false, filter.isValidRequest(getRequest("http://somehost")));
-        Assert.assertEquals(true, filter.isValidRequest(getRequest("http://me")));
         Assert.assertEquals(true, filter.isValidRequest(getRequest("http://localhost")));
         Assert.assertEquals(true, filter.isValidRequest(getRequest("http://127.0.0.1")));
         Assert.assertEquals(false, filter.isValidRequest(getRequest("http://somehost/but/[illegal]")));
-        Assert.assertEquals(true, filter.isValidRequest(getRequest("http://me/but/[illegal]")));
     }
 }