You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@shindig.apache.org by rb...@apache.org on 2013/05/10 16:32:53 UTC

svn commit: r1481027 - in /shindig/trunk: config/ java/common/conf/ java/gadgets/src/main/java/org/apache/shindig/gadgets/ java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/ java/gadgets/src/test/java/org/apache/shindig/gadgets/render/

Author: rbaxter85
Date: Fri May 10 14:32:52 2013
New Revision: 1481027

URL: http://svn.apache.org/r1481027
Log:
Implement referer checks for shindig endpoints
SHINDIG-1858
Committed For Zhi Hong Yang

Modified:
    shindig/trunk/config/container.js
    shindig/trunk/java/common/conf/shindig.properties
    shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/AbstractLockedDomainService.java
    shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/GadgetContext.java
    shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/HashLockedDomainService.java
    shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/LockedDomainService.java
    shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/HttpGadgetContext.java
    shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/render/RendererTest.java

Modified: shindig/trunk/config/container.js
URL: http://svn.apache.org/viewvc/shindig/trunk/config/container.js?rev=1481027&r1=1481026&r2=1481027&view=diff
==============================================================================
--- shindig/trunk/config/container.js (original)
+++ shindig/trunk/config/container.js Fri May 10 14:32:52 2013
@@ -120,6 +120,10 @@
 // Should all gadgets be forced on to a locked domain?
 "gadgets.uri.iframe.lockedDomainRequired" : false,
 
+// The permitted domain where the render request is sent from. For examle: ["www.hostA.com", "www.hostB.com"]
+// Empty means all domains are permitted.
+"shindig.locked-domain.permittedRefererDomains" : [],
+
 // Default Js Uri config: also must be overridden.
 // gadgets.uri.js.host should be protocol relative.
 "gadgets.uri.js.host" : "//${Cur['default.domain.unlocked.server']}", // Use unlocked host for better caching.
@@ -336,4 +340,5 @@
     // This variable is needed during the container feature init.
     "jsPath" : "${Cur['gadgets.uri.js.path']}"
   }
-}}
+}
+}

Modified: shindig/trunk/java/common/conf/shindig.properties
URL: http://svn.apache.org/viewvc/shindig/trunk/java/common/conf/shindig.properties?rev=1481027&r1=1481026&r2=1481027&view=diff
==============================================================================
--- shindig/trunk/java/common/conf/shindig.properties (original)
+++ shindig/trunk/java/common/conf/shindig.properties Fri May 10 14:32:52 2013
@@ -59,6 +59,9 @@ shindig.signing.viewer-access-tokens-ena
 # If enabled here, configuration values can be found in container configuration files.
 shindig.locked-domain.enabled=false
 
+# Enable or disable referrer check.
+shindig.locked-domain.refererCheck.enabled=false
+
 # TODO: This needs to be moved to container configuration.
 shindig.content-rewrite.only-allow-excludes=false
 shindig.content-rewrite.include-urls=.*

Modified: shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/AbstractLockedDomainService.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/AbstractLockedDomainService.java?rev=1481027&r1=1481026&r2=1481027&view=diff
==============================================================================
--- shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/AbstractLockedDomainService.java (original)
+++ shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/AbstractLockedDomainService.java Fri May 10 14:32:52 2013
@@ -18,9 +18,15 @@
  */
 package org.apache.shindig.gadgets;
 
+import java.net.MalformedURLException;
+import java.net.URL;
 import java.util.Collection;
+import java.util.List;
 import java.util.Map;
+import java.util.logging.Level;
+import java.util.logging.Logger;
 
+import org.apache.shindig.common.logging.i18n.MessageKeys;
 import org.apache.shindig.config.ContainerConfig;
 
 import com.google.common.collect.Maps;
@@ -52,23 +58,34 @@ public abstract class AbstractLockedDoma
             Collection<String> removed) {
       for (String container : changed) {
         required.put(container, config.getBool(container, LOCKED_DOMAIN_REQUIRED_KEY));
+        permittedRefererDomains.put(container, config.getList(container, PERMITTED_REFERER_DOMAINS_KEY));
       }
       for (String container : removed) {
         required.remove(container);
+        permittedRefererDomains.remove(container);
       }
     }
   }
 
   protected static final String LOCKED_DOMAIN_REQUIRED_KEY = "gadgets.uri.iframe.lockedDomainRequired";
 
+  protected static final String PERMITTED_REFERER_DOMAINS_KEY = "shindig.locked-domain.permittedRefererDomains";
+
   protected static final String LOCKED_DOMAIN_FEATURE = "locked-domain";
   private final boolean enabled;
 
+  private boolean refererCheckEnabled;
+
   protected final Map<String, Boolean> required;
   private boolean lockSecurityTokens = false;
 
   private LockedDomainObserver ldObserver;
 
+  protected final Map<String, List<Object>> permittedRefererDomains;
+
+  private static final String classname = HashLockedDomainService.class.getName();
+  private static final Logger LOG = Logger.getLogger(classname, MessageKeys.MESSAGES);
+
   /**
    * Create a LockedDomainService. This constructor should be called by implementors.
    *
@@ -80,12 +97,18 @@ public abstract class AbstractLockedDoma
   protected AbstractLockedDomainService(ContainerConfig config, boolean enabled) {
     this.enabled = enabled;
     this.required = Maps.newHashMap();
+    this.permittedRefererDomains = Maps.newHashMap();
     if (enabled) {
       this.ldObserver = new LockedDomainObserver();
       config.addConfigObserver(this.ldObserver, true);
     }
   }
 
+  @Inject
+  public void setRefererCheckEnabled(@Named("shindig.locked-domain.refererCheck.enabled") boolean refererCheckEnabled) {
+      this.refererCheckEnabled = refererCheckEnabled;
+  }
+
   /*
    * (non-Javadoc)
    *
@@ -131,6 +154,15 @@ public abstract class AbstractLockedDoma
     return true;
   }
 
+  /*
+   * (non-Javadoc)
+   *
+   * @see org.apache.shindig.gadgets.LockedDomainService#isRefererCheckEnabled()
+   */
+  public boolean isRefererCheckEnabled() {
+    return this.refererCheckEnabled;
+  }
+
   /**
    * Allows a renderer to render all gadgets that require a security token on a locked domain. This
    * is recommended security practice, as it secures the token from other gadgets, but because the
@@ -150,11 +182,11 @@ public abstract class AbstractLockedDoma
   }
 
   /**
-   * Returns true iff domain locking is enforced for every gadget by the container
+   * Returns true if domain locking is enforced for every gadget by the container
    *
    * @param container
    *          the container configuration, e.g., "default"
-   * @return true iff domain locking is enforced by the container
+   * @return true if domain locking is enforced by the container
    */
   protected boolean isDomainLockingEnforced(String container) {
     return this.required.get(container);
@@ -169,14 +201,14 @@ public abstract class AbstractLockedDoma
   }
 
   /**
-   * Returns true iff the gadget is requesting to be on a locked domain. If security token locking
+   * Returns true if the gadget is requesting to be on a locked domain. If security token locking
    * has been enabled via {@link #setLockSecurityTokens(Boolean)}, this method will return true if
    * the gadget is explicitly or implicitly requesting locked domains; otherwise, this will return
    * true only if the gadget is explicitly requesting locked domains.
    *
    * @param gadget
    *          the gadget
-   * @return true iff the gadget is requesting to be on a locked domain
+   * @return true if the gadget is requesting to be on a locked domain
    */
   protected boolean isGadgetReqestingLocking(Gadget gadget) {
     if (this.lockSecurityTokens) {
@@ -184,4 +216,48 @@ public abstract class AbstractLockedDoma
     }
     return gadget.getViewFeatures().keySet().contains(LOCKED_DOMAIN_FEATURE);
   }
+
+  /**
+   * Check whether the referer value in the request head is in the permitted referer domain list or not.
+   * @param gadget
+   *     the gadget
+   * @param container
+   *     the container
+   * @return true if the referer is valid, otherwise return false.
+   */
+  protected boolean isValidReferer(Gadget gadget, String container) {
+    String referer = gadget.getContext().getReferer();
+    List<Object> domainList = this.permittedRefererDomains.get(container);
+    if (null != referer && !"".equals(referer.trim())) {
+      try {
+        URL url = new URL(referer);
+        if (!domainList.isEmpty()) {
+          boolean matched = false;
+          String refererHost = url.getHost().toLowerCase();
+          for (Object permittedDomain: domainList) {
+            if (refererHost.endsWith(((String) permittedDomain).toLowerCase())) {
+              matched = true;
+              break;
+            }
+          }
+          if (!matched) {
+            LOG.logp(Level.SEVERE, classname, "Referer check failed.",
+                MessageKeys.FAILED_TO_VALIDATE, new Object[] { referer });
+            return false;
+          }
+        }
+      } catch (MalformedURLException e) {
+        LOG.logp(Level.SEVERE, classname, "Referer check failed, malformed referer url.",
+            MessageKeys.FAILED_TO_VALIDATE, new Object[] { referer });
+        return false;
+      }
+    } else {
+      if (!domainList.isEmpty()) {
+        LOG.logp(Level.SEVERE, classname, "Referer check failed, referer url is not valid.",
+          MessageKeys.FAILED_TO_VALIDATE, new Object[] { referer });
+        return false;
+      }
+    }
+    return true;
+  }
 }

Modified: shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/GadgetContext.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/GadgetContext.java?rev=1481027&r1=1481026&r2=1481027&view=diff
==============================================================================
--- shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/GadgetContext.java (original)
+++ shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/GadgetContext.java Fri May 10 14:32:52 2013
@@ -168,5 +168,9 @@ public class GadgetContext {
   public String getRepository() {
     return delegate == null ? null : delegate.getRepository();
   }
+
+  public String getReferer() {
+      return delegate == null ? null : delegate.getReferer();
+  }
 }
 

Modified: shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/HashLockedDomainService.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/HashLockedDomainService.java?rev=1481027&r1=1481026&r2=1481027&view=diff
==============================================================================
--- shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/HashLockedDomainService.java (original)
+++ shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/HashLockedDomainService.java Fri May 10 14:32:52 2013
@@ -147,6 +147,9 @@ public class HashLockedDomainService ext
     if (isEnabled()) {
       if (isGadgetReqestingLocking(gadget) || isHostUsingLockedDomain(host)
               || isDomainLockingEnforced(container)) {
+        if (isRefererCheckEnabled() && !isValidReferer(gadget, container)) {
+          return false;
+        }
         String neededHost;
         try {
           neededHost = getLockedDomain(gadget, container);

Modified: shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/LockedDomainService.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/LockedDomainService.java?rev=1481027&r1=1481026&r2=1481027&view=diff
==============================================================================
--- shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/LockedDomainService.java (original)
+++ shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/LockedDomainService.java Fri May 10 14:32:52 2013
@@ -71,4 +71,9 @@ public interface LockedDomainService {
    *         Returns false if locked domains are not enabled on the server.
    */
   boolean isHostUsingLockedDomain(String host);
+
+  /**
+   * @return If referrer check is enabled, return true. Otherwise, return false.
+   */
+  boolean isRefererCheckEnabled();
 }

Modified: shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/HttpGadgetContext.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/HttpGadgetContext.java?rev=1481027&r1=1481026&r2=1481027&view=diff
==============================================================================
--- shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/HttpGadgetContext.java (original)
+++ shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/HttpGadgetContext.java Fri May 10 14:32:52 2013
@@ -51,6 +51,7 @@ public class HttpGadgetContext extends G
   private final Uri url;
   private final UserPrefs userPrefs;
   private final String view;
+  private final String referer;
 
   public HttpGadgetContext(HttpServletRequest request) {
     this.request = request;
@@ -64,6 +65,7 @@ public class HttpGadgetContext extends G
     url = getUrl(request);
     userPrefs = getUserPrefs(request);
     view = getView(request);
+    referer = getReferer();
   }
 
   @Override
@@ -166,6 +168,12 @@ public class HttpGadgetContext extends G
     return repository;
   }
 
+  @Override
+  public String getReferer() {
+    String referer = request.getHeader("Referer");
+    return referer == null ? super.getReferer() : referer;
+  }
+
   /**
    * @param req
    * @return The container, if set, or null.

Modified: shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/render/RendererTest.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/render/RendererTest.java?rev=1481027&r1=1481026&r2=1481027&view=diff
==============================================================================
--- shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/render/RendererTest.java (original)
+++ shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/render/RendererTest.java Fri May 10 14:32:52 2013
@@ -295,5 +295,9 @@ public class RendererTest {
     public boolean isHostUsingLockedDomain(String host) {
       return false;
     }
+
+    public boolean isRefererCheckEnabled() {
+        return false;
+    }
   }
 }