You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by ro...@apache.org on 2017/11/07 10:13:20 UTC
[sling-org-apache-sling-security] 21/30: FELIX-2870 : Support
allowed hosts patterns in ReferrerFilter . Apply patch from Timothee Maret
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.10
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-security.git
commit 45dec5c3941a1c121ca0703aeaac522b6405e4f7
Author: Carsten Ziegeler <cz...@apache.org>
AuthorDate: Wed May 22 08:59:33 2013 +0000
FELIX-2870 : Support allowed hosts patterns in ReferrerFilter . Apply patch from Timothee Maret
git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/contrib/extensions/security@1485123 13f79535-47bb-0310-9956-ffa450edef68
---
.../apache/sling/security/impl/ReferrerFilter.java | 130 ++++++++++++++++-----
.../OSGI-INF/metatype/metatype.properties | 9 +-
.../sling/security/impl/ReferrerFilterTest.java | 14 ++-
3 files changed, 116 insertions(+), 37 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 000f463..e3dfa5d 100644
--- a/src/main/java/org/apache/sling/security/impl/ReferrerFilter.java
+++ b/src/main/java/org/apache/sling/security/impl/ReferrerFilter.java
@@ -26,12 +26,14 @@ import java.net.NetworkInterface;
import java.net.SocketException;
import java.net.URL;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Dictionary;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.List;
import java.util.Set;
+import java.util.regex.Pattern;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
@@ -93,19 +95,30 @@ public class ReferrerFilter implements Filter {
@Property(boolValue=DEFAULT_ALLOW_EMPTY)
private static final String PROP_ALLOW_EMPTY = "allow.empty";
- /** Allow empty property. */
+ private static final String[] DEFAULT_PROP_HOSTS = {};
+
+ /** Allow referrer uri hosts property. */
@Property(unbounded=PropertyUnbounded.ARRAY)
private static final String PROP_HOSTS = "allow.hosts";
- /** Allow empty property. */
+ /** Allow referrer regex hosts property */
+ @Property(unbounded=PropertyUnbounded.ARRAY)
+ private static final String PROP_HOSTS_REGEX = "allow.hosts.regexp";
+
+ /** Filtered methods 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;
- /** Allowed referrers */
- private URL[] allowedReferrers;
+ /** Allowed uri referrers */
+ private URL[] allowedUriReferrers;
+
+ /** Allowed regexp referrers */
+ private Pattern[] allowedRegexReferrers;
/** Methods to be filtered. */
private String[] filterMethods;
@@ -160,7 +173,7 @@ public class ReferrerFilter implements Filter {
}
/**
- * Create URLs out of the referrer list
+ * Create URLs out of the uri referrer set
*/
private URL[] createReferrerUrls(final Set<String> referrers) {
final List<URL> urls = new ArrayList<URL>();
@@ -179,27 +192,41 @@ public class ReferrerFilter implements Filter {
}
/**
+ * Create Patterns out of the regexp referrer list
+ */
+ private Pattern[] createReferrerPatterns(final String[] regexps) {
+ final List<Pattern> patterns = new ArrayList<Pattern>();
+ for(final String regexp : regexps) {
+ try {
+ final Pattern pattern = Pattern.compile(regexp);
+ patterns.add(pattern);
+ } catch (final Exception e) {
+ logger.warn("Unable to create Pattern from {} : {}", new String[]{regexp, e.getMessage()});
+ }
+ }
+ return patterns.toArray(new Pattern[patterns.size()]);
+ }
+
+ /**
* Activate
*/
@Activate
protected void activate(final ComponentContext ctx) {
- this.allowEmpty = PropertiesUtil.toBoolean(ctx.getProperties().get(PROP_ALLOW_EMPTY), DEFAULT_ALLOW_EMPTY);
- String[] allowHosts = PropertiesUtil.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 = PropertiesUtil.toStringArray(ctx.getProperties().get(PROP_METHODS));
+ final Dictionary props = ctx.getProperties();
+
+ this.allowEmpty = PropertiesUtil.toBoolean(props.get(PROP_ALLOW_EMPTY), DEFAULT_ALLOW_EMPTY);
+
+ final String[] allowRegexHosts = defaultIfEmpty(PropertiesUtil.toStringArray(props.get(PROP_HOSTS_REGEX),
+ DEFAULT_PROP_HOSTS), DEFAULT_PROP_HOSTS);
+ this.allowedRegexReferrers = createReferrerPatterns(allowRegexHosts);
+
+ final Set<String> allowUriReferrers = getDefaultAllowedReferrers();
+ final String[] allowHosts = defaultIfEmpty(PropertiesUtil.toStringArray(props.get(PROP_HOSTS),
+ DEFAULT_PROP_HOSTS), DEFAULT_PROP_HOSTS);
+ allowUriReferrers.addAll(Arrays.asList(allowHosts));
+ this.allowedUriReferrers = createReferrerUrls(allowUriReferrers);
+
+ this.filterMethods = PropertiesUtil.toStringArray(props.get(PROP_METHODS));
if ( this.filterMethods != null && this.filterMethods.length == 1 && (this.filterMethods[0] == null || this.filterMethods[0].trim().length() == 0) ) {
this.filterMethods = null;
}
@@ -267,6 +294,9 @@ public class ReferrerFilter implements Filter {
public String host;
public String scheme;
public int port;
+ public String toURI() {
+ return scheme + "://" + host + ":" + port;
+ }
}
HostInfo getHost(final String referrer) {
@@ -330,15 +360,9 @@ public class ReferrerFilter implements Filter {
return 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;
- }
- }
- }
+ // allow the request if the referrer matches any of the allowed referrers
+ boolean valid = isValidUriReferrer(info) || isValidRegexReferrer(info);
+
if ( !valid) {
this.logger.info("Rejected referrer header for {} request to {} : {}",
new Object[] {request.getMethod(), request.getRequestURI(), referrer});
@@ -361,6 +385,45 @@ public class ReferrerFilter implements Filter {
}
/**
+ * @param hostInfo The hostInfo to check for validity
+ * @return <code>true</code> if the hostInfo matches any of the allowed URI referrer.
+ */
+ private boolean isValidUriReferrer(HostInfo hostInfo) {
+ for(final URL ref : this.allowedUriReferrers) {
+ if ( hostInfo.host.equals(ref.getHost()) && hostInfo.scheme.equals(ref.getProtocol()) ) {
+ if ( ref.getPort() == 0 || hostInfo.port == ref.getPort() ) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * @param hostInfo The hostInfo to check for validity
+ * @return <code>true</code> if the hostInfo matches any of the allowed regexp referrer.
+ */
+ private boolean isValidRegexReferrer(HostInfo hostInfo) {
+ for(final Pattern ref : this.allowedRegexReferrers) {
+ String url = hostInfo.toURI();
+ if (ref.matcher(url).matches()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * @return The <code>defaultProperties</code> if <code>properties</code> contains a single empty string,
+ * <code>properties</code> otherwise.
+ */
+ private String[] defaultIfEmpty(String[] properties, String[] defaultProperties) {
+ return properties.length == 1 && properties[0].trim().length() == 0
+ ? defaultProperties
+ : properties;
+ }
+
+ /**
* Returns <code>true</code> if the given request can be assumed to be sent
* by a client browser such as Firefix, Internet Explorer, etc.
* <p>
@@ -391,9 +454,12 @@ public class ReferrerFilter implements Filter {
public void printConfiguration(final PrintWriter pw) {
pw.println("Current Apache Sling Referrer Filter Allowed Referrers:");
pw.println();
- for (final URL url : allowedReferrers) {
+ for (final URL url : allowedUriReferrers) {
pw.println(url.toString());
}
+ for (final Pattern pattern : allowedRegexReferrers) {
+ pw.println(pattern.toString());
+ }
}
}
diff --git a/src/main/resources/OSGI-INF/metatype/metatype.properties b/src/main/resources/OSGI-INF/metatype/metatype.properties
index f536075..0905fb1 100644
--- a/src/main/resources/OSGI-INF/metatype/metatype.properties
+++ b/src/main/resources/OSGI-INF/metatype/metatype.properties
@@ -25,14 +25,17 @@
#
# Referrer Filter
referrer.name = Apache Sling Referrer Filter
-referrer.description = Request filter checking the referrer of modification requests.
+referrer.description = Request filter checking the referrer of modification requests.
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 default\
- hosts are allowed.
+allow.hosts.description = List of allowed hosts for the referrer which are added to the list of default hosts.
+
+
+allow.hosts.regexp.name = Allow Regexp Host
+allow.hosts.regexp.description = List of allowed regexp for the referrer.
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 136cb28..567246e 100644
--- a/src/test/java/org/apache/sling/security/impl/ReferrerFilterTest.java
+++ b/src/test/java/org/apache/sling/security/impl/ReferrerFilterTest.java
@@ -17,7 +17,6 @@
package org.apache.sling.security.impl;
import static org.mockito.Mockito.*;
-import static org.mockito.Matchers.*;
import java.util.Dictionary;
import java.util.Hashtable;
@@ -40,7 +39,10 @@ public class ReferrerFilterTest {
final ComponentContext ctx = mock(ComponentContext.class);
final BundleContext bundleCtx = mock(BundleContext.class);
final ServiceRegistration reg = mock(ServiceRegistration.class);
- final Dictionary<String, Object> props = new Hashtable<String, Object>();
+ final Dictionary<String, Object> props = new Hashtable<String, Object>(){{
+ put("allow.hosts", new String[]{"relhost"});
+ put("allow.hosts.regexp", new String[]{"http://([^.]*.)?abshost:80"});
+ }};
doReturn(props).when(ctx).getProperties();
doReturn(bundleCtx).when(ctx).getBundleContext();
doReturn(reg).when(bundleCtx).registerService(any(String[].class), any(), any(Dictionary.class));
@@ -83,5 +85,13 @@ public class ReferrerFilterTest {
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://relhost")));
+ Assert.assertEquals(true, filter.isValidRequest(getRequest("http://relhost:9001")));
+ Assert.assertEquals(false, filter.isValidRequest(getRequest("http://abshost:9001")));
+ Assert.assertEquals(false, filter.isValidRequest(getRequest("https://abshost:80")));
+ Assert.assertEquals(true, filter.isValidRequest(getRequest("http://abshost:80")));
+ Assert.assertEquals(false, filter.isValidRequest(getRequest("http://abshost:9001")));
+ Assert.assertEquals(true, filter.isValidRequest(getRequest("http://another.abshost:80")));
+ Assert.assertEquals(false, filter.isValidRequest(getRequest("http://yet.another.abshost:80")));
}
}
--
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.