You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@shindig.apache.org by li...@apache.org on 2011/10/12 20:26:28 UTC
svn commit: r1182510 - in /shindig/trunk/java/gadgets/src:
main/java/org/apache/shindig/gadgets/ test/java/org/apache/shindig/gadgets/
test/java/org/apache/shindig/gadgets/render/
Author: lindner
Date: Wed Oct 12 18:26:28 2011
New Revision: 1182510
URL: http://svn.apache.org/viewvc?rev=1182510&view=rev
Log:
SHINDIG-1637 | Patch from Stanton Sievers | Introduce abstract LockedDomainService implementation to enable easier customization
Added:
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/AbstractLockedDomainService.java
Modified:
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/test/java/org/apache/shindig/gadgets/HashLockedDomainServiceTest.java
shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/render/RendererTest.java
Added: 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=1182510&view=auto
==============================================================================
--- shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/AbstractLockedDomainService.java (added)
+++ shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/AbstractLockedDomainService.java Wed Oct 12 18:26:28 2011
@@ -0,0 +1,188 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.shindig.gadgets;
+
+import java.util.Collection;
+import java.util.Map;
+
+import org.apache.shindig.config.ContainerConfig;
+
+import com.google.common.collect.Maps;
+import com.google.inject.Inject;
+import com.google.inject.name.Named;
+
+/**
+ * Provides a default implementation of much of the basic functionality for managing locked domains.
+ *
+ * @author <a href="mailto:dev@shindig.apache.org">Shindig Dev</a>
+ * @since 3.0.0
+ */
+public abstract class AbstractLockedDomainService implements LockedDomainService {
+
+ /**
+ * Used to observer locked domain required in the config. Doing this instead of having
+ * AbstractLockedDomainService implement ConfigObserver so that subclasses don't need to know what
+ * AbstractLockedDomainService is observing. In order to add the config observer in the constructor
+ * this needed to be broken out to avoid initialization order problems when subclassing and
+ * calling super()
+ */
+ private class LockedDomainObserver implements ContainerConfig.ConfigObserver {
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.apache.shindig.config.ContainerConfig.ConfigObserver#containersChanged
+ * (org.apache.shindig.config.ContainerConfig, java.util.Collection, java.util.Collection)
+ */
+ public void containersChanged(ContainerConfig config, Collection<String> changed,
+ Collection<String> removed) {
+ for (String container : changed) {
+ required.put(container, config.getBool(container, LOCKED_DOMAIN_REQUIRED_KEY));
+ }
+ for (String container : removed) {
+ required.remove(container);
+ }
+ }
+ }
+
+ protected static final String LOCKED_DOMAIN_REQUIRED_KEY = "gadgets.uri.iframe.lockedDomainRequired";
+
+ protected static final String LOCKED_DOMAIN_FEATURE = "locked-domain";
+ protected final boolean enabled;
+
+ protected final Map<String, Boolean> required;
+ private boolean lockSecurityTokens = false;
+
+ private LockedDomainObserver ldObserver;
+
+ /**
+ * Create a LockedDomainService. This constructor should be called by implementors.
+ *
+ * @param config
+ * the container config that will be observed
+ * @param enabled
+ * true if locked domains are enabled; false otherwise
+ */
+ protected AbstractLockedDomainService(ContainerConfig config, boolean enabled) {
+ this.enabled = enabled;
+ this.required = Maps.newHashMap();
+ if (enabled) {
+ this.ldObserver = new LockedDomainObserver();
+ config.addConfigObserver(this.ldObserver, true);
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.apache.shindig.gadgets.LockedDomainService#getLockedDomainForGadget
+ * (org.apache.shindig.gadgets.Gadget, java.lang.String)
+ */
+ public abstract String getLockedDomainForGadget(Gadget gadget, String container)
+ throws GadgetException;
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.apache.shindig.gadgets.LockedDomainService#isEnabled()
+ */
+ public boolean isEnabled() {
+ return this.enabled;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.apache.shindig.gadgets.LockedDomainService#isGadgetValidForHost(java .lang.String,
+ * org.apache.shindig.gadgets.Gadget, java.lang.String)
+ */
+ public abstract boolean isGadgetValidForHost(String host, Gadget gadget, String container);
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.apache.shindig.gadgets.LockedDomainService#isHostUsingLockedDomain (java.lang.String)
+ */
+ public abstract boolean isHostUsingLockedDomain(String host);
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.apache.shindig.gadgets.LockedDomainService#isSafeForOpenProxy(java .lang.String)
+ */
+ public boolean isSafeForOpenProxy(String host) {
+ if (this.enabled) {
+ return !isHostUsingLockedDomain(host);
+ }
+ return true;
+ }
+
+ /**
+ * 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
+ * "security-token" dependency on "locked-domain" is both implicit (added by GadgetSpec code for
+ * OAuth elements) and/or transitive (included by opensocial and opensocial-templates features),
+ * turning this behavior by default may take some by surprise. As such, we provide this flag. If
+ * false (by default), locked-domain will apply only when the gadget's Requires/Optional sections
+ * include it. Otherwise, the transitive dependency tree will be traversed to make this decision.
+ *
+ * @param lockSecurityTokens
+ * If true, locks domains for all gadgets requiring security-token.
+ */
+ @Inject(optional = true)
+ public void setLockSecurityTokens(
+ @Named("shindig.locked-domain.lock-security-tokens") Boolean lockSecurityTokens) {
+ this.lockSecurityTokens = lockSecurityTokens;
+ }
+
+ /**
+ * Returns true iff 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
+ */
+ protected boolean isDomainLockingEnforced(String container) {
+ return this.required.get(container);
+ }
+
+ /**
+ * Override methods for custom behavior Allows you to override locked domain feature requests from
+ * a gadget.
+ */
+ protected boolean isExcludedFromLockedDomain(Gadget gadget, String container) {
+ return false;
+ }
+
+ /**
+ * Returns true iff 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
+ */
+ protected boolean isGadgetReqestingLocking(Gadget gadget) {
+ if (this.lockSecurityTokens) {
+ return gadget.getAllFeatures().contains(LOCKED_DOMAIN_FEATURE);
+ }
+ return gadget.getViewFeatures().keySet().contains(LOCKED_DOMAIN_FEATURE);
+ }
+}
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=1182510&r1=1182509&r2=1182510&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 Wed Oct 12 18:26:28 2011
@@ -34,6 +34,7 @@ import org.apache.shindig.config.Contain
import org.apache.shindig.gadgets.spec.Feature;
import org.apache.shindig.gadgets.uri.LockedDomainPrefixGenerator;
+import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.Maps;
import com.google.inject.Inject;
import com.google.inject.Singleton;
@@ -48,113 +49,103 @@ import com.google.inject.name.Named;
*
* Other domain locking schemes are possible as well.
*/
-/**
- * @author <a href="mailto:dev@shindig.apache.org">Shindig Dev</a>
- * @version $Id: $
- *
- */
@Singleton
-public class HashLockedDomainService implements LockedDomainService, ContainerConfig.ConfigObserver {
- //class name for logging purpose
+public class HashLockedDomainService extends AbstractLockedDomainService {
+
+ /**
+ * Used to observer locked domain suffixes for this class
+ */
+ private class HashLockedDomainObserver implements ContainerConfig.ConfigObserver {
+
+ public void containersChanged(ContainerConfig config, Collection<String> changed,
+ Collection<String> removed) {
+ for (String container : changed) {
+ String suffix = config.getString(container, LOCKED_DOMAIN_SUFFIX_KEY);
+ if (suffix == null) {
+ if (LOG.isLoggable(Level.WARNING)) {
+ LOG.logp(Level.WARNING, classname, "containersChanged",
+ MessageKeys.NO_LOCKED_DOMAIN_CONFIG, new Object[] { container });
+ }
+ } else {
+ HashLockedDomainService.this.lockedSuffixes.put(container, checkSuffix(suffix));
+ }
+ }
+ for (String container : removed) {
+ HashLockedDomainService.this.lockedSuffixes.remove(container);
+ }
+ }
+ }
+
+ // class name for logging purpose
private static final String classname = HashLockedDomainService.class.getName();
- private static final Logger LOG = Logger.getLogger(classname, MessageKeys.MESSAGES);
- private final boolean enabled;
- private boolean lockSecurityTokens = false;
+ private static final Logger LOG = Logger.getLogger(classname, MessageKeys.MESSAGES);
private final Map<String, String> lockedSuffixes;
- private final Map<String, Boolean> required;
private Authority authority;
private LockedDomainPrefixGenerator ldGen;
private final Pattern authpattern = Pattern.compile("%authority%");
- public static final String LOCKED_DOMAIN_REQUIRED_KEY = "gadgets.uri.iframe.lockedDomainRequired";
+ private HashLockedDomainObserver ldObserver;
+
public static final String LOCKED_DOMAIN_SUFFIX_KEY = "gadgets.uri.iframe.lockedDomainSuffix";
+ /*
+ * Injected methods
+ */
+
/**
* Create a LockedDomainService
- * @param config per-container configuration
- * @param enabled whether this service should do anything at all.
+ *
+ * @param config
+ * per-container configuration
+ * @param enabled
+ * whether this service should do anything at all.
*/
@Inject
public HashLockedDomainService(ContainerConfig config,
- @Named("shindig.locked-domain.enabled") boolean enabled,
- LockedDomainPrefixGenerator ldGen) {
- this.enabled = enabled;
+ @Named("shindig.locked-domain.enabled") boolean enabled, LockedDomainPrefixGenerator ldGen) {
+ super(config, enabled);
+ this.lockedSuffixes = Maps.newHashMap();
this.ldGen = ldGen;
- lockedSuffixes = Maps.newHashMap();
- required = Maps.newHashMap();
if (enabled) {
- config.addConfigObserver(this, true);
+ this.ldObserver = new HashLockedDomainObserver();
+ config.addConfigObserver(this.ldObserver, true);
}
}
- /*
- * Injected methods
- */
-
- @Inject(optional = true)
- public void setAuthority(Authority authority) {
- this.authority = authority;
- }
-
- /**
- * 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 "security-token" dependency on "locked-domain" is
- * both implicit (added by GadgetSpec code for OAuth elements) and/or transitive
- * (included by opensocial and opensocial-templates features), turning this behavior
- * by default may take some by surprise. As such, we provide this flag. If false
- * (by default), locked-domain will apply only when the gadget's Requires/Optional
- * sections include it. Otherwise, the transitive dependency tree will be traversed
- * to make this decision.
- * @param lockSecurityTokens If true, locks domains for all gadgets requiring security-token.
- */
- @Inject(optional = true)
- public void setLockSecurityTokens(
- @Named("shindig.locked-domain.lock-security-tokens") Boolean lockSecurityTokens) {
- this.lockSecurityTokens = lockSecurityTokens;
- }
-
-
- /*
- * Public implmentation
- */
-
- public void containersChanged(ContainerConfig config, Collection<String> changed, Collection<String> removed) {
- for (String container : changed) {
- String suffix = config.getString(container, LOCKED_DOMAIN_SUFFIX_KEY);
- if (suffix == null) {
- if (LOG.isLoggable(Level.WARNING)) {
- LOG.logp(Level.WARNING, classname, "containersChanged", MessageKeys.NO_LOCKED_DOMAIN_CONFIG, new Object[] {container});
- }
- } else {
- lockedSuffixes.put(container, checkSuffix(suffix));
+ @Override
+ public String getLockedDomainForGadget(Gadget gadget, String container) throws GadgetException {
+ container = getContainer(container);
+ if (this.enabled && !isExcludedFromLockedDomain(gadget, container)) {
+ if (isGadgetReqestingLocking(gadget) || isDomainLockingEnforced(container)) {
+ return getLockedDomain(gadget, container);
}
- required.put(container, config.getBool(container, LOCKED_DOMAIN_REQUIRED_KEY));
}
- for (String container : removed) {
- lockedSuffixes.remove(container);
- required.remove(container);
- }
- }
-
- public boolean isEnabled() {
- return enabled;
+ return null;
}
- public boolean isSafeForOpenProxy(String host) {
- if (enabled) {
- return !isHostUsingLockedDomain(host);
+ /**
+ * Generates a locked domain prefix given a gadget Uri.
+ *
+ * @param gadget The uri of the gadget.
+ * @return A locked domain prefix for the gadgetUri.
+ * Returns empty string if locked domains are not enabled on the server.
+ */
+ private String getLockedDomainPrefix(Gadget gadget) throws GadgetException {
+ String ret = "";
+ if (this.enabled) {
+ ret = this.ldGen.getLockedDomainPrefix(getLockedDomainParticipants(gadget));
}
- return true;
+ // Lower-case to prevent casing from being relevant.
+ return ret.toLowerCase();
}
+ @Override
public boolean isGadgetValidForHost(String host, Gadget gadget, String container) {
container = getContainer(container);
- if (enabled) {
- if (isGadgetReqestingLocking(gadget) ||
- isHostUsingLockedDomain(host) ||
- isDomainLockingEnforced(container)) {
+ if (this.enabled) {
+ if (isGadgetReqestingLocking(gadget) || isHostUsingLockedDomain(host)
+ || isDomainLockingEnforced(container)) {
String neededHost;
try {
neededHost = getLockedDomain(gadget, container);
@@ -170,19 +161,10 @@ public class HashLockedDomainService imp
return true;
}
- public String getLockedDomainForGadget(Gadget gadget, String container) throws GadgetException {
- container = getContainer(container);
- if (enabled && !isExcludedFromLockedDomain(gadget, container)) {
- if (isGadgetReqestingLocking(gadget) || isDomainLockingEnforced(container)) {
- return getLockedDomain(gadget, container);
- }
- }
- return null;
- }
-
+ @Override
public boolean isHostUsingLockedDomain(String host) {
- if (enabled) {
- for (String suffix : lockedSuffixes.values()) {
+ if (this.enabled) {
+ for (String suffix : this.lockedSuffixes.values()) {
if (host.endsWith(suffix)) {
return true;
}
@@ -191,79 +173,43 @@ public class HashLockedDomainService imp
return false;
}
- public String getLockedDomainPrefix(Gadget gadget) throws GadgetException {
- String ret = "";
- if (enabled) {
- ret = ldGen.getLockedDomainPrefix(getLockedDomainParticipants(gadget));
- }
- // Lower-case to prevent casing from being relevant.
- return ret.toLowerCase();
- }
-
-
- /*
- * Protected implementation
- */
-
- /**
- * Override methods for custom behavior
- * Allows you to override locked domain feature requests from a gadget.
- */
- protected boolean isExcludedFromLockedDomain(Gadget gadget, String container) {
- return false;
- }
-
-
- /*
- * Private implmentation
- */
-
- private String getLockedDomain(Gadget gadget, String container) throws GadgetException {
- String suffix = lockedSuffixes.get(container);
- if (suffix == null) {
- return null;
- }
- return getLockedDomainPrefix(gadget) + suffix;
- }
-
- /**
- * @see HashLockedDomainService#setLockSecurityTokens(Boolean)
- */
- private boolean isGadgetReqestingLocking(Gadget gadget) {
- if (lockSecurityTokens) {
- return gadget.getAllFeatures().contains("locked-domain");
- }
- return gadget.getViewFeatures().keySet().contains("locked-domain");
- }
-
- private boolean isDomainLockingEnforced(String container) {
- return required.get(container);
- }
-
- private String getContainer(String container) {
- if (required.containsKey(container)) {
- return container;
- }
- return ContainerConfig.DEFAULT_CONTAINER;
+ @Inject(optional = true)
+ public void setAuthority(Authority authority) {
+ this.authority = authority;
}
private String checkSuffix(String suffix) {
if (suffix != null) {
- Matcher m = authpattern.matcher(suffix);
+ Matcher m = this.authpattern.matcher(suffix);
if (m.matches()) {
if (LOG.isLoggable(Level.WARNING)) {
LOG.warning("You should not be using %authority% replacement in a running environment!");
LOG.warning("Check your config and specify an explicit locked domain suffix.");
LOG.warning("Found suffix: " + suffix);
}
- if (authority != null) {
- suffix = m.replaceAll(authority.getAuthority());
+ if (this.authority != null) {
+ suffix = m.replaceAll(this.authority.getAuthority());
}
}
}
return suffix;
}
+ private String getContainer(String container) {
+ if (this.required.containsKey(container)) {
+ return container;
+ }
+ return ContainerConfig.DEFAULT_CONTAINER;
+ }
+
+ private String getLockedDomain(Gadget gadget, String container) throws GadgetException {
+ String suffix = this.lockedSuffixes.get(container);
+ if (suffix == null) {
+ return null;
+ }
+ return getLockedDomainPrefix(gadget) + suffix;
+ }
+
private String getLockedDomainParticipants(Gadget gadget) throws GadgetException {
Map<String, Feature> features = gadget.getSpec().getModulePrefs().getFeatures();
Feature ldFeature = features.get("locked-domain");
@@ -280,7 +226,7 @@ public class HashLockedDomainService imp
Uri.parse(participant);
} catch (UriException e) {
throw new GadgetException(GadgetException.Code.INVALID_PARAMETER,
- "Participant param must be a valid uri", e);
+ "Participant param must be a valid uri", e);
}
filtered.add(participant.toLowerCase());
}
@@ -292,4 +238,9 @@ public class HashLockedDomainService imp
}
return buffer.toString();
}
+
+ @VisibleForTesting
+ ContainerConfig.ConfigObserver getConfigObserver() {
+ return this.ldObserver;
+ }
}
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=1182510&r1=1182509&r2=1182510&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 Wed Oct 12 18:26:28 2011
@@ -71,13 +71,4 @@ public interface LockedDomainService {
* Returns false if locked domains are not enabled on the server.
*/
boolean isHostUsingLockedDomain(String host);
-
- /**
- * Generates a locked domain prefix given a gadget Uri.
- *
- * @param gadget The uri of the gadget.
- * @return A locked domain prefix for the gadgetUri.
- * Returns empty string if locked domains are not enabled on the server.
- */
- String getLockedDomainPrefix(Gadget gadget) throws GadgetException;
}
Modified: shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/HashLockedDomainServiceTest.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/HashLockedDomainServiceTest.java?rev=1182510&r1=1182509&r2=1182510&view=diff
==============================================================================
--- shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/HashLockedDomainServiceTest.java (original)
+++ shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/HashLockedDomainServiceTest.java Wed Oct 12 18:26:28 2011
@@ -254,7 +254,7 @@ public class HashLockedDomainServiceTest
config.newTransaction().addContainer(makeContainer(
"other", LOCKED_DOMAIN_REQUIRED_KEY, true, LOCKED_DOMAIN_SUFFIX_KEY, "-a.example.com:8080"))
.commit();
- lockedDomainService.containersChanged(
+ lockedDomainService.getConfigObserver().containersChanged(
config, ImmutableSet.of("other"), ImmutableSet.<String>of());
assertTrue(lockedDomainService.isGadgetValidForHost(
"8uhr00296d2o3sfhqilj387krjmgjv3v-a.example.com:8080", wantsLocked, "container"));
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=1182510&r1=1182509&r2=1182510&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 Wed Oct 12 18:26:28 2011
@@ -288,22 +288,12 @@ public class RendererTest {
return false;
}
- @Override
public boolean isEnabled() {
- // TODO Auto-generated method stub
return false;
}
- @Override
public boolean isHostUsingLockedDomain(String host) {
- // TODO Auto-generated method stub
return false;
}
-
- @Override
- public String getLockedDomainPrefix(Gadget gadget) {
- // TODO Auto-generated method stub
- return null;
- }
}
}