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:[email protected]">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:[email protected]">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;
- }
}
}