This is an automated email from the ASF dual-hosted git repository. rombert pushed a commit to annotated tag org.apache.sling.security-1.0.0 in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-security.git
commit 2989f952235cf82cd03bddc03e72f7a93278dcfd Author: Carsten Ziegeler <[email protected]> AuthorDate: Wed Aug 3 07:49:44 2011 +0000 SLING-2141 : Update localhost and server handling git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/contrib/extensions/security@1153377 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/sling/security/impl/ReferrerFilter.java | 200 ++++++++++++++++----- .../OSGI-INF/metatype/metatype.properties | 8 +- .../sling/security/impl/ReferrerFilterTest.java | 33 ++-- 3 files changed, 172 insertions(+), 69 deletions(-) diff --git a/src/main/java/org/apache/sling/security/impl/ReferrerFilter.java b/src/main/java/org/apache/sling/security/impl/ReferrerFilter.java index b27ec45..9339900 100644 --- a/src/main/java/org/apache/sling/security/impl/ReferrerFilter.java +++ b/src/main/java/org/apache/sling/security/impl/ReferrerFilter.java @@ -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 Filter { 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; - /** Allowed hosts */ - private String[] allowHosts; + /** 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; + } + + 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 Filter { 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 Filter { 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 Filter { 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 {} : {}", diff --git a/src/main/resources/OSGI-INF/metatype/metatype.properties b/src/main/resources/OSGI-INF/metatype/metatype.properties index 72ac2f5..f536075 100644 --- a/src/main/resources/OSGI-INF/metatype/metatype.properties +++ b/src/main/resources/OSGI-INF/metatype/metatype.properties @@ -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 diff --git a/src/test/java/org/apache/sling/security/impl/ReferrerFilterTest.java b/src/test/java/org/apache/sling/security/impl/ReferrerFilterTest.java index cd41e10..f892a97 100644 --- a/src/test/java/org/apache/sling/security/impl/ReferrerFilterTest.java +++ b/src/test/java/org/apache/sling/security/impl/ReferrerFilterTest.java @@ -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]"))); } } -- To stop receiving notification emails like this one, please contact "[email protected]" <[email protected]>.
