You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@shindig.apache.org by be...@apache.org on 2008/09/24 03:10:30 UTC
svn commit: r698410 - in /incubator/shindig/trunk/java/common/src:
main/java/org/apache/shindig/auth/ test/java/org/apache/shindig/auth/
Author: beaton
Date: Tue Sep 23 18:10:30 2008
New Revision: 698410
URL: http://svn.apache.org/viewvc?rev=698410&view=rev
Log:
Provide real security tokens. There is no way to enable these without writing
Guice modules, yet.
Also remove the toSerialForm method from SecurityToken, since Shindig never
uses it.
Added:
incubator/shindig/trunk/java/common/src/main/java/org/apache/shindig/auth/BlobCrypterSecurityToken.java (with props)
incubator/shindig/trunk/java/common/src/main/java/org/apache/shindig/auth/BlobCrypterSecurityTokenDecoder.java (with props)
incubator/shindig/trunk/java/common/src/test/java/org/apache/shindig/auth/BlobCrypterSecurityTokenDecoderTest.java (with props)
incubator/shindig/trunk/java/common/src/test/java/org/apache/shindig/auth/BlobCrypterSecurityTokenTest.java (with props)
Modified:
incubator/shindig/trunk/java/common/src/main/java/org/apache/shindig/auth/SecurityToken.java
Added: incubator/shindig/trunk/java/common/src/main/java/org/apache/shindig/auth/BlobCrypterSecurityToken.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/common/src/main/java/org/apache/shindig/auth/BlobCrypterSecurityToken.java?rev=698410&view=auto
==============================================================================
--- incubator/shindig/trunk/java/common/src/main/java/org/apache/shindig/auth/BlobCrypterSecurityToken.java (added)
+++ incubator/shindig/trunk/java/common/src/main/java/org/apache/shindig/auth/BlobCrypterSecurityToken.java Tue Sep 23 18:10:30 2008
@@ -0,0 +1,177 @@
+/*
+ * 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.auth;
+
+import com.google.common.collect.Maps;
+
+import org.apache.shindig.common.crypto.BlobCrypter;
+import org.apache.shindig.common.crypto.BlobCrypterException;
+
+import java.util.Map;
+
+/**
+ * Authentication based on a provided BlobCrypter.
+ *
+ * Wire format is "<container>:<encrypted-and-signed-token>"
+ *
+ * Container is included so different containers can use different security tokens if necessary.
+ */
+public class BlobCrypterSecurityToken implements SecurityToken {
+
+ private static final int MAX_TOKEN_LIFETIME_SECS = 3600;
+
+ private static final String OWNER_KEY = "o";
+ private static final String VIEWER_KEY = "v";
+ private static final String GADGET_KEY = "g";
+ private static final String GADGET_INSTANCE_KEY = "i";
+ private static final String TRUSTED_JSON_KEY = "j";
+
+ private final BlobCrypter crypter;
+ private final String container;
+ private final String domain;
+
+ private String ownerId;
+ private String viewerId;
+ private String appUrl;
+ private long moduleId;
+ private String trustedJson;
+
+ /**
+ * 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.
+ */
+ public BlobCrypterSecurityToken(BlobCrypter crypter, String container, String domain) {
+ this.crypter = crypter;
+ this.container = container;
+ this.domain = domain;
+ }
+
+ /**
+ * Decrypt and verify a token. Note this is not public, use BlobCrypterSecurityTokenDecoder
+ * 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
+ */
+ static BlobCrypterSecurityToken decrypt(BlobCrypter crypter, String container, String domain,
+ String token) throws BlobCrypterException {
+ Map<String, String> values = crypter.unwrap(token, MAX_TOKEN_LIFETIME_SECS);
+ BlobCrypterSecurityToken t = new BlobCrypterSecurityToken(crypter, container, domain);
+ t.setOwnerId(values.get(OWNER_KEY));
+ t.setViewerId(values.get(VIEWER_KEY));
+ t.setAppUrl(values.get(GADGET_KEY));
+ String moduleId = values.get(GADGET_INSTANCE_KEY);
+ if (moduleId != null) {
+ t.setModuleId(Long.parseLong(moduleId));
+ }
+ t.setTrustedJson(values.get(TRUSTED_JSON_KEY));
+ return t;
+ }
+
+ /**
+ * 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 encrypt() throws BlobCrypterException {
+ Map<String, String> values = Maps.newHashMap();
+ if (ownerId != null) {
+ values.put(OWNER_KEY, ownerId);
+ }
+ if (viewerId != null) {
+ values.put(VIEWER_KEY, viewerId);
+ }
+ if (appUrl != null) {
+ values.put(GADGET_KEY, appUrl);
+ }
+ if (moduleId != 0) {
+ values.put(GADGET_INSTANCE_KEY, Long.toString(moduleId));
+ }
+ if (trustedJson != null) {
+ values.put(TRUSTED_JSON_KEY, trustedJson);
+ }
+ return container + ":" + crypter.wrap(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;
+ }
+
+ // 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 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;
+ }
+
+ // Our tokens are static, we could change this to periodically update the token.
+ public String getUpdatedToken() {
+ return null;
+ }
+
+ public String getViewerId() {
+ return viewerId;
+ }
+
+ public void setViewerId(String viewerId) {
+ this.viewerId = viewerId;
+ }
+
+ public boolean isAnonymous() {
+ return false;
+ }
+}
Propchange: incubator/shindig/trunk/java/common/src/main/java/org/apache/shindig/auth/BlobCrypterSecurityToken.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: incubator/shindig/trunk/java/common/src/main/java/org/apache/shindig/auth/BlobCrypterSecurityTokenDecoder.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/common/src/main/java/org/apache/shindig/auth/BlobCrypterSecurityTokenDecoder.java?rev=698410&view=auto
==============================================================================
--- incubator/shindig/trunk/java/common/src/main/java/org/apache/shindig/auth/BlobCrypterSecurityTokenDecoder.java (added)
+++ incubator/shindig/trunk/java/common/src/main/java/org/apache/shindig/auth/BlobCrypterSecurityTokenDecoder.java Tue Sep 23 18:10:30 2008
@@ -0,0 +1,118 @@
+/*
+ * 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.auth;
+
+import com.google.common.collect.Maps;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+
+import org.apache.shindig.common.ContainerConfig;
+import org.apache.shindig.common.crypto.BasicBlobCrypter;
+import org.apache.shindig.common.crypto.BlobCrypter;
+import org.apache.shindig.common.crypto.BlobCrypterException;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Map;
+
+/**
+ * Provides security token decoding services. Configuration is via containers.js. Each container
+ * should specify (or inherit)
+ *
+ * securityTokenKeyFile: path to file containing a key to use for verifying tokens.
+ * signedFetchDomain: oauth_consumer_key value to use for signed fetch using default key.
+ *
+ * Creating a key is best done with a command line like this:
+ *
+ * dd if=/dev/random bs=32 count=1 | openssl base64 > /tmp/key.txt
+ *
+ * Wire format is "<container>:<encrypted-and-signed-token>"
+ */
+@Singleton
+public class BlobCrypterSecurityTokenDecoder implements SecurityTokenDecoder {
+
+ public static final String SECURITY_TOKEN_KEY_FILE = "securityTokenKeyFile";
+
+ public static final String SIGNED_FETCH_DOMAIN = "signedFetchDomain";
+
+ /**
+ * Keys are container ids, values are crypters
+ */
+ private Map<String, BlobCrypter> crypters = Maps.newHashMap();
+
+ /**
+ * Keys are container ids, values are domains used for signed fetch.
+ */
+ private Map<String, String> domains = Maps.newHashMap();
+
+ @Inject
+ public BlobCrypterSecurityTokenDecoder(ContainerConfig config) {
+ try {
+ for (String container : config.getContainers()) {
+ String keyFile = config.get(container, SECURITY_TOKEN_KEY_FILE);
+ if (keyFile != null) {
+ BlobCrypter crypter = loadCrypterFromFile(new File(keyFile));
+ crypters.put(container, crypter);
+ }
+ String domain = config.get(container, SIGNED_FETCH_DOMAIN);
+ domains.put(container, domain);
+ }
+ } catch (IOException e) {
+ // Someone specified securityTokenKeyFile, but we couldn't load the key. That merits killing
+ // the server.
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Load a BlobCrypter from the specified file. Override this if you have your own
+ * BlobCrypter implementation.
+ */
+ protected BlobCrypter loadCrypterFromFile(File file) throws IOException {
+ return new BasicBlobCrypter(file);
+ }
+
+ /**
+ * Decrypt and verify the provided security token.
+ */
+ public SecurityToken createToken(Map<String, String> tokenParameters)
+ throws SecurityTokenException {
+ String token = tokenParameters.get(SecurityTokenDecoder.SECURITY_TOKEN_NAME);
+ if (token == null || token.trim().length() == 0) {
+ // No token is present, assume anonymous access
+ return new AnonymousSecurityToken();
+ }
+ String[] fields = token.split(":");
+ if (fields.length != 2) {
+ throw new SecurityTokenException("Invalid security token " + token);
+ }
+ String container = fields[0];
+ BlobCrypter crypter = crypters.get(container);
+ if (crypter == null) {
+ throw new SecurityTokenException("Unknown container " + token);
+ }
+ String domain = domains.get(container);
+ String crypted = fields[1];
+ try {
+ return BlobCrypterSecurityToken.decrypt(crypter, container, domain, crypted);
+ } catch (BlobCrypterException e) {
+ throw new SecurityTokenException(e);
+ }
+ }
+}
Propchange: incubator/shindig/trunk/java/common/src/main/java/org/apache/shindig/auth/BlobCrypterSecurityTokenDecoder.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified: incubator/shindig/trunk/java/common/src/main/java/org/apache/shindig/auth/SecurityToken.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/common/src/main/java/org/apache/shindig/auth/SecurityToken.java?rev=698410&r1=698409&r2=698410&view=diff
==============================================================================
--- incubator/shindig/trunk/java/common/src/main/java/org/apache/shindig/auth/SecurityToken.java (original)
+++ incubator/shindig/trunk/java/common/src/main/java/org/apache/shindig/auth/SecurityToken.java Tue Sep 23 18:10:30 2008
@@ -23,16 +23,7 @@
* Use in conjunction with @code SecurityTokenDecoder.
*/
public interface SecurityToken {
-
- /**
- * Serializes the token into a string. This can be the exact same as
- * toString; using a different name here is only to force interface
- * compliance.
- *
- * @return A string representation of the token.
- */
- public String toSerialForm();
-
+
/**
* @return the owner from the token, or null if there is none.
*/
Added: incubator/shindig/trunk/java/common/src/test/java/org/apache/shindig/auth/BlobCrypterSecurityTokenDecoderTest.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/common/src/test/java/org/apache/shindig/auth/BlobCrypterSecurityTokenDecoderTest.java?rev=698410&view=auto
==============================================================================
--- incubator/shindig/trunk/java/common/src/test/java/org/apache/shindig/auth/BlobCrypterSecurityTokenDecoderTest.java (added)
+++ incubator/shindig/trunk/java/common/src/test/java/org/apache/shindig/auth/BlobCrypterSecurityTokenDecoderTest.java Tue Sep 23 18:10:30 2008
@@ -0,0 +1,233 @@
+/*
+ * 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.auth;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+
+import org.apache.shindig.common.ContainerConfig;
+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.junit.Before;
+import org.junit.Test;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Collection;
+import java.util.Map;
+
+/**
+ * Tests for BlobCrypterSecurityTokenDecoder
+ */
+public class BlobCrypterSecurityTokenDecoderTest {
+
+ private BlobCrypterSecurityTokenDecoder decoder;
+ private FakeTimeSource timeSource = new FakeTimeSource();
+
+ @Before
+ public void setUp() throws Exception {
+ ContainerConfig config = new ContainerConfig(null) {
+ @Override
+ public String get(String container, String name) {
+ if (BlobCrypterSecurityTokenDecoder.SECURITY_TOKEN_KEY_FILE.equals(name)) {
+ return getContainerKey(container);
+ }
+ if (BlobCrypterSecurityTokenDecoder.SIGNED_FETCH_DOMAIN.equals(name)) {
+ return container + ".com";
+ }
+ throw new RuntimeException("Mock not smart enough, unknown name " + name);
+ }
+
+ @Override
+ public Collection<String> getContainers() {
+ return Lists.newArrayList("container", "example");
+ }
+ };
+ decoder = new DecoderWithLoadStubbedOut(config);
+ }
+
+ private String getContainerKey(String container) {
+ return "KEY FOR CONTAINER " + container;
+ }
+
+ private BlobCrypter getBlobCrypter(String fileName) {
+ BasicBlobCrypter c = new BasicBlobCrypter(CharsetUtil.getUtf8Bytes(fileName));
+ c.timeSource = timeSource;
+ return c;
+ }
+
+ /**
+ * Stubs out loading the key file.
+ */
+ private class DecoderWithLoadStubbedOut extends BlobCrypterSecurityTokenDecoder {
+
+ public DecoderWithLoadStubbedOut(ContainerConfig config) {
+ super(config);
+ }
+
+ /**
+ * @return a crypter based on the name of the file passed in, rather than the contents
+ */
+ @Override
+ protected BlobCrypter loadCrypterFromFile(File file) throws IOException {
+ if (file.getPath().contains("fail")) {
+ throw new IOException("Load failed: " + file);
+ }
+ return getBlobCrypter(file.getPath());
+ }
+ }
+
+ @Test
+ public void testCreateToken() throws Exception {
+ BlobCrypterSecurityToken t = new BlobCrypterSecurityToken(
+ getBlobCrypter(getContainerKey("container")), "container", null);
+ t.setAppUrl("http://www.example.com/gadget.xml");
+ t.setModuleId(12345L);
+ t.setOwnerId("owner");
+ t.setViewerId("viewer");
+ t.setTrustedJson("trusted");
+ String encrypted = t.encrypt();
+
+ SecurityToken t2 = decoder.createToken(
+ Maps.immutableMap(SecurityTokenDecoder.SECURITY_TOKEN_NAME, encrypted));
+
+ assertEquals("http://www.example.com/gadget.xml", t2.getAppId());
+ assertEquals("http://www.example.com/gadget.xml", t2.getAppUrl());
+ assertEquals("container.com", t2.getDomain());
+ assertEquals(12345L, t2.getModuleId());
+ assertEquals("owner", t2.getOwnerId());
+ assertEquals("viewer", t2.getViewerId());
+ assertEquals("trusted", t2.getTrustedJson());
+ }
+
+ @Test
+ public void testUnknownContainer() throws Exception {
+ BlobCrypterSecurityToken t = new BlobCrypterSecurityToken(
+ getBlobCrypter(getContainerKey("container")), "container", null);
+ t.setAppUrl("http://www.example.com/gadget.xml");
+ t.setModuleId(12345L);
+ t.setOwnerId("owner");
+ t.setViewerId("viewer");
+ t.setTrustedJson("trusted");
+ String encrypted = t.encrypt();
+ encrypted = encrypted.replace("container:", "other:");
+
+ try {
+ decoder.createToken(Maps.immutableMap(SecurityTokenDecoder.SECURITY_TOKEN_NAME, encrypted));
+ fail("should have reported that container was unknown");
+ } catch (SecurityTokenException e) {
+ assertTrue(e.getMessage(), e.getMessage().contains("Unknown container"));
+ }
+ }
+
+ @Test
+ public void testWrongContainer() throws Exception {
+ BlobCrypterSecurityToken t = new BlobCrypterSecurityToken(
+ getBlobCrypter(getContainerKey("container")), "container", null);
+ t.setAppUrl("http://www.example.com/gadget.xml");
+ t.setModuleId(12345L);
+ t.setOwnerId("owner");
+ t.setViewerId("viewer");
+ t.setTrustedJson("trusted");
+ String encrypted = t.encrypt();
+ encrypted = encrypted.replace("container:", "example:");
+
+ try {
+ decoder.createToken(Maps.immutableMap(SecurityTokenDecoder.SECURITY_TOKEN_NAME, encrypted));
+ fail("should have tried to decrypt with wrong key");
+ } catch (SecurityTokenException e) {
+ assertTrue(e.getMessage(), e.getMessage().contains("Invalid token signature"));
+ }
+ }
+
+ @Test
+ public void testExpired() throws Exception {
+ BlobCrypterSecurityToken t = new BlobCrypterSecurityToken(
+ getBlobCrypter(getContainerKey("container")), "container", null);
+ t.setAppUrl("http://www.example.com/gadget.xml");
+ t.setModuleId(12345L);
+ t.setOwnerId("owner");
+ t.setViewerId("viewer");
+ t.setTrustedJson("trusted");
+ String encrypted = t.encrypt();
+
+ timeSource.incrementSeconds(3600 + 181); // one hour plus clock skew
+ try {
+ decoder.createToken(Maps.immutableMap(SecurityTokenDecoder.SECURITY_TOKEN_NAME, encrypted));
+ fail("should have expired");
+ } catch (SecurityTokenException e) {
+ assertTrue(e.getMessage(), e.getMessage().contains("Blob expired"));
+ }
+ }
+
+ @Test
+ public void testMalformed() throws Exception {
+ try {
+ decoder.createToken(Maps.immutableMap(SecurityTokenDecoder.SECURITY_TOKEN_NAME, "foo"));
+ fail("should have tried to decrypt with wrong key");
+ } catch (SecurityTokenException e) {
+ assertTrue(e.getMessage(), e.getMessage().contains("Invalid security token foo"));
+ }
+ }
+
+ @Test
+ public void testAnonymous() throws Exception {
+ SecurityToken t = decoder.createToken(
+ Maps.immutableMap(SecurityTokenDecoder.SECURITY_TOKEN_NAME, " "));
+ assertTrue(t.isAnonymous());
+
+ Map<String, String> empty = Maps.immutableMap();
+ t = decoder.createToken(empty);
+ assertTrue(t.isAnonymous());
+ }
+
+ @Test
+ public void testLoadFailure() throws Exception {
+ ContainerConfig config = new ContainerConfig(null) {
+ @Override
+ public String get(String container, String name) {
+ if (BlobCrypterSecurityTokenDecoder.SECURITY_TOKEN_KEY_FILE.equals(name)) {
+ return getContainerKey(container);
+ }
+ if (BlobCrypterSecurityTokenDecoder.SIGNED_FETCH_DOMAIN.equals(name)) {
+ return container + ".com";
+ }
+ throw new RuntimeException("Mock not smart enough, unknown name " + name);
+ }
+
+ @Override
+ public Collection<String> getContainers() {
+ return Lists.newArrayList("container", "example", "failure");
+ }
+ };
+
+ try {
+ new DecoderWithLoadStubbedOut(config);
+ fail("Should have failed to load crypter");
+ } catch (RuntimeException e) {
+ assertTrue(e.getMessage(), e.getMessage().contains("Load failed"));
+ }
+ }
+}
Propchange: incubator/shindig/trunk/java/common/src/test/java/org/apache/shindig/auth/BlobCrypterSecurityTokenDecoderTest.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: incubator/shindig/trunk/java/common/src/test/java/org/apache/shindig/auth/BlobCrypterSecurityTokenTest.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/common/src/test/java/org/apache/shindig/auth/BlobCrypterSecurityTokenTest.java?rev=698410&view=auto
==============================================================================
--- incubator/shindig/trunk/java/common/src/test/java/org/apache/shindig/auth/BlobCrypterSecurityTokenTest.java (added)
+++ incubator/shindig/trunk/java/common/src/test/java/org/apache/shindig/auth/BlobCrypterSecurityTokenTest.java Tue Sep 23 18:10:30 2008
@@ -0,0 +1,104 @@
+/*
+ * 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.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.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 org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Tests BlobCrypterSecurityToken
+ */
+public class BlobCrypterSecurityTokenTest {
+
+ private static final String CONTAINER = "container";
+ private static final String DOMAIN = "example.com";
+
+ private FakeTimeSource timeSource = new FakeTimeSource();
+ private BasicBlobCrypter crypter;
+
+ @Before
+ public void setUp() {
+ crypter = new BasicBlobCrypter(Crypto.getRandomBytes(20));
+ crypter.timeSource = timeSource;
+ }
+
+ @Test
+ public void testNullValues() throws Exception {
+ BlobCrypterSecurityToken t = new BlobCrypterSecurityToken(crypter, CONTAINER, DOMAIN);
+ String token = t.encrypt();
+ assertTrue("should start with container: " + token, token.startsWith("container:"));
+ String[] fields = token.split(":");
+ BlobCrypterSecurityToken t2 =
+ BlobCrypterSecurityToken.decrypt(crypter, CONTAINER, DOMAIN, fields[1]);
+ assertNull(t2.getAppId(), t2.getAppId());
+ assertNull(t2.getAppUrl(), t2.getAppUrl());
+ assertEquals(DOMAIN, t2.getDomain());
+ assertEquals(0, t2.getModuleId());
+ assertNull(t2.getOwnerId(), t2.getOwnerId());
+ assertNull(t2.getViewerId(), t2.getViewerId());
+ assertNull(t2.getTrustedJson(), t2.getTrustedJson());
+ assertNull(t2.getUpdatedToken(), t2.getUpdatedToken());
+ }
+
+ @Test
+ public void testRealValues() throws Exception {
+ BlobCrypterSecurityToken t = new BlobCrypterSecurityToken(crypter, CONTAINER, DOMAIN);
+ t.setAppUrl("http://www.example.com/gadget.xml");
+ t.setModuleId(12345L);
+ t.setOwnerId("owner");
+ t.setViewerId("viewer");
+ t.setTrustedJson("trusted");
+ String token = t.encrypt();
+ assertTrue("should start with container: " + token, token.startsWith("container:"));
+ String[] fields = token.split(":");
+ BlobCrypterSecurityToken t2 =
+ BlobCrypterSecurityToken.decrypt(crypter, CONTAINER, DOMAIN, fields[1]);
+ assertEquals("http://www.example.com/gadget.xml", t2.getAppId());
+ assertEquals("http://www.example.com/gadget.xml", t2.getAppUrl());
+ assertEquals(DOMAIN, t2.getDomain());
+ assertEquals(12345L, t2.getModuleId());
+ assertEquals("owner", t2.getOwnerId());
+ assertEquals("viewer", t2.getViewerId());
+ assertEquals("trusted", t2.getTrustedJson());
+ }
+
+ @Test
+ public void testExpired() throws Exception {
+ BlobCrypterSecurityToken t = new BlobCrypterSecurityToken(crypter, CONTAINER, DOMAIN);
+ String token = t.encrypt();
+ // one hour plus clock skew
+ timeSource.incrementSeconds(3600 + 181);
+ String[] fields = token.split(":");
+ try {
+ BlobCrypterSecurityToken.decrypt(crypter, CONTAINER, DOMAIN, fields[1]);
+ fail("Token should have expired");
+ } catch (BlobExpiredException e) {
+ // good
+ }
+ }
+}
Propchange: incubator/shindig/trunk/java/common/src/test/java/org/apache/shindig/auth/BlobCrypterSecurityTokenTest.java
------------------------------------------------------------------------------
svn:eol-style = native