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 2011/10/21 16:19:34 UTC

svn commit: r1187358 [1/2] - in /shindig/trunk/java: common/src/main/java/org/apache/shindig/auth/ common/src/main/java/org/apache/shindig/common/crypto/ common/src/test/java/org/apache/shindig/auth/ common/src/test/java/org/apache/shindig/common/crypt...

Author: rbaxter85
Date: Fri Oct 21 14:19:33 2011
New Revision: 1187358

URL: http://svn.apache.org/viewvc?rev=1187358&view=rev
Log:
SHINDIG-1645
Committed For Dan Dumont
Security Token Cleanup in preparation for ContainerConfig controlled token expirations

Added:
    shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/OAuthCallbackStateToken.java
Modified:
    shindig/trunk/java/common/src/main/java/org/apache/shindig/auth/AbstractSecurityToken.java
    shindig/trunk/java/common/src/main/java/org/apache/shindig/auth/AnonymousSecurityToken.java
    shindig/trunk/java/common/src/main/java/org/apache/shindig/auth/BasicSecurityToken.java
    shindig/trunk/java/common/src/main/java/org/apache/shindig/auth/BasicSecurityTokenCodec.java
    shindig/trunk/java/common/src/main/java/org/apache/shindig/auth/BlobCrypterSecurityToken.java
    shindig/trunk/java/common/src/main/java/org/apache/shindig/auth/BlobCrypterSecurityTokenCodec.java
    shindig/trunk/java/common/src/main/java/org/apache/shindig/auth/DefaultSecurityTokenCodec.java
    shindig/trunk/java/common/src/main/java/org/apache/shindig/auth/SecurityToken.java
    shindig/trunk/java/common/src/main/java/org/apache/shindig/auth/SecurityTokenCodec.java
    shindig/trunk/java/common/src/main/java/org/apache/shindig/common/crypto/BasicBlobCrypter.java
    shindig/trunk/java/common/src/main/java/org/apache/shindig/common/crypto/BlobCrypter.java
    shindig/trunk/java/common/src/main/java/org/apache/shindig/common/crypto/BlobExpiredException.java
    shindig/trunk/java/common/src/test/java/org/apache/shindig/auth/BasicSecurityTokenCodecTest.java
    shindig/trunk/java/common/src/test/java/org/apache/shindig/auth/BlobCrypterSecurityTokenCodecTest.java
    shindig/trunk/java/common/src/test/java/org/apache/shindig/auth/BlobCrypterSecurityTokenTest.java
    shindig/trunk/java/common/src/test/java/org/apache/shindig/auth/DefaultSecurityTokenCodecTest.java
    shindig/trunk/java/common/src/test/java/org/apache/shindig/auth/UrlParameterAuthenticationHandlerTest.java
    shindig/trunk/java/common/src/test/java/org/apache/shindig/common/crypto/BlobCrypterTest.java
    shindig/trunk/java/common/src/test/java/org/apache/shindig/common/testing/FakeGadgetToken.java
    shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/config/ShindigAuthConfigContributor.java
    shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/OAuthCallbackState.java
    shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/OAuthClientState.java
    shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/GadgetsHandlerService.java
    shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/oauth/OAuthClientStateTest.java
    shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/oauth2/MockUtils.java
    shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/GadgetsHandlerServiceTest.java
    shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/GadgetsHandlerTest.java
    shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/core/oauth/OAuthSecurityToken.java

Modified: shindig/trunk/java/common/src/main/java/org/apache/shindig/auth/AbstractSecurityToken.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/common/src/main/java/org/apache/shindig/auth/AbstractSecurityToken.java?rev=1187358&r1=1187357&r2=1187358&view=diff
==============================================================================
--- shindig/trunk/java/common/src/main/java/org/apache/shindig/auth/AbstractSecurityToken.java (original)
+++ shindig/trunk/java/common/src/main/java/org/apache/shindig/auth/AbstractSecurityToken.java Fri Oct 21 14:19:33 2011
@@ -18,19 +18,358 @@
  */
 package org.apache.shindig.auth;
 
+import java.util.EnumSet;
+import java.util.Map;
+
+import org.apache.shindig.common.crypto.BlobExpiredException;
+import org.apache.shindig.common.util.TimeSource;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.collect.Maps;
+
 /**
- * A base class for SecurityToken Implementations.  Currently provides an isExpired() method
+ * A base class for SecurityToken Implementations.
+ * Currently provides an isExpired() method and getters/setters for nearly
+ * every field of the token.
  *
  * @since 2.0.0
  */
 public abstract class AbstractSecurityToken implements SecurityToken {
+  /** allow three minutes for clock skew */
+  private static final long CLOCK_SKEW_ALLOWANCE = 180;
+
+  // TODO: Make configurable by ContainerConfig
+  private static final int MAX_TOKEN_TTL = 3600;
+
+  private static final TimeSource TIME_SOURCE = new TimeSource();
+
+  public enum Keys {
+    OWNER("o") {
+      public String getValue(SecurityToken token) {
+        return token.getOwnerId();
+      }
+      public void loadFromMap(AbstractSecurityToken token, Map<String, String> map) {
+        token.setOwnerId(map.get(key));
+      }
+    },
+    VIEWER("v") {
+      public String getValue(SecurityToken token) {
+        return token.getViewerId();
+      }
+      public void loadFromMap(AbstractSecurityToken token, Map<String, String> map) {
+        token.setViewerId(map.get(key));
+      }
+    },
+    APP_ID("i") {
+      public String getValue(SecurityToken token) {
+        return token.getAppId();
+      }
+      public void loadFromMap(AbstractSecurityToken token, Map<String, String> map) {
+        token.setAppId(map.get(key));
+      }
+    },
+    DOMAIN("d") {
+      public String getValue(SecurityToken token) {
+        return token.getDomain();
+      }
+      public void loadFromMap(AbstractSecurityToken token, Map<String, String> map) {
+        token.setDomain(map.get(key));
+      }
+    },
+    CONTAINER("c") {
+      public String getValue(SecurityToken token) {
+        return token.getContainer();
+      }
+      public void loadFromMap(AbstractSecurityToken token, Map<String, String> map) {
+        token.setContainer(map.get(key));
+      }
+    },
+    APP_URL("u") {
+      public String getValue(SecurityToken token) {
+        return token.getAppUrl();
+      }
+      public void loadFromMap(AbstractSecurityToken token, Map<String, String> map) {
+        token.setAppUrl(map.get(key));
+      }
+    },
+    MODULE_ID("m") {
+      public String getValue(SecurityToken token) {
+        long value = token.getModuleId();
+        if (value == 0) {
+          return null;
+        }
+        return Long.toString(token.getModuleId(), 10);
+      }
+      public void loadFromMap(AbstractSecurityToken token, Map<String, String> map) {
+        String value = map.get(key);
+        if (value != null) {
+          token.setModuleId(Long.parseLong(value, 10));
+        }
+      }
+    },
+    EXPIRES("x") {
+      public String getValue(SecurityToken token) {
+        Long value = token.getExpiresAt();
+        if (value == null) {
+          return null;
+        }
+        return Long.toString(token.getExpiresAt(), 10);
+      }
+      public void loadFromMap(AbstractSecurityToken token, Map<String, String> map) {
+        String value = map.get(key);
+        if (value != null) {
+          token.setExpiresAt(Long.parseLong(value, 10));
+        }
+      }
+    },
+    TRUSTED_JSON("j") {
+      public String getValue(SecurityToken token) {
+        return token.getTrustedJson();
+      }
+      public void loadFromMap(AbstractSecurityToken token, Map<String, String> map) {
+        token.setTrustedJson(map.get(key));
+      }
+    };
+
+    protected String key;
+    private Keys(String key) {
+      this.key = key;
+    }
+
+    /**
+     * @return The key this {@link Keys} is bound to.
+     */
+    public String getKey() {
+      return key;
+    }
+
+    /**
+     * Gets the {@link String} value from the {@link SecurityToken} using the getter that
+     * this {@link Keys} is bound to.
+     *
+     * @param token The token to get the value from.
+     * @return The value
+     */
+    public abstract String getValue(SecurityToken token);
+
+    /**
+     * Loads from the map the value bound to this {@link Keys} and sets it on the
+     * {@link SecurityToken}
+     *
+     * @param token The token to insert set the value on.
+     * @param map The map to read the value from.
+     */
+    public abstract void loadFromMap(AbstractSecurityToken token, Map<String, String> map);
+  }
+
+  private String ownerId;
+  private String viewerId;
+  private String appId;
+  private String domain;
+  private String container;
+  private String appUrl;
+  private long moduleId = 0;
+  private Long expiresAt;
+  private String trustedJson;
+  private String activeUrl;
+
+  private TimeSource timeSource = AbstractSecurityToken.TIME_SOURCE;
+
+  /**
+   * This method is mostly used for test code to test the expire methods.
+   *
+   * @param timeSource The new {@link TimeSource} for this token to use.
+   * @return This object.
+   */
+  @VisibleForTesting
+  protected AbstractSecurityToken setTimeSource(TimeSource timeSource) {
+    this.timeSource = timeSource;
+    return this;
+  }
+
+  protected TimeSource getTimeSource() {
+    return timeSource;
+  }
+
+  public String getOwnerId() {
+    return ownerId;
+  }
+
+  protected AbstractSecurityToken setOwnerId(String ownerId) {
+    this.ownerId = ownerId;
+    return this;
+  }
+
+  public String getViewerId() {
+    return viewerId;
+  }
+
+  protected AbstractSecurityToken setViewerId(String viewerId) {
+    this.viewerId = viewerId;
+    return this;
+  }
+
+  public String getAppId() {
+    return appId;
+  }
+
+  protected AbstractSecurityToken setAppId(String appId) {
+    this.appId = appId;
+    return this;
+  }
+
+  public String getDomain() {
+    return domain;
+  }
+
+  protected AbstractSecurityToken setDomain(String domain) {
+    this.domain = domain;
+    return this;
+  }
+
+  public String getContainer() {
+    return container;
+  }
+
+  protected AbstractSecurityToken setContainer(String container) {
+    this.container = container;
+    return this;
+  }
+
+  public String getAppUrl() {
+    return appUrl;
+  }
+
+  protected AbstractSecurityToken setAppUrl(String appUrl) {
+    this.appUrl = appUrl;
+    return this;
+  }
+
+  public long getModuleId() {
+    return moduleId;
+  }
+
+  protected AbstractSecurityToken setModuleId(long moduleId) {
+    this.moduleId = moduleId;
+    return this;
+  }
+
+  public Long getExpiresAt() {
+    return expiresAt;
+  }
+
+  /**
+   * Compute and set the expiration time for this token.
+   *
+   * @return This security token.
+   */
+  protected AbstractSecurityToken setExpires() {
+    return setExpiresAt((getTimeSource().currentTimeMillis() / 1000) + getMaxTokenTTL());
+  }
+
+  /**
+   * Set the expiration time for this token.
+   *
+   * @param expiresAt When this token expires, in seconds since epoch.
+   * @return This security token.
+   */
+  protected AbstractSecurityToken setExpiresAt(Long expiresAt) {
+    this.expiresAt = expiresAt;
+    return this;
+  }
+
+  public String getTrustedJson() {
+    return trustedJson;
+  }
+
+  protected AbstractSecurityToken setTrustedJson(String trustedJson) {
+    this.trustedJson = trustedJson;
+    return this;
+  }
 
   public boolean isExpired() {
+    try {
+      enforceNotExpired();
+    } catch (BlobExpiredException e) {
+      return true;
+    }
+    return false;
+  }
+
+  public AbstractSecurityToken enforceNotExpired() throws BlobExpiredException {
     Long expiresAt = getExpiresAt();
-    return (expiresAt == null) ? false : (System.currentTimeMillis() >expiresAt);
+    if (expiresAt != null) {
+      long maxTime = expiresAt + CLOCK_SKEW_ALLOWANCE;
+      long now = getTimeSource().currentTimeMillis() / 1000;
+
+      if (!(now < maxTime)) {
+        throw new BlobExpiredException(now, maxTime);
+      }
+    }
+    return this;
   }
 
   public String getActiveUrl() {
-    throw new UnsupportedOperationException("No active URL available");
+    return activeUrl;
+  }
+
+  protected AbstractSecurityToken setActiveUrl(String activeUrl) {
+    this.activeUrl = activeUrl;
+    return this;
+  }
+
+  /**
+   * A {@link Map} representation of this {@link SecurityToken}.  Implementors that
+   * handle additional keys not contained in {@link Keys} should override and
+   * supplement the functionality of this method.
+   *
+   * @return A map of serialized token values keyed according to {@link Keys}.
+   * @see #getMapKeys()
+   * @see #loadFromMap(Map)
+   */
+  public Map<String, String> toMap() {
+    Map<String, String> map = Maps.newHashMap();
+    for (Keys key : getMapKeys()) {
+      String value = key.getValue(this);
+      if (value != null) {
+        map.put(key.getKey(), key.getValue(this));
+      }
+    }
+    return map;
+  }
+
+  /**
+   * @return Maximum allowable time in seconds for a token to live.
+   */
+  protected int getMaxTokenTTL() {
+    return MAX_TOKEN_TTL;
+  }
+
+  /**
+   * A helper to help load known supported keys from a provided map.
+   *
+   * @param map The map of values.
+   * @see #getMapKeys()
+   * @see #toMap()
+   */
+  protected AbstractSecurityToken loadFromMap(Map<String, String> map) {
+    for (Keys key : getMapKeys()) {
+      key.loadFromMap(this, map);
+    }
+    return this;
   }
+
+  /**
+   * This method will govern the effectiveness of the protected {@link #toMap()} and
+   * {@link #loadFromMap(SecurityToken, Map)} helper methods.
+   * <br><br>
+   * If your implementation throws an exception on any of the get methods, you
+   * should not include the associated key here, and those values should be handled
+   * in an overridden implementation of {@link #toMap()} if they might contain
+   * useful information.
+   *
+   * @return An EnumSet of the Enums supported by the implementation of this
+   * {@link AbstractSecurityToken}.
+   */
+  protected abstract EnumSet<Keys> getMapKeys();
 }

Modified: shindig/trunk/java/common/src/main/java/org/apache/shindig/auth/AnonymousSecurityToken.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/common/src/main/java/org/apache/shindig/auth/AnonymousSecurityToken.java?rev=1187358&r1=1187357&r2=1187358&view=diff
==============================================================================
--- shindig/trunk/java/common/src/main/java/org/apache/shindig/auth/AnonymousSecurityToken.java (original)
+++ shindig/trunk/java/common/src/main/java/org/apache/shindig/auth/AnonymousSecurityToken.java Fri Oct 21 14:19:33 2011
@@ -18,66 +18,41 @@
  */
 package org.apache.shindig.auth;
 
+import java.util.EnumSet;
+
 import org.apache.shindig.config.ContainerConfig;
 
 /**
  * A special class of Token representing the anonymous viewer/owner
  */
 public class AnonymousSecurityToken extends AbstractSecurityToken implements SecurityToken {
-  private final String container;
-  private final long moduleId;
-  private final String appUrl;
-  private final Long expiresAt;
+  private static final EnumSet<Keys> MAP_KEYS = EnumSet.of(
+    Keys.OWNER, Keys.VIEWER, Keys.APP_URL, Keys.MODULE_ID, Keys.EXPIRES, Keys.TRUSTED_JSON
+  );
 
   public AnonymousSecurityToken() {
     this(ContainerConfig.DEFAULT_CONTAINER);
   }
-  
+
   public AnonymousSecurityToken(String container) {
     this(container, 0L, "", null);
   }
 
-  public AnonymousSecurityToken(String container, long moduleId, String appUrl, Long expiresAt) {
-    this.container = container;
-    this.moduleId = moduleId;
-    this.appUrl = appUrl;
-    this.expiresAt = expiresAt;
-  }
-
-  public boolean isAnonymous() {
-    return true;
-  }
-
-  public String getOwnerId() {
-    return "-1";
-  }
-
-  public String getViewerId() {
-    return "-1";
+  public AnonymousSecurityToken(String container, Long moduleId, String appUrl, Long expiresAt) {
+    setContainer(container).setModuleId(moduleId).setAppUrl(appUrl).setExpiresAt(expiresAt)
+      .setOwnerId("-1")
+      .setViewerId("-1")
+      .setDomain("*")
+      .setTrustedJson("");
   }
 
+  @Override
   public String getAppId() {
-    return appUrl;
-  }
-
-  public String getDomain() {
-    return "*";
+    return getAppUrl();
   }
 
-  public String getContainer() {
-    return this.container;
-  }
-
-  public String getAppUrl() {
-    return appUrl;
-  }
-
-  public long getModuleId() {
-    return moduleId;
-  }
-
-  public Long getExpiresAt() {
-    return expiresAt;
+  public boolean isAnonymous() {
+    return true;
   }
 
   public String getUpdatedToken() {
@@ -88,7 +63,11 @@ public class AnonymousSecurityToken exte
     return AuthenticationMode.UNAUTHENTICATED.name();
   }
 
-  public String getTrustedJson() {
-    return "";
+  public String getActiveUrl() {
+    throw new UnsupportedOperationException("No active URL available");
+  }
+
+  protected EnumSet<Keys> getMapKeys() {
+    return MAP_KEYS;
   }
 }

Modified: shindig/trunk/java/common/src/main/java/org/apache/shindig/auth/BasicSecurityToken.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/common/src/main/java/org/apache/shindig/auth/BasicSecurityToken.java?rev=1187358&r1=1187357&r2=1187358&view=diff
==============================================================================
--- shindig/trunk/java/common/src/main/java/org/apache/shindig/auth/BasicSecurityToken.java (original)
+++ shindig/trunk/java/common/src/main/java/org/apache/shindig/auth/BasicSecurityToken.java Fri Oct 21 14:19:33 2011
@@ -18,134 +18,24 @@
  */
 package org.apache.shindig.auth;
 
-import org.apache.shindig.common.crypto.BasicBlobCrypter;
-import org.apache.shindig.common.crypto.BlobCrypter;
-import org.apache.shindig.common.crypto.BlobCrypterException;
-
-import com.google.common.collect.Maps;
-
-import java.util.Map;
+import java.util.EnumSet;
 
 /**
  * Primitive token implementation that uses strings as tokens.
  */
-public class BasicSecurityToken extends AbstractSecurityToken implements SecurityToken {
-  /** serialized form of the token */
-  private final String token;
-
-  /** data from the token */
-  private final Map<String, String> tokenData;
-
-  /** tool to use for signing and encrypting the token */
-  private final BlobCrypter crypter = new BasicBlobCrypter(INSECURE_KEY);
-  
-  private final String activeUrl;
-
-  private static final byte[] INSECURE_KEY =
-    { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
-
-  private static final String OWNER_KEY = "o";
-  private static final String APP_KEY = "a";
-  private static final String VIEWER_KEY = "v";
-  private static final String DOMAIN_KEY = "d";
-  private static final String APPURL_KEY = "u";
-  private static final String MODULE_KEY = "m";
-  private static final String CONTAINER_KEY = "c";
-  private static final String EXPIRES_KEY = "x";
-
-  /**
-   * Generates a token from an input string
-   * @param token String form of token
-   * @param maxAge max age of the token (in seconds)
-   * @throws BlobCrypterException never
-   */
-  public BasicSecurityToken(String token, int maxAge, String activeUrl)
-      throws BlobCrypterException {
-    this.token = token;
-    this.tokenData = crypter.unwrap(token, maxAge);
-    this.activeUrl = activeUrl;
-  }
+public class BasicSecurityToken extends AbstractSecurityToken {
+  private static final EnumSet<Keys> SUPPORTED = EnumSet.noneOf(Keys.class);
 
   public BasicSecurityToken(String owner, String viewer, String app,
-      String domain, String appUrl, String moduleId, String container, String activeUrl, Long expiresAt)
-      throws BlobCrypterException {
-    tokenData = Maps.newHashMapWithExpectedSize(7);
-    putNullSafe(OWNER_KEY, owner);
-    putNullSafe(VIEWER_KEY, viewer);
-    putNullSafe(APP_KEY, app);
-    putNullSafe(DOMAIN_KEY, domain);
-    putNullSafe(APPURL_KEY, appUrl);
-    putNullSafe(MODULE_KEY, moduleId);
-    putNullSafe(CONTAINER_KEY, container);
-    if (expiresAt != null)
-      putNullSafe(EXPIRES_KEY, expiresAt.toString());
-
-    token = crypter.wrap(tokenData);
-    this.activeUrl = activeUrl;
-  }
-
-  private void putNullSafe(String key, String value) {
-    if (value != null) {
-      tokenData.put(key, value);
-    }
-  }
-
-  /**
-   * {@inheritDoc}
-   */
-  public String getAppId() {
-    return tokenData.get(APP_KEY);
-  }
-
-  /**
-   * {@inheritDoc}
-   */
-  public String getDomain() {
-    return tokenData.get(DOMAIN_KEY);
-  }
-
-  /**
-   * {@inheritDoc}
-   */
-  public String getContainer() {
-    return tokenData.get(CONTAINER_KEY);
-  }
-
-  /**
-   * {@inheritDoc}
-   */
-  public String getOwnerId() {
-    return tokenData.get(OWNER_KEY);
-  }
-
-  /**
-   * {@inheritDoc}
-   */
-  public String getViewerId() {
-    return tokenData.get(VIEWER_KEY);
-  }
-
-  /**
-   * {@inheritDoc}
-   */
-  public String getAppUrl() {
-    return tokenData.get(APPURL_KEY);
+      String domain, String appUrl, String moduleId, String container, String activeUrl, Long expiresAt) {
+    setOwnerId(owner).setViewerId(viewer).setAppId(app).setDomain(domain).setAppUrl(appUrl);
+    if (moduleId != null)
+      setModuleId(Long.parseLong(moduleId));
+    setContainer(container).setActiveUrl(activeUrl).setExpiresAt(expiresAt);
   }
 
-  /**
-   * {@inheritDoc}
-   */
-  public long getModuleId() {
-    return Long.parseLong(tokenData.get(MODULE_KEY));
-  }
-
-  public Long getExpiresAt() {
-    return Long.parseLong(tokenData.get(EXPIRES_KEY));
-  }
+  public BasicSecurityToken() { }
 
-  /**
-   * {@inheritDoc}
-   */
   public String getUpdatedToken() {
     return null;
   }
@@ -154,24 +44,25 @@ public class BasicSecurityToken extends 
     return AuthenticationMode.SECURITY_TOKEN_URL_PARAMETER.name();
   }
 
-  /**
-   * {@inheritDoc}
-   */
-  public String getTrustedJson() {
-    return null;
-  }
-
-  /**
-   * {@inheritDoc}
-   */
   public boolean isAnonymous() {
     return false;
   }
 
   public String getActiveUrl() {
+    String activeUrl = super.getActiveUrl();
     if (activeUrl == null) {
       throw new UnsupportedOperationException("No active URL available");
     }
     return activeUrl;
   }
+
+  /* (non-Javadoc)
+   * @see org.apache.shindig.auth.AbstractSecurityToken#getSupportedKeys()
+   *
+   * The codec for this token does not use a BlobCrypter, so we don't need the
+   * toMap and loadFromMap functionality.
+   */
+  protected EnumSet<Keys> getMapKeys() {
+    return SUPPORTED;
+  }
 }

Modified: shindig/trunk/java/common/src/main/java/org/apache/shindig/auth/BasicSecurityTokenCodec.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/common/src/main/java/org/apache/shindig/auth/BasicSecurityTokenCodec.java?rev=1187358&r1=1187357&r2=1187358&view=diff
==============================================================================
--- shindig/trunk/java/common/src/main/java/org/apache/shindig/auth/BasicSecurityTokenCodec.java (original)
+++ shindig/trunk/java/common/src/main/java/org/apache/shindig/auth/BasicSecurityTokenCodec.java Fri Oct 21 14:19:33 2011
@@ -43,6 +43,7 @@ public class BasicSecurityTokenCodec imp
   private static final int APP_URL_INDEX = 4;
   private static final int MODULE_ID_INDEX = 5;
   private static final int CONTAINER_ID_INDEX = 6;
+  private static final int EXPIRY_INDEX = 7; // for back compat, conditionally check later
   private static final int TOKEN_COUNT = CONTAINER_ID_INDEX + 1;
 
   /**
@@ -51,14 +52,17 @@ public class BasicSecurityTokenCodec imp
    * @return token with values separated by colons
    */
   public String encodeToken(SecurityToken token) {
+    BasicSecurityToken basicToken = new BasicSecurityToken();
+    basicToken.setExpires();  // Quick and dirty token expire calculation.
     return Joiner.on(":").join(
         Utf8UrlCoder.encode(token.getOwnerId()),
         Utf8UrlCoder.encode(token.getViewerId()),
         Utf8UrlCoder.encode(token.getAppId()),
         Utf8UrlCoder.encode(token.getDomain()),
         Utf8UrlCoder.encode(token.getAppUrl()),
-        Long.toString(token.getModuleId()),
-        Utf8UrlCoder.encode(token.getContainer()));
+        Long.toString(token.getModuleId(), 10),
+        Utf8UrlCoder.encode(token.getContainer()),
+        Long.toString(basicToken.getExpiresAt(), 10));
   }
 
 
@@ -78,11 +82,16 @@ public class BasicSecurityTokenCodec imp
 
     try {
       String[] tokens = StringUtils.split(token, ':');
-      if (tokens.length != TOKEN_COUNT) {
+      if (tokens.length < TOKEN_COUNT) {
         throw new SecurityTokenException("Malformed security token");
       }
 
-      return new BasicSecurityToken(
+      Long expires = null;
+      if (tokens.length > TOKEN_COUNT && !tokens[EXPIRY_INDEX].equals("")) {
+        expires = Long.parseLong(Utf8UrlCoder.decode(tokens[EXPIRY_INDEX]), 10);
+      }
+
+      BasicSecurityToken basicToken = new BasicSecurityToken(
           Utf8UrlCoder.decode(tokens[OWNER_INDEX]),
           Utf8UrlCoder.decode(tokens[VIEWER_INDEX]),
           Utf8UrlCoder.decode(tokens[APP_ID_INDEX]),
@@ -91,7 +100,8 @@ public class BasicSecurityTokenCodec imp
           Utf8UrlCoder.decode(tokens[MODULE_ID_INDEX]),
           Utf8UrlCoder.decode(tokens[CONTAINER_ID_INDEX]),
           parameters.get(SecurityTokenCodec.ACTIVE_URL_NAME),
-          null);
+          expires);
+      return basicToken.enforceNotExpired();
     } catch (BlobCrypterException e) {
       throw new SecurityTokenException(e);
     } catch (ArrayIndexOutOfBoundsException e) {
@@ -99,11 +109,6 @@ public class BasicSecurityTokenCodec imp
     }
   }
 
-  public Long getTokenExpiration(SecurityToken token) {
-    // TODO: Support and/or implement this operation.
-    return null;
-  }
-
   /**
    * Creates a signer with 24 hour token expiry
    */

Modified: shindig/trunk/java/common/src/main/java/org/apache/shindig/auth/BlobCrypterSecurityToken.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/common/src/main/java/org/apache/shindig/auth/BlobCrypterSecurityToken.java?rev=1187358&r1=1187357&r2=1187358&view=diff
==============================================================================
--- shindig/trunk/java/common/src/main/java/org/apache/shindig/auth/BlobCrypterSecurityToken.java (original)
+++ shindig/trunk/java/common/src/main/java/org/apache/shindig/auth/BlobCrypterSecurityToken.java Fri Oct 21 14:19:33 2011
@@ -18,13 +18,8 @@
  */
 package org.apache.shindig.auth;
 
-import org.apache.shindig.common.crypto.BlobCrypter;
-import org.apache.shindig.common.crypto.BlobCrypterException;
-
-import com.google.common.collect.Maps;
-
+import java.util.EnumSet;
 import java.util.Map;
-
 /**
  * Authentication based on a provided BlobCrypter.
  *
@@ -32,161 +27,24 @@ import java.util.Map;
  *
  * Container is included so different containers can use different security tokens if necessary.
  */
-public class BlobCrypterSecurityToken extends AbstractSecurityToken implements SecurityToken {
-
-  protected static final int MAX_TOKEN_LIFETIME_SECS = 3600;
-
-  protected static final String OWNER_KEY = "o";
-  protected static final String VIEWER_KEY = "v";
-  protected static final String GADGET_KEY = "g";
-  protected static final String GADGET_INSTANCE_KEY = "i";
-  protected static final String TRUSTED_JSON_KEY = "j";
-  protected static final String EXPIRES_KEY = "x";
-
-  protected final String container;
-  protected final String domain;
-
-  protected String ownerId;
-  protected String viewerId;
-  protected String appUrl;
-  protected long moduleId;
-  protected Long expiresAt;
-
-  protected String trustedJson;
-  protected String activeUrl;
+public class BlobCrypterSecurityToken extends AbstractSecurityToken {
+  private static final EnumSet<Keys> MAP_KEYS = EnumSet.of(
+    Keys.OWNER, Keys.VIEWER, Keys.APP_URL, Keys.MODULE_ID, Keys.EXPIRES, Keys.TRUSTED_JSON
+  );
 
   /**
    * Create a new security token.
    *
-   * @param crypter used for encryption and signing
    * @param container container that is issuing the token
    * @param domain domain to use for signed fetch with default signed fetch key.
+   * @param activeUrl
+   * @param values Other values to init into the token.
    */
-  public BlobCrypterSecurityToken(String container, String domain) {
-    this.container = container;
-    this.domain = domain;
-  }
-
-  /**
-   * Decrypt and verify a token.  Note that this is a low level API dealing directly with encrypted
-   * data, for a higher level API consider using the BlobCrypterSecurityTokenCodec instead.
-   *
-   * @param crypter crypter to use for decryption
-   * @param container container that minted the token
-   * @param domain oauth_consumer_key to use for signed fetch with default key
-   * @param token the encrypted token (just the portion after the first ":")
-   * @return the decrypted, verified token.
-   *
-   * @throws BlobCrypterException
-   */
-  public static BlobCrypterSecurityToken decrypt(BlobCrypter crypter, String container, String domain,
-        String token, String activeUrl) throws BlobCrypterException {
-    Map<String, String> values = crypter.unwrap(token, MAX_TOKEN_LIFETIME_SECS);
-    BlobCrypterSecurityToken t = new BlobCrypterSecurityToken(container, domain);
-    setTokenValues(t, values);
-    t.setActiveUrl(activeUrl);
-    return t;
-  }
-  
-  protected static void setTokenValues(BlobCrypterSecurityToken token, Map<String, String> values) {
-    token.setOwnerId(values.get(OWNER_KEY));
-    token.setViewerId(values.get(VIEWER_KEY));
-    token.setAppUrl(values.get(GADGET_KEY));
-    String moduleId = values.get(GADGET_INSTANCE_KEY);
-    if (moduleId != null) {
-      token.setModuleId(Long.parseLong(moduleId));
-    }
-    String expiresAt = values.get(EXPIRES_KEY);
-    if (expiresAt != null) {
-      token.setExpiresAt(Long.parseLong(expiresAt));
-    }
-    token.setTrustedJson(values.get(TRUSTED_JSON_KEY));
-  }
-
-  /**
-   * Encrypt and sign the token.  The returned value is *not* web safe, it should be URL
-   * encoded before being used as a form parameter.
-   */
-  public static String encrypt(SecurityToken token, BlobCrypter crypter) throws BlobCrypterException {
-    Map<String, String> values = buildValuesMap(token);
-    return token.getContainer() + ':' + crypter.wrap(values);
-  }
-
-  protected static Map<String, String> buildValuesMap(SecurityToken token) {
-    Map<String, String> values = Maps.newHashMap();
-    if (token.getOwnerId() != null) {
-      values.put(OWNER_KEY, token.getOwnerId());
-    }
-    if (token.getViewerId() != null) {
-      values.put(VIEWER_KEY, token.getViewerId());
-    }
-    if (token.getAppUrl() != null) {
-      values.put(GADGET_KEY, token.getAppUrl());
+  public BlobCrypterSecurityToken(String container, String domain, String activeUrl, Map<String, String> values) {
+    if (values != null) {
+      loadFromMap(values);
     }
-    if (token.getModuleId() != 0) {
-      values.put(GADGET_INSTANCE_KEY, Long.toString(token.getModuleId()));
-    }
-    if (token.getExpiresAt() != null) {
-      values.put(EXPIRES_KEY, Long.toString(token.getExpiresAt()));
-    }
-    if (token.getTrustedJson() != null) {
-      values.put(TRUSTED_JSON_KEY, token.getTrustedJson());
-    }
-    return values;                                                                                           
-   }
-
-  // Legacy value for signed fetch, opensocial 0.8 prefers opensocial_app_url
-  public String getAppId() {
-    return appUrl;
-  }
-
-  public String getAppUrl() {
-    return appUrl;
-  }
-
-  public void setAppUrl(String appUrl) {
-    this.appUrl = appUrl;
-  }
-
-  public String getContainer() {
-    return container;
-  }
-
-  // Used for oauth_consumer_key for signed fetch with default key.  This is a weird spot for this.
-  public String getDomain() {
-    return domain;
-  }
-
-  public long getModuleId() {
-    return moduleId;
-  }
-
-  public void setModuleId(long moduleId) {
-    this.moduleId = moduleId;
-  }
-
-  public Long getExpiresAt() {
-    return expiresAt;
-  }
-
-  public void setExpiresAt(Long expiresAt) {
-    this.expiresAt = expiresAt;
-  }
-
-  public String getOwnerId() {
-    return ownerId;
-  }
-
-  public void setOwnerId(String ownerId) {
-    this.ownerId = ownerId;
-  }
-
-  public String getTrustedJson() {
-    return trustedJson;
-  }
-
-  public void setTrustedJson(String trustedJson) {
-    this.trustedJson = trustedJson;
+    setContainer(container).setDomain(domain).setActiveUrl(activeUrl);
   }
 
   // Our tokens are static, we could change this to periodically update the token.
@@ -198,26 +56,45 @@ public class BlobCrypterSecurityToken ex
     return AuthenticationMode.SECURITY_TOKEN_URL_PARAMETER.name();
   }
 
-  public String getViewerId() {
-    return viewerId;
-  }
-
-  public void setViewerId(String viewerId) {
-    this.viewerId = viewerId;
-  }
-
   public boolean isAnonymous() {
     return false;
   }
 
-  public void setActiveUrl(String activeUrl) {
-    this.activeUrl = activeUrl;
-  }
-
   public String getActiveUrl() {
+    String activeUrl = super.getActiveUrl();
     if (activeUrl == null) {
       throw new UnsupportedOperationException("No active URL available");
     }
     return activeUrl;
   }
+
+  // Legacy value for signed fetch, opensocial 0.8 prefers opensocial_app_url
+  @Override
+  public String getAppId() {
+    return getAppUrl();
+  }
+
+  protected EnumSet<Keys> getMapKeys() {
+    return MAP_KEYS;
+  }
+
+  public static BlobCrypterSecurityToken fromToken(SecurityToken token) {
+    String activeUrl = null;
+    try {
+      activeUrl = token.getActiveUrl();
+    } catch (UnsupportedOperationException e) {}
+
+    BlobCrypterSecurityToken interpretedToken = new BlobCrypterSecurityToken(
+        token.getContainer(), token.getDomain(), activeUrl, null);
+    interpretedToken
+        .setAppId(token.getAppId())
+        .setAppUrl(token.getAppUrl())
+        .setExpiresAt(token.getExpiresAt())
+        .setModuleId(token.getModuleId())
+        .setOwnerId(token.getOwnerId())
+        .setTrustedJson(token.getTrustedJson())
+        .setViewerId(token.getViewerId());
+
+    return interpretedToken;
+  }
 }

Modified: shindig/trunk/java/common/src/main/java/org/apache/shindig/auth/BlobCrypterSecurityTokenCodec.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/common/src/main/java/org/apache/shindig/auth/BlobCrypterSecurityTokenCodec.java?rev=1187358&r1=1187357&r2=1187358&view=diff
==============================================================================
--- shindig/trunk/java/common/src/main/java/org/apache/shindig/auth/BlobCrypterSecurityTokenCodec.java (original)
+++ shindig/trunk/java/common/src/main/java/org/apache/shindig/auth/BlobCrypterSecurityTokenCodec.java Fri Oct 21 14:19:33 2011
@@ -18,6 +18,12 @@
  */
 package org.apache.shindig.auth;
 
+import java.io.IOException;
+import java.util.Collection;
+import java.util.Map;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
 import org.apache.commons.io.IOUtils;
 import org.apache.commons.lang.StringUtils;
 import org.apache.shindig.common.crypto.BasicBlobCrypter;
@@ -30,13 +36,6 @@ import com.google.common.collect.Maps;
 import com.google.inject.Inject;
 import com.google.inject.Singleton;
 
-import java.io.File;
-import java.io.IOException;
-import java.util.Collection;
-import java.util.Map;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
 /**
  * Provides security token decoding services.  Configuration is via containers.js.  Each container
  * should specify (or inherit)
@@ -103,7 +102,7 @@ public class BlobCrypterSecurityTokenCod
     crypters = newCrypters;
     domains = newDomains;
   }
-  
+
   private void loadContainers(ContainerConfig config, Collection<String> containers,
       Map<String, BlobCrypter> crypters, Map<String, String> domains) throws IOException {
     for (String container : containers) {
@@ -153,32 +152,39 @@ public class BlobCrypterSecurityTokenCod
     String activeUrl = tokenParameters.get(SecurityTokenCodec.ACTIVE_URL_NAME);
     String crypted = fields[1];
     try {
-      return BlobCrypterSecurityToken.decrypt(crypter, container, domain, crypted, activeUrl);
+      BlobCrypterSecurityToken st = new BlobCrypterSecurityToken(container, domain, activeUrl,
+          crypter.unwrap(crypted));
+      return st.enforceNotExpired();
     } catch (BlobCrypterException e) {
       throw new SecurityTokenException(e);
     }
   }
 
+  /**
+   * Encrypt and sign the token.  The returned value is *not* web safe, it should be URL
+   * encoded before being used as a form parameter.
+   */
   public String encodeToken(SecurityToken token) throws SecurityTokenException {
     if (!token.getAuthenticationMode().equals(
             AuthenticationMode.SECURITY_TOKEN_URL_PARAMETER.name())) {
       throw new SecurityTokenException("Can only encode BlogCrypterSecurityTokens");
     }
 
-    BlobCrypter crypter = crypters.get(token.getContainer());
+    // Test code sends in real AbstractTokens, they have modified time sources in them so
+    // that we can test token expiration, production tokens are proxied via the SecurityToken interface.
+    AbstractSecurityToken aToken = token instanceof AbstractSecurityToken ?
+        (AbstractSecurityToken)token : BlobCrypterSecurityToken.fromToken(token);
+
+    BlobCrypter crypter = crypters.get(aToken.getContainer());
     if (crypter == null) {
-      throw new SecurityTokenException("Unknown container " + token.getContainer());
+      throw new SecurityTokenException("Unknown container " + aToken.getContainer());
     }
-    
+
     try {
-      return BlobCrypterSecurityToken.encrypt(token, crypter);
+      aToken.setExpires();
+      return aToken.getContainer() + ':' + crypter.wrap(aToken.toMap());
     } catch (BlobCrypterException e) {
       throw new SecurityTokenException(e);
     }
   }
-
-  public Long getTokenExpiration(SecurityToken token) {
-    // TODO: Support and/or implement this operation.
-    return null;
-  }
 }

Modified: shindig/trunk/java/common/src/main/java/org/apache/shindig/auth/DefaultSecurityTokenCodec.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/common/src/main/java/org/apache/shindig/auth/DefaultSecurityTokenCodec.java?rev=1187358&r1=1187357&r2=1187358&view=diff
==============================================================================
--- shindig/trunk/java/common/src/main/java/org/apache/shindig/auth/DefaultSecurityTokenCodec.java (original)
+++ shindig/trunk/java/common/src/main/java/org/apache/shindig/auth/DefaultSecurityTokenCodec.java Fri Oct 21 14:19:33 2011
@@ -74,8 +74,4 @@ public class DefaultSecurityTokenCodec i
     }
     return codec.encodeToken(token);
   }
-
-  public Long getTokenExpiration(SecurityToken token) throws SecurityTokenException {
-    return codec.getTokenExpiration(token);
-  }
 }

Modified: shindig/trunk/java/common/src/main/java/org/apache/shindig/auth/SecurityToken.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/common/src/main/java/org/apache/shindig/auth/SecurityToken.java?rev=1187358&r1=1187357&r2=1187358&view=diff
==============================================================================
--- shindig/trunk/java/common/src/main/java/org/apache/shindig/auth/SecurityToken.java (original)
+++ shindig/trunk/java/common/src/main/java/org/apache/shindig/auth/SecurityToken.java Fri Oct 21 14:19:33 2011
@@ -60,12 +60,13 @@ public interface SecurityToken {
   long getModuleId();
 
   /**
-   * @return the timestamp that this token expires or null if unknown or indeterminate
+   * @return The time in seconds since epoc that this token expires or
+   *   <code>null</code> if unknown or indeterminate.
    */
   Long getExpiresAt();
 
   /**
-   * @return true if the token is no longer valid
+   * @return true if the token is no longer valid.
    */
   boolean isExpired();
 
@@ -91,14 +92,14 @@ public interface SecurityToken {
    * @return true if the token is for an anonymous viewer/owner
    */
   boolean isAnonymous();
-  
+
   /**
    * @return the URL being used by the current request
-   * 
+   *
    * The returned URL must contain at least protocol, host, and port.
-   * 
+   *
    * The returned URL may contain path or query parameters.
-   * 
+   *
    * @throws UnsupportedOperationException if the URL is not available.
    */
   String getActiveUrl();

Modified: shindig/trunk/java/common/src/main/java/org/apache/shindig/auth/SecurityTokenCodec.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/common/src/main/java/org/apache/shindig/auth/SecurityTokenCodec.java?rev=1187358&r1=1187357&r2=1187358&view=diff
==============================================================================
--- shindig/trunk/java/common/src/main/java/org/apache/shindig/auth/SecurityTokenCodec.java (original)
+++ shindig/trunk/java/common/src/main/java/org/apache/shindig/auth/SecurityTokenCodec.java Fri Oct 21 14:19:33 2011
@@ -53,7 +53,4 @@ public interface SecurityTokenCodec {
       throws SecurityTokenException;
 
   String encodeToken(SecurityToken token) throws SecurityTokenException;
-
-  Long getTokenExpiration(SecurityToken token) throws SecurityTokenException;
-
 }

Modified: shindig/trunk/java/common/src/main/java/org/apache/shindig/common/crypto/BasicBlobCrypter.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/common/src/main/java/org/apache/shindig/common/crypto/BasicBlobCrypter.java?rev=1187358&r1=1187357&r2=1187358&view=diff
==============================================================================
--- shindig/trunk/java/common/src/main/java/org/apache/shindig/common/crypto/BasicBlobCrypter.java (original)
+++ shindig/trunk/java/common/src/main/java/org/apache/shindig/common/crypto/BasicBlobCrypter.java Fri Oct 21 14:19:33 2011
@@ -48,15 +48,9 @@ public class BasicBlobCrypter implements
   private static final byte CIPHER_KEY_LABEL = 0;
   private static final byte HMAC_KEY_LABEL = 1;
 
-  /** Key used for time stamp (in seconds) of data */
-  public static final String TIMESTAMP_KEY = "t";
-
   /** minimum length of master key */
   public static final int MASTER_KEY_MIN_LEN = 16;
 
-  /** allow three minutes for clock skew */
-  private static final long CLOCK_SKEW_ALLOWANCE = 180;
-
   public TimeSource timeSource = new TimeSource();
   private byte[] cipherKey;
   private byte[] hmacKey;
@@ -149,13 +143,9 @@ public class BasicBlobCrypter implements
   /* (non-Javadoc)
    * @see org.apache.shindig.util.BlobCrypter#wrap(java.util.Map)
    */
-  public String wrap(Map<String, String> in)
-  throws BlobCrypterException {
-    Preconditions.checkArgument(!in.containsKey(TIMESTAMP_KEY),
-        "No '%s' key allowed for BlobCrypter", TIMESTAMP_KEY);
-
+  public String wrap(Map<String, String> in) throws BlobCrypterException {
     try {
-      byte[] encoded = serializeAndTimestamp(in);
+      byte[] encoded = serialize(in);
       byte[] cipherText = Crypto.aes128cbcEncrypt(cipherKey, encoded);
       byte[] hmac = Crypto.hmacSha1(hmacKey, cipherText);
       byte[] b64 = Base64.encodeBase64URLSafe(Bytes.concat(cipherText, hmac));
@@ -167,10 +157,10 @@ public class BasicBlobCrypter implements
 
   /**
    * Encode the input for transfer.  We use something a lot like HTML form
-   * encodings.  The time stamp is in seconds since the epoch.
+   * encodings.
    * @param in map of parameters to encode
    */
-  private byte[] serializeAndTimestamp(Map<String, String> in) {
+  private byte[] serialize(Map<String, String> in) {
     StringBuilder sb = new StringBuilder();
 
     for (Map.Entry<String, String> val : in.entrySet()) {
@@ -179,17 +169,16 @@ public class BasicBlobCrypter implements
       sb.append(Utf8UrlCoder.encode(val.getValue()));
       sb.append('&');
     }
-    sb.append(TIMESTAMP_KEY);
-    sb.append('=');
-    sb.append(timeSource.currentTimeMillis()/1000);
+    if (sb.length() > 0) {
+      sb.deleteCharAt(sb.length() - 1);  // Remove the last &
+    }
     return CharsetUtil.getUtf8Bytes(sb.toString());
   }
 
   /* (non-Javadoc)
    * @see org.apache.shindig.util.BlobCrypter#unwrap(java.lang.String, int)
    */
-  public Map<String, String> unwrap(String in, int maxAgeSec)
-  throws BlobCrypterException {
+  public Map<String, String> unwrap(String in) throws BlobCrypterException {
     try {
       byte[] bin = Base64.decodeBase64(CharsetUtil.getUtf8Bytes(in));
       byte[] hmac = new byte[Crypto.HMAC_SHA1_LEN];
@@ -199,7 +188,6 @@ public class BasicBlobCrypter implements
       Crypto.hmacSha1Verify(hmacKey, cipherText, hmac);
       byte[] plain = Crypto.aes128cbcDecrypt(cipherKey, cipherText);
       Map<String, String> out = deserialize(plain);
-      checkTimestamp(out, maxAgeSec);
       return out;
     } catch (GeneralSecurityException e) {
       throw new BlobCrypterException("Invalid token signature", e);
@@ -223,20 +211,4 @@ public class BasicBlobCrypter implements
     }
     return map;
   }
-
-  /**
-   * We allow a few minutes on either side of the validity window to account
-   * for clock skew.
-   */
-  private void checkTimestamp(Map<String, String> out, int maxAge)
-  throws BlobExpiredException {
-    long origin = Long.parseLong(out.get(TIMESTAMP_KEY));
-    long minTime = origin - CLOCK_SKEW_ALLOWANCE;
-    long maxTime = origin + maxAge + CLOCK_SKEW_ALLOWANCE;
-    long now = timeSource.currentTimeMillis()/1000;
-    if (!(minTime < now && now < maxTime)) {
-      throw new BlobExpiredException(minTime, now, maxTime);
-    }
-  }
-
 }

Modified: shindig/trunk/java/common/src/main/java/org/apache/shindig/common/crypto/BlobCrypter.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/common/src/main/java/org/apache/shindig/common/crypto/BlobCrypter.java?rev=1187358&r1=1187357&r2=1187358&view=diff
==============================================================================
--- shindig/trunk/java/common/src/main/java/org/apache/shindig/common/crypto/BlobCrypter.java (original)
+++ shindig/trunk/java/common/src/main/java/org/apache/shindig/common/crypto/BlobCrypter.java Fri Oct 21 14:19:33 2011
@@ -21,16 +21,15 @@ package org.apache.shindig.common.crypto
 import java.util.Map;
 
 /**
- * Utility interface for managing signed, encrypted, and time stamped blobs.
- * Blobs are made up of name/value pairs.  Time stamps are automatically
- * included and checked.
+ * Utility interface for managing signed and encrypted blobs.
+ * Blobs are made up of name/value pairs.
  *
  * Thread safe.
  */
 public interface BlobCrypter {
 
   /**
-   * Time stamps, encrypts, and signs a blob.
+   * Encrypts and signs a blob.
    *
    * @param in name/value pairs to encrypt
    * @return a base64 encoded blob
@@ -43,12 +42,9 @@ public interface BlobCrypter {
    * Unwraps a blob.
    *
    * @param in blob
-   * @param maxAgeSec maximum age for the blob
-   * @return the name/value pairs, including the origin timestamp.
+   * @return the name/value pairs.
    *
-   * @throws BlobExpiredException if the blob is too old to be accepted.
    * @throws BlobCrypterException if the blob can't be decoded.
    */
-  Map<String, String> unwrap(String in, int maxAgeSec)
-      throws BlobCrypterException;
+  Map<String, String> unwrap(String in) throws BlobCrypterException;
 }

Modified: shindig/trunk/java/common/src/main/java/org/apache/shindig/common/crypto/BlobExpiredException.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/common/src/main/java/org/apache/shindig/common/crypto/BlobExpiredException.java?rev=1187358&r1=1187357&r2=1187358&view=diff
==============================================================================
--- shindig/trunk/java/common/src/main/java/org/apache/shindig/common/crypto/BlobExpiredException.java (original)
+++ shindig/trunk/java/common/src/main/java/org/apache/shindig/common/crypto/BlobExpiredException.java Fri Oct 21 14:19:33 2011
@@ -25,20 +25,16 @@ import java.util.Date;
  */
 public class BlobExpiredException extends BlobCrypterException {
 
-  public final Date minDate;
   public final Date used;
   public final Date maxDate;
 
-  public BlobExpiredException(long minTime, long now, long maxTime) {
-    this(new Date(minTime*1000), new Date(now*1000), new Date(maxTime*1000));
+  public BlobExpiredException(long now, long maxTime) {
+    this(new Date(now*1000), new Date(maxTime*1000));
   }
 
-  public BlobExpiredException(Date minTime, Date now, Date maxTime) {
-    super("Blob expired, was valid from " + minTime + " to " + maxTime
-        + ", attempted use at " + now);
-    this.minDate = minTime;
+  public BlobExpiredException(Date now, Date maxTime) {
+    super("Blob expired. Was valid until " + maxTime + ", attempted use at " + now);
     this.used = now;
     this.maxDate = maxTime;
   }
-
 }

Modified: shindig/trunk/java/common/src/test/java/org/apache/shindig/auth/BasicSecurityTokenCodecTest.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/common/src/test/java/org/apache/shindig/auth/BasicSecurityTokenCodecTest.java?rev=1187358&r1=1187357&r2=1187358&view=diff
==============================================================================
--- shindig/trunk/java/common/src/test/java/org/apache/shindig/auth/BasicSecurityTokenCodecTest.java (original)
+++ shindig/trunk/java/common/src/test/java/org/apache/shindig/auth/BasicSecurityTokenCodecTest.java Fri Oct 21 14:19:33 2011
@@ -18,10 +18,7 @@
  */
 package org.apache.shindig.auth;
 
-import static junit.framework.Assert.assertNull;
-
 import org.junit.Before;
-import org.junit.Test;
 
 public class BasicSecurityTokenCodecTest {
 
@@ -31,9 +28,4 @@ public class BasicSecurityTokenCodecTest
   public void setUp() throws Exception {
     codec = new BasicSecurityTokenCodec();
   }
-
-  @Test
-  public void testGetTokenExpiration() throws Exception {
-    assertNull(codec.getTokenExpiration(null));
-  }
 }

Modified: shindig/trunk/java/common/src/test/java/org/apache/shindig/auth/BlobCrypterSecurityTokenCodecTest.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/common/src/test/java/org/apache/shindig/auth/BlobCrypterSecurityTokenCodecTest.java?rev=1187358&r1=1187357&r2=1187358&view=diff
==============================================================================
--- shindig/trunk/java/common/src/test/java/org/apache/shindig/auth/BlobCrypterSecurityTokenCodecTest.java (original)
+++ shindig/trunk/java/common/src/test/java/org/apache/shindig/auth/BlobCrypterSecurityTokenCodecTest.java Fri Oct 21 14:19:33 2011
@@ -22,24 +22,22 @@ import static org.junit.Assert.assertEqu
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.shindig.auth.AbstractSecurityToken.Keys;
 import org.apache.shindig.common.crypto.BasicBlobCrypter;
 import org.apache.shindig.common.crypto.BlobCrypter;
 import org.apache.shindig.common.util.CharsetUtil;
 import org.apache.shindig.common.util.FakeTimeSource;
 import org.apache.shindig.config.BasicContainerConfig;
 import org.apache.shindig.config.ContainerConfig;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-
-import junit.framework.Assert;
-
 import org.junit.Before;
 import org.junit.Test;
 
-import java.io.File;
-import java.io.IOException;
-import java.util.Map;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
 
 /**
  * Tests for BlobCrypterSecurityTokenCodec
@@ -47,7 +45,7 @@ import java.util.Map;
 public class BlobCrypterSecurityTokenCodecTest {
 
   private BlobCrypterSecurityTokenCodec codec;
-  private final FakeTimeSource timeSource = new FakeTimeSource();
+  private FakeTimeSource timeSource;
   private ContainerConfig config;
 
   @Before
@@ -60,8 +58,9 @@ public class BlobCrypterSecurityTokenCod
         .addContainer(makeContainer("example"))
         .commit();
     codec = new CodecWithLoadStubbedOut(config);
+    timeSource = new FakeTimeSource();
   }
-  
+
   protected Map<String, Object> makeContainer(String container) {
     return ImmutableMap.<String, Object>of(ContainerConfig.CONTAINER_KEY,
         ImmutableList.of(container),
@@ -70,7 +69,7 @@ public class BlobCrypterSecurityTokenCod
         BlobCrypterSecurityTokenCodec.SIGNED_FETCH_DOMAIN,
         container + ".com");
   }
-  
+
   protected String getContainerKey(String container) {
     return "KEY FOR CONTAINER " + container;
   }
@@ -106,17 +105,17 @@ public class BlobCrypterSecurityTokenCod
 
   @Test
   public void testCreateToken() throws Exception {
-    BlobCrypterSecurityToken t = new BlobCrypterSecurityToken("container", null);
-    t.setAppUrl("http://www.example.com/gadget.xml");
-    t.setModuleId(12345L);
-    t.setOwnerId("owner");
-    t.setViewerId("viewer");
-    t.setTrustedJson("trusted");
-    String encrypted = BlobCrypterSecurityToken.encrypt(t,
-            getBlobCrypter(getContainerKey("container")));
+    Map<String, String> values = new HashMap<String, String>();
+    values.put(Keys.APP_URL.getKey(), "http://www.example.com/gadget.xml");
+    values.put(Keys.MODULE_ID.getKey(), Long.toString(12345L, 10));
+    values.put(Keys.OWNER.getKey(), "owner");
+    values.put(Keys.VIEWER.getKey(), "viewer");
+    values.put(Keys.TRUSTED_JSON.getKey(), "trusted");
 
-    SecurityToken t2 = codec.createToken(
-        ImmutableMap.of(SecurityTokenCodec.SECURITY_TOKEN_NAME, encrypted));
+    BlobCrypterSecurityToken t = new BlobCrypterSecurityToken("container", null, null, values);
+    String encrypted = t.getContainer() + ":" + getBlobCrypter(getContainerKey("container")).wrap(t.toMap());
+
+    SecurityToken t2 = codec.createToken(ImmutableMap.of(SecurityTokenCodec.SECURITY_TOKEN_NAME, encrypted));
 
     assertEquals("http://www.example.com/gadget.xml", t2.getAppId());
     assertEquals("http://www.example.com/gadget.xml", t2.getAppUrl());
@@ -129,14 +128,15 @@ public class BlobCrypterSecurityTokenCod
 
   @Test
   public void testUnknownContainer() throws Exception {
-    BlobCrypterSecurityToken t = new BlobCrypterSecurityToken("container", null);
-    t.setAppUrl("http://www.example.com/gadget.xml");
-    t.setModuleId(12345L);
-    t.setOwnerId("owner");
-    t.setViewerId("viewer");
-    t.setTrustedJson("trusted");
-    String encrypted = BlobCrypterSecurityToken.encrypt(t,
-            getBlobCrypter(getContainerKey("container")));
+    Map<String, String> values = new HashMap<String, String>();
+    values.put(Keys.APP_URL.getKey(), "http://www.example.com/gadget.xml");
+    values.put(Keys.MODULE_ID.getKey(), Long.toString(12345L, 10));
+    values.put(Keys.OWNER.getKey(), "owner");
+    values.put(Keys.VIEWER.getKey(), "viewer");
+    values.put(Keys.TRUSTED_JSON.getKey(), "trusted");
+
+    BlobCrypterSecurityToken t = new BlobCrypterSecurityToken("container", null, null, values);
+    String encrypted = t.getContainer() + ":" + getBlobCrypter(getContainerKey("container")).wrap(t.toMap());
     encrypted = encrypted.replace("container:", "other:");
 
     try {
@@ -149,14 +149,15 @@ public class BlobCrypterSecurityTokenCod
 
   @Test
   public void testWrongContainer() throws Exception {
-    BlobCrypterSecurityToken t = new BlobCrypterSecurityToken("container", null);
-    t.setAppUrl("http://www.example.com/gadget.xml");
-    t.setModuleId(12345L);
-    t.setOwnerId("owner");
-    t.setViewerId("viewer");
-    t.setTrustedJson("trusted");
-    String encrypted = BlobCrypterSecurityToken.encrypt(t,
-            getBlobCrypter(getContainerKey("container")));
+    Map<String, String> values = new HashMap<String, String>();
+    values.put(Keys.APP_URL.getKey(), "http://www.example.com/gadget.xml");
+    values.put(Keys.MODULE_ID.getKey(), Long.toString(12345L, 10));
+    values.put(Keys.OWNER.getKey(), "owner");
+    values.put(Keys.VIEWER.getKey(), "viewer");
+    values.put(Keys.TRUSTED_JSON.getKey(), "trusted");
+
+    BlobCrypterSecurityToken t = new BlobCrypterSecurityToken("container", null, null, values);
+    String encrypted = t.getContainer() + ":" + getBlobCrypter(getContainerKey("container")).wrap(t.toMap());
     encrypted = encrypted.replace("container:", "example:");
 
     try {
@@ -169,16 +170,17 @@ public class BlobCrypterSecurityTokenCod
 
   @Test
   public void testExpired() throws Exception {
-    BlobCrypterSecurityToken t = new BlobCrypterSecurityToken("container", null);
-    t.setAppUrl("http://www.example.com/gadget.xml");
-    t.setModuleId(12345L);
-    t.setOwnerId("owner");
-    t.setViewerId("viewer");
-    t.setTrustedJson("trusted");
-    String encrypted = BlobCrypterSecurityToken.encrypt(t,
-            getBlobCrypter(getContainerKey("container")));
-
-    timeSource.incrementSeconds(3600 + 181); // one hour plus clock skew
+    Map<String, String> values = new HashMap<String, String>();
+    values.put(Keys.APP_URL.getKey(), "http://www.example.com/gadget.xml");
+    values.put(Keys.MODULE_ID.getKey(), Long.toString(12345L, 10));
+    values.put(Keys.OWNER.getKey(), "owner");
+    values.put(Keys.VIEWER.getKey(), "viewer");
+    values.put(Keys.TRUSTED_JSON.getKey(), "trusted");
+
+    BlobCrypterSecurityToken token = new BlobCrypterSecurityToken("container", null, null, values);
+    token.setTimeSource(timeSource);
+    timeSource.incrementSeconds(-1 * (3600 + 181)); // one hour plus clock skew
+    String encrypted = codec.encodeToken(token);
     try {
       codec.createToken(ImmutableMap.of(SecurityTokenCodec.SECURITY_TOKEN_NAME, encrypted));
       fail("should have expired");
@@ -223,14 +225,15 @@ public class BlobCrypterSecurityTokenCod
   @Test
   public void testChangingContainers() throws Exception {
     String newContainer = "newcontainer";
-    BlobCrypterSecurityToken t = new BlobCrypterSecurityToken(newContainer, null);
-    t.setAppUrl("http://www.example.com/gadget.xml");
-    t.setModuleId(12345L);
-    t.setOwnerId("owner");
-    t.setViewerId("viewer");
-    t.setTrustedJson("trusted");
-    String encrypted = BlobCrypterSecurityToken.encrypt(t,
-            getBlobCrypter(getContainerKey(newContainer)));
+    Map<String, String> values = new HashMap<String, String>();
+    values.put(Keys.APP_URL.getKey(), "http://www.example.com/gadget.xml");
+    values.put(Keys.MODULE_ID.getKey(), Long.toString(12345L, 10));
+    values.put(Keys.OWNER.getKey(), "owner");
+    values.put(Keys.VIEWER.getKey(), "viewer");
+    values.put(Keys.TRUSTED_JSON.getKey(), "trusted");
+
+    BlobCrypterSecurityToken t = new BlobCrypterSecurityToken(newContainer, null, null, values);
+    String encrypted = t.getContainer() + ":" + getBlobCrypter(getContainerKey(newContainer)).wrap(t.toMap());
 
     // fails when trying to create a token for a non-existing container
     try {
@@ -251,9 +254,4 @@ public class BlobCrypterSecurityTokenCod
       // pass
     }
   }
-
- @Test
-  public void testGetTokenExpiration() throws Exception {
-    Assert.assertNull(codec.getTokenExpiration(null));
-  }
 }

Modified: shindig/trunk/java/common/src/test/java/org/apache/shindig/auth/BlobCrypterSecurityTokenTest.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/common/src/test/java/org/apache/shindig/auth/BlobCrypterSecurityTokenTest.java?rev=1187358&r1=1187357&r2=1187358&view=diff
==============================================================================
--- shindig/trunk/java/common/src/test/java/org/apache/shindig/auth/BlobCrypterSecurityTokenTest.java (original)
+++ shindig/trunk/java/common/src/test/java/org/apache/shindig/auth/BlobCrypterSecurityTokenTest.java Fri Oct 21 14:19:33 2011
@@ -18,16 +18,18 @@
  */
 package org.apache.shindig.auth;
 
-import org.apache.commons.lang.StringUtils;
-import org.apache.shindig.common.crypto.BasicBlobCrypter;
-import org.apache.shindig.common.crypto.BlobExpiredException;
-import org.apache.shindig.common.crypto.Crypto;
-import org.apache.shindig.common.util.FakeTimeSource;
-
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.shindig.auth.AbstractSecurityToken.Keys;
+import org.apache.shindig.common.crypto.BasicBlobCrypter;
+import org.apache.shindig.common.crypto.Crypto;
+import org.apache.shindig.common.util.FakeTimeSource;
 import org.junit.Before;
 import org.junit.Test;
 
@@ -50,12 +52,12 @@ public class BlobCrypterSecurityTokenTes
 
   @Test(expected=UnsupportedOperationException.class)
   public void testNullValues() throws Exception {
-    BlobCrypterSecurityToken t = new BlobCrypterSecurityToken(CONTAINER, DOMAIN);
-    String token = BlobCrypterSecurityToken.encrypt(t, crypter);
+    BlobCrypterSecurityToken t = new BlobCrypterSecurityToken(CONTAINER, DOMAIN, null, null);
+    String token = t.getContainer() + ":" + crypter.wrap(t.toMap());
     assertTrue("should start with container: " + token, token.startsWith("container:"));
     String[] fields = StringUtils.split(token, ':');
-    BlobCrypterSecurityToken t2 =
-        BlobCrypterSecurityToken.decrypt(crypter, CONTAINER, DOMAIN, fields[1], null);
+    BlobCrypterSecurityToken t2 = new BlobCrypterSecurityToken(CONTAINER, DOMAIN, null, crypter.unwrap(fields[1]));
+
     assertNull(t2.getAppId(), t2.getAppId());
     assertNull(t2.getAppUrl(), t2.getAppUrl());
     assertEquals(DOMAIN, t2.getDomain());
@@ -72,17 +74,18 @@ public class BlobCrypterSecurityTokenTes
 
   @Test
   public void testRealValues() throws Exception {
-    BlobCrypterSecurityToken t = new BlobCrypterSecurityToken(CONTAINER, DOMAIN);
-    t.setAppUrl("http://www.example.com/gadget.xml");
-    t.setModuleId(12345L);
-    t.setOwnerId("owner");
-    t.setViewerId("viewer");
-    t.setTrustedJson("trusted");
-    String token = BlobCrypterSecurityToken.encrypt(t, crypter);
+    Map<String, String> values = new HashMap<String, String>();
+    values.put(Keys.APP_URL.getKey(), "http://www.example.com/gadget.xml");
+    values.put(Keys.MODULE_ID.getKey(), Long.toString(12345L, 10));
+    values.put(Keys.OWNER.getKey(), "owner");
+    values.put(Keys.VIEWER.getKey(), "viewer");
+    values.put(Keys.TRUSTED_JSON.getKey(), "trusted");
+
+    BlobCrypterSecurityToken t = new BlobCrypterSecurityToken(CONTAINER, DOMAIN, null, values);
+    String token = t.getContainer() + ":" + crypter.wrap(t.toMap());
     assertTrue("should start with container: " + token, token.startsWith("container:"));
     String[] fields = StringUtils.split(token, ':');
-    BlobCrypterSecurityToken t2 =
-        BlobCrypterSecurityToken.decrypt(crypter, CONTAINER, DOMAIN, fields[1], "active");
+    BlobCrypterSecurityToken t2 = new BlobCrypterSecurityToken(CONTAINER, DOMAIN, "active", crypter.unwrap(fields[1]));
     assertEquals("http://www.example.com/gadget.xml", t2.getAppId());
     assertEquals("http://www.example.com/gadget.xml", t2.getAppUrl());
     assertEquals(DOMAIN, t2.getDomain());
@@ -93,16 +96,4 @@ public class BlobCrypterSecurityTokenTes
     assertEquals(CONTAINER, t2.getContainer());
     assertEquals("active", t2.getActiveUrl());
   }
-
-  @Test(expected=BlobExpiredException.class)
-  public void testExpired() throws Exception {
-    BlobCrypterSecurityToken t = new BlobCrypterSecurityToken(CONTAINER, DOMAIN);
-    String token = BlobCrypterSecurityToken.encrypt(t, crypter);
-    // one hour plus clock skew
-    timeSource.incrementSeconds(3600 + 181);
-    String[] fields = StringUtils.split(token, ':');
-
-    // expect an exception
-    BlobCrypterSecurityToken.decrypt(crypter, CONTAINER, DOMAIN, fields[1], "active");
-  }
 }

Modified: shindig/trunk/java/common/src/test/java/org/apache/shindig/auth/DefaultSecurityTokenCodecTest.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/common/src/test/java/org/apache/shindig/auth/DefaultSecurityTokenCodecTest.java?rev=1187358&r1=1187357&r2=1187358&view=diff
==============================================================================
--- shindig/trunk/java/common/src/test/java/org/apache/shindig/auth/DefaultSecurityTokenCodecTest.java (original)
+++ shindig/trunk/java/common/src/test/java/org/apache/shindig/auth/DefaultSecurityTokenCodecTest.java Fri Oct 21 14:19:33 2011
@@ -19,21 +19,19 @@
 package org.apache.shindig.auth;
 
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
-import org.apache.shindig.config.BasicContainerConfig;
-
-import com.google.common.collect.Lists;
-
-import org.junit.Test;
-
 import java.io.FileNotFoundException;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Map;
 
+import org.apache.shindig.config.BasicContainerConfig;
+import org.junit.Test;
+
+import com.google.common.collect.Lists;
+
 /**
  * Tests of DefaultSecurityTokenCodec
  */
@@ -68,7 +66,8 @@ public class DefaultSecurityTokenCodecTe
   public void testBasicDecoder() throws Exception {
     DefaultSecurityTokenCodec codec = new DefaultSecurityTokenCodec(
         new FakeContainerConfig("insecure"));
-    String token = "o:v:app:domain:appurl:12345:container";
+    Long expires = System.currentTimeMillis() / 1000 + 500; // 50 seconds in the future
+    String token = "o:v:app:domain:appurl:12345:container:" +  Long.toString(expires, 10);
     Map<String, String> parameters = Collections.singletonMap(
         SecurityTokenCodec.SECURITY_TOKEN_NAME, token);
     SecurityToken st = codec.createToken(parameters);
@@ -76,7 +75,7 @@ public class DefaultSecurityTokenCodecTe
     assertEquals("v", st.getViewerId());
     assertEquals("appurl", st.getAppUrl());
     assertEquals("container", st.getContainer());
-    assertNull(codec.getTokenExpiration(st));
+    assertEquals(expires, st.getExpiresAt());
   }
 
   @Test

Modified: shindig/trunk/java/common/src/test/java/org/apache/shindig/auth/UrlParameterAuthenticationHandlerTest.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/common/src/test/java/org/apache/shindig/auth/UrlParameterAuthenticationHandlerTest.java?rev=1187358&r1=1187357&r2=1187358&view=diff
==============================================================================
--- shindig/trunk/java/common/src/test/java/org/apache/shindig/auth/UrlParameterAuthenticationHandlerTest.java (original)
+++ shindig/trunk/java/common/src/test/java/org/apache/shindig/auth/UrlParameterAuthenticationHandlerTest.java Fri Oct 21 14:19:33 2011
@@ -35,7 +35,7 @@ public class UrlParameterAuthenticationH
   public void setup() throws Exception {
     expectedToken = new BasicSecurityToken(
         "owner", "viewer", "app",
-        "domain", "appUrl", "moduleId", "container", "activeUrl", 1000L);
+        "domain", "appUrl", "0", "container", "activeUrl", 1000L);
     // Mock token codec
     codec = new SecurityTokenCodec() {
       public SecurityToken createToken(Map<String, String> tokenParameters) throws SecurityTokenException {
@@ -46,10 +46,6 @@ public class UrlParameterAuthenticationH
       public String encodeToken(SecurityToken token) throws SecurityTokenException {
         return null;
       }
-
-      public Long getTokenExpiration(SecurityToken token) throws SecurityTokenException {
-        return null;
-      }
     };
 
     authHandler = new UrlParameterAuthenticationHandler(codec, true);

Modified: shindig/trunk/java/common/src/test/java/org/apache/shindig/common/crypto/BlobCrypterTest.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/common/src/test/java/org/apache/shindig/common/crypto/BlobCrypterTest.java?rev=1187358&r1=1187357&r2=1187358&view=diff
==============================================================================
--- shindig/trunk/java/common/src/test/java/org/apache/shindig/common/crypto/BlobCrypterTest.java (original)
+++ shindig/trunk/java/common/src/test/java/org/apache/shindig/common/crypto/BlobCrypterTest.java Fri Oct 21 14:19:33 2011
@@ -59,7 +59,7 @@ public class BlobCrypterTest {
       in.put("a", string);
     }
     String blob = crypter.wrap(in);
-    Map<String, String> out = crypter.unwrap(blob, 0);
+    Map<String, String> out = crypter.unwrap(blob);
     assertEquals(string, out.get("a"));
   }
 
@@ -74,7 +74,7 @@ public class BlobCrypterTest {
 
   private void assertThrowsBlobCrypterException(String in) {
     try {
-      crypter.unwrap(in, 1000);
+      crypter.unwrap(in);
       fail("Should have thrown BlobCrypterException for input " + in);
     } catch (BlobCrypterException e) {
       // Good.
@@ -88,33 +88,12 @@ public class BlobCrypterTest {
       in.put(Integer.toString(i), Integer.toString(i));
     }
     String blob = crypter.wrap(in);
-    Map<String, String> out = crypter.unwrap(blob, 0);
+    Map<String, String> out = crypter.unwrap(blob);
     for (int i=0; i < 1000; i++) {
       assertEquals(out.get(Integer.toString(i)), Integer.toString(i));
     }
   }
 
-  @Test
-  public void testTimeStamping() throws Exception {
-    long start = 1201917724000L;
-    long skew = 180000;
-    int maxAge = 300; // 5 minutes
-    int realAge = 600; // 10 minutes
-    try {
-
-      timeSource.setCurrentTimeMillis(start);
-      Map<String, String> in = ImmutableMap.of("a","b");
-      String blob = crypter.wrap(in);
-      timeSource.incrementSeconds(realAge);
-      crypter.unwrap(blob, maxAge);
-      fail("Blob should have expired");
-    } catch (BlobExpiredException e) {
-      assertEquals(start-skew, e.minDate.getTime());
-      assertEquals(start+realAge*1000L, e.used.getTime());
-      assertEquals(start+skew+maxAge*1000L, e.maxDate.getTime());
-    }
-  }
-
   @Test(expected=BlobCrypterException.class)
   public void testTamperIV() throws Exception {
     Map<String, String> in = ImmutableMap.of("a","b");
@@ -123,7 +102,7 @@ public class BlobCrypterTest {
     byte[] blobBytes = Base64.decodeBase64(blob.getBytes());
     blobBytes[0] ^= 0x01;
     String tampered = new String(Base64.encodeBase64(blobBytes));
-    crypter.unwrap(tampered, 30);
+    crypter.unwrap(tampered);
   }
 
   @Test(expected=BlobCrypterException.class)
@@ -133,7 +112,7 @@ public class BlobCrypterTest {
     byte[] blobBytes = Base64.decodeBase64(blob.getBytes());
     blobBytes[30] ^= 0x01;
     String tampered = new String(Base64.encodeBase64(blobBytes));
-    crypter.unwrap(tampered, 30);
+    crypter.unwrap(tampered);
   }
 
   @Test(expected=BlobCrypterException.class)
@@ -144,7 +123,7 @@ public class BlobCrypterTest {
     byte[] blobBytes = Base64.decodeBase64(blob.getBytes());
     blobBytes[blobBytes.length-1] ^= 0x01;
     String tampered = new String(Base64.encodeBase64(blobBytes));
-    crypter.unwrap(tampered, 30);
+    crypter.unwrap(tampered);
   }
 
   @Test
@@ -153,7 +132,7 @@ public class BlobCrypterTest {
     Map<String, String> in = ImmutableMap.of("a","b");
 
     String blob = crypter.wrap(in);
-    Map<String, String> out = alt.unwrap(blob, 30);
+    Map<String, String> out = alt.unwrap(blob);
     assertEquals("b", out.get("a"));
   }
 
@@ -163,7 +142,7 @@ public class BlobCrypterTest {
     Map<String, String> in = ImmutableMap.of("a","b");
 
     String blob = crypter.wrap(in);
-    alt.unwrap(blob, 30);
+    alt.unwrap(blob);
   }
 
   @Test(expected=IllegalArgumentException.class)

Modified: shindig/trunk/java/common/src/test/java/org/apache/shindig/common/testing/FakeGadgetToken.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/common/src/test/java/org/apache/shindig/common/testing/FakeGadgetToken.java?rev=1187358&r1=1187357&r2=1187358&view=diff
==============================================================================
--- shindig/trunk/java/common/src/test/java/org/apache/shindig/common/testing/FakeGadgetToken.java (original)
+++ shindig/trunk/java/common/src/test/java/org/apache/shindig/common/testing/FakeGadgetToken.java Fri Oct 21 14:19:33 2011
@@ -18,212 +18,136 @@
  */
 package org.apache.shindig.common.testing;
 
+import java.util.EnumSet;
+import java.util.Map;
+
 import org.apache.shindig.auth.AbstractSecurityToken;
 import org.apache.shindig.auth.AuthenticationMode;
 import org.apache.shindig.auth.SecurityToken;
 import org.apache.shindig.auth.SecurityTokenCodec;
-
-import com.google.common.collect.Maps;
 import org.apache.shindig.auth.SecurityTokenException;
 
-import java.util.Map;
-
 /**
  * A fake SecurityToken implementation to help testing.
  */
-public class FakeGadgetToken extends AbstractSecurityToken implements SecurityToken {
-
-  private String updatedToken = null;
-  private String trustedJson = null;
+public class FakeGadgetToken extends AbstractSecurityToken {
 
-  private String ownerId = null;
-  private String viewerId = null;
-  private String appId = null;
-  private String domain = null;
-  private String container = null;
-  private String appUrl = null;
-  private String activeUrl = null;
   private String authMode = AuthenticationMode.SECURITY_TOKEN_URL_PARAMETER.name();
-  private int moduleId = 0;
-  private Long expiresAt = null;
-
-  public FakeGadgetToken setUpdatedToken(String updatedToken) {
-    this.updatedToken = updatedToken;
-    return this;
-  }
-
-  public FakeGadgetToken setTrustedJson(String trustedJson) {
-    this.trustedJson = trustedJson;
-    return this;
-  }
-
-  public FakeGadgetToken setOwnerId(String ownerId) {
-    this.ownerId = ownerId;
-    return this;
-  }
+  private String updated;
 
-  public FakeGadgetToken setViewerId(String viewerId) {
-    this.viewerId = viewerId;
-    return this;
+  public String getAuthenticationMode() {
+    return authMode;
   }
 
-  public FakeGadgetToken setAppId(String appId) {
-    this.appId = appId;
-    return this;
+  public boolean isAnonymous() {
+    return false;
   }
 
-  public FakeGadgetToken setDomain(String domain) {
-    this.domain = domain;
-    return this;
-  }
+  public FakeGadgetToken() {}
+  /**
+   * Create a fake security token from a map of parameter strings, keys are one of:
+   * ownerId, viewerId, domain, appUrl, appId, trustedJson, module
+   *
+   * @param paramMap
+   * @return The fake token
+   */
+  public FakeGadgetToken(Map<String, String> paramMap) {
+    this(
+      paramMap.get("appId"),
+      paramMap.get("appUrl"),
+      paramMap.get("domain"),
+      paramMap.get("ownerId"),
+      paramMap.get("trustedJson"),
+      paramMap.get("viewerId"),
+      paramMap.get("module")
+    );
+  }
+
+  public FakeGadgetToken(String appId, String appUrl, String domain, String ownerId, String trustedJson, String viewerId, String moduleId) {
+    setAppId(appId);
+    setAppUrl(appUrl);
+    setDomain(domain);
+    setOwnerId(ownerId);
+    setTrustedJson(trustedJson);
+    setViewerId(viewerId);
 
-  public FakeGadgetToken setContainer(String container) {
-    this.container = container;
-    return this;
+    if (moduleId != null) {
+      setModuleId(Long.parseLong(moduleId));
+    }
   }
 
-  public FakeGadgetToken setAppUrl(String appUrl) {
-    this.appUrl = appUrl;
-    return this;
-  }
+  /**
+   * SecurityTokenCodec for testing - this allows passing around a
+   * security token of format key=value&key2=value2, where key is one of:
+   * ownerId, viewerId, domain, appUrl, appId, trustedJson, module
+   */
+  public static class Codec implements SecurityTokenCodec {
+    public SecurityToken createToken(Map<String, String> tokenParameters)  {
+      return new FakeGadgetToken(tokenParameters);
+    }
 
-  public FakeGadgetToken setModuleId(int moduleId) {
-    this.moduleId = moduleId;
-    return this;
+    public String encodeToken(SecurityToken token) throws SecurityTokenException {
+      return null; // NOT USED
+    }
   }
 
-  public FakeGadgetToken setExpiresAt(Long expiresAt) {
-    this.expiresAt = expiresAt;
+  public FakeGadgetToken setAuthenticationMode(String authMode) {
+    this.authMode = authMode;
     return this;
   }
 
-  public FakeGadgetToken setActiveUrl(String activeUrl) {
-    this.activeUrl = activeUrl;
+  public FakeGadgetToken setUpdatedToken(String updated) {
+    this.updated = updated;
     return this;
   }
 
-  public void setAuthenticationMode(String authMode) {
-    this.authMode = authMode;
-  }
-
-  public String getOwnerId() {
-    return ownerId;
-  }
-
-  public String getViewerId() {
-    return viewerId;
-  }
-
-  public String getAppId() {
-    return appId;
-  }
-
-  public String getDomain() {
-    return domain;
-  }
-
-  public String getContainer() {
-    return container;
+  @Override
+  public String getUpdatedToken() {
+    return updated;
   }
 
-  public String getAppUrl() {
-    return appUrl;
+  @Override
+  protected EnumSet<Keys> getMapKeys() {
+    return EnumSet.noneOf(Keys.class);
   }
 
-  public long getModuleId() {
-    return moduleId;
+  public FakeGadgetToken setAppUrl(String appUrl) {
+    return (FakeGadgetToken)super.setAppUrl(appUrl);
   }
 
-  public Long getExpiresAt() {
-    return expiresAt;
+  public FakeGadgetToken setOwnerId(String ownerId) {
+    return (FakeGadgetToken)super.setOwnerId(ownerId);
   }
 
-  public String getUpdatedToken() {
-    return updatedToken;
+  public FakeGadgetToken setViewerId(String viewerId) {
+    return (FakeGadgetToken)super.setViewerId(viewerId);
   }
 
-  public String getAuthenticationMode() {
-    return authMode;
+  public FakeGadgetToken setAppId(String appId) {
+    return (FakeGadgetToken)super.setAppId(appId);
   }
 
-  public String getTrustedJson() {
-    return trustedJson;
+  public FakeGadgetToken setDomain(String domain) {
+    return (FakeGadgetToken)super.setDomain(domain);
   }
 
-  public boolean isAnonymous() {
-    return false;
+  public FakeGadgetToken setContainer(String container) {
+    return (FakeGadgetToken)super.setContainer(container);
   }
 
-  @Override
-  public String getActiveUrl() {
-    return activeUrl;
+  public FakeGadgetToken setModuleId(long moduleId) {
+    return (FakeGadgetToken)super.setModuleId(moduleId);
   }
 
-  /**
-   * Create a fake security token parameter string, allows passing around a
-   * security token of format key=value&key2=value2, where key is one of:
-   * ownerId, viewerId, domain, appUrl, appId, trustedJson, module.
-   *
-   * Useful for creating tokens that can be decoded with FakeGadgetToken.Decoder
-   *
-   * @param tokenString the parameter string
-   * @return The fake token
-   */
-  public static SecurityToken createToken(String tokenString)  {
-    String keyValuePairs[] = tokenString.split("&");
-    Map<String, String> paramMap = Maps.newHashMap();
-
-    for (String keyValuePair : keyValuePairs) {
-      String[] keyAndValue = keyValuePair.split("=");
-      if (keyAndValue.length == 2) {
-        paramMap.put(keyAndValue[0], keyAndValue[1]);
-      }
-    }
-
-    return createToken(paramMap);
+  public FakeGadgetToken setExpiresAt(Long expiresAt) {
+    return (FakeGadgetToken)super.setExpiresAt(expiresAt);
   }
 
-  /**
-   * Create a fake security token from a map of parameter strings, keys are one of:
-   * ownerId, viewerId, domain, appUrl, appId, trustedJson, module
-   *
-   * @param paramMap
-   * @return The fake token
-   */
-  public static FakeGadgetToken createToken(Map<String, String> paramMap) {
-    FakeGadgetToken fakeToken = new FakeGadgetToken();
-
-    fakeToken.setAppId(paramMap.get("appId"));
-    fakeToken.setAppUrl(paramMap.get("appUrl"));
-    fakeToken.setDomain(paramMap.get("domain"));
-    fakeToken.setOwnerId(paramMap.get("ownerId"));
-    fakeToken.setTrustedJson(paramMap.get("trustedJson"));
-    fakeToken.setViewerId(paramMap.get("viewerId"));
-
-    String moduleIdStr = paramMap.get("module");
-    if (moduleIdStr != null) {
-      fakeToken.setModuleId(Integer.parseInt(moduleIdStr));
-    }
-
-    return fakeToken;
+  public FakeGadgetToken setTrustedJson(String trustedJson) {
+    return (FakeGadgetToken)super.setTrustedJson(trustedJson);
   }
 
-  /**
-   * SecurityTokenCodec for testing - this allows passing around a
-   * security token of format key=value&key2=value2, where key is one of:
-   * ownerId, viewerId, domain, appUrl, appId, trustedJson, module
-   */
-  public static class Codec implements SecurityTokenCodec {
-    public SecurityToken createToken(Map<String, String> tokenParameters)  {
-      return FakeGadgetToken.createToken(tokenParameters);
-    }
-
-    public String encodeToken(SecurityToken token) throws SecurityTokenException {
-      return null; // NOT USED
-    }
-
-    public Long getTokenExpiration(SecurityToken token) throws SecurityTokenException {
-      return null; // NOT USED
-    }
+  public FakeGadgetToken setActiveUrl(String activeUrl) {
+    return (FakeGadgetToken)super.setActiveUrl(activeUrl);
   }
 }

Modified: shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/config/ShindigAuthConfigContributor.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/config/ShindigAuthConfigContributor.java?rev=1187358&r1=1187357&r2=1187358&view=diff
==============================================================================
--- shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/config/ShindigAuthConfigContributor.java (original)
+++ shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/config/ShindigAuthConfigContributor.java Fri Oct 21 14:19:33 2011
@@ -67,7 +67,7 @@ public class ShindigAuthConfigContributo
   /** {@inheritDoc} */
   public void contribute(Map<String,Object> config, String container, String host) {
     // Inject an anonymous security token TODO set TTL based on cachability of this JS?
-    SecurityToken containerToken = new AnonymousSecurityToken(container, 0,"*", 1000L * 60 * 60 * 24);
+    SecurityToken containerToken = new AnonymousSecurityToken(container, 0L,"*", null);
     Map<String, String> authConfig = Maps.newHashMapWithExpectedSize(2);
 
     try {

Modified: shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/OAuthCallbackState.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/OAuthCallbackState.java?rev=1187358&r1=1187357&r2=1187358&view=diff
==============================================================================
--- shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/OAuthCallbackState.java (original)
+++ shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/OAuthCallbackState.java Fri Oct 21 14:19:33 2011
@@ -32,43 +32,44 @@ import java.util.Map;
  */
 public class OAuthCallbackState {
 
-  private static final int CALLBACK_STATE_MAX_AGE_SECS = 600;
-  
-  private static final String REAL_CALLBACK_URL_KEY = "u";
-  
   private final BlobCrypter crypter;
-  private final Map<String, String> state;
-  
+  private OAuthCallbackStateToken state;
+
   public OAuthCallbackState(BlobCrypter crypter) {
     this.crypter = crypter;
-    this.state = Maps.newHashMap();
+    this.state = new OAuthCallbackStateToken();
   }
-  
+
   public OAuthCallbackState(BlobCrypter crypter, String stateBlob) {
     this.crypter = crypter;
-    Map<String, String> state = Maps.newHashMap();
+    Map<String, String> state = null;
     if (stateBlob != null) {
       try {
-        state = crypter.unwrap(stateBlob, CALLBACK_STATE_MAX_AGE_SECS);
+        state = crypter.unwrap(stateBlob);
+        if (state == null) {
+          state = Maps.newHashMap();
+        }
+        this.state = new OAuthCallbackStateToken(state);
+        this.state.enforceNotExpired();
       } catch (BlobCrypterException e) {
         // Too old, or corrupt.  Ignore it.
+        state = null;
       }
     }
     if (state == null) {
-      state = Maps.newHashMap();
+      this.state = new OAuthCallbackStateToken();
     }
-    this.state = state;
   }
-  
+
   public String getEncryptedState() throws BlobCrypterException {
-    return crypter.wrap(state);
+    return crypter.wrap(state.toMap());
   }
-  
+
   public String getRealCallbackUrl() {
-    return state.get(REAL_CALLBACK_URL_KEY);
+    return state.getRealCallbackUrl();
   }
-  
+
   public void setRealCallbackUrl(String realCallbackUrl) {
-    state.put(REAL_CALLBACK_URL_KEY, realCallbackUrl);
+    state.setRealCallbackUrl(realCallbackUrl);
   }
 }

Added: shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/OAuthCallbackStateToken.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/OAuthCallbackStateToken.java?rev=1187358&view=auto
==============================================================================
--- shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/OAuthCallbackStateToken.java (added)
+++ shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/OAuthCallbackStateToken.java Fri Oct 21 14:19:33 2011
@@ -0,0 +1,80 @@
+/*
+ * 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.oauth;
+
+import java.util.EnumSet;
+import java.util.Map;
+
+import org.apache.shindig.auth.AbstractSecurityToken;
+
+
+/**
+ * Token used to persist information for the {@link OAuthCallbackState}
+ */
+public class OAuthCallbackStateToken extends AbstractSecurityToken {
+  private static final EnumSet<Keys> MAP_KEYS = EnumSet.of(Keys.EXPIRES);
+  private static final String REAL_CALLBACK_URL_KEY = "u";
+
+  private String realCallbackUrl;
+
+  public OAuthCallbackStateToken () {}
+
+  public OAuthCallbackStateToken (Map<String, String> values) {
+    loadFromMap(values);
+    setRealCallbackUrl(values.get(REAL_CALLBACK_URL_KEY));
+  }
+
+  public String getUpdatedToken() {
+    return null;
+  }
+
+  public String getAuthenticationMode() {
+    return null;
+  }
+
+  public boolean isAnonymous() {
+    return false;
+  }
+
+  protected EnumSet<Keys> getMapKeys() {
+    return MAP_KEYS;
+  }
+
+  public OAuthCallbackStateToken setRealCallbackUrl(String realCallbackUrl) {
+    this.realCallbackUrl = realCallbackUrl;
+    return this;
+  }
+
+  @Override
+  protected int getMaxTokenTTL() {
+    return 600;
+  }
+
+  public String getRealCallbackUrl() {
+    return realCallbackUrl;
+  }
+
+  @Override
+  public Map<String, String> toMap() {
+    Map<String, String> map = super.toMap();
+    map.put(REAL_CALLBACK_URL_KEY, getRealCallbackUrl());
+    return map;
+  }
+}
+