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 2012/04/16 23:30:49 UTC

svn commit: r1326805 - in /shindig/trunk: config/ content/samplecontainer/examples/oauth2/ java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/ java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/persistence/ java/gadgets/src/main/jav...

Author: rbaxter85
Date: Mon Apr 16 21:30:49 2012
New Revision: 1326805

URL: http://svn.apache.org/viewvc?rev=1326805&view=rev
Log:
SHINDIG-1731
Committed For Adam Clarke
Share OAuth2Token for a user across multiple gadgets

Added:
    shindig/trunk/content/samplecontainer/examples/oauth2/oauth2_google_shared1.xml   (with props)
    shindig/trunk/content/samplecontainer/examples/oauth2/oauth2_google_shared2.xml   (with props)
Modified:
    shindig/trunk/config/oauth2.json
    shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/BasicOAuth2Store.java
    shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/OAuth2Message.java
    shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/persistence/OAuth2Client.java
    shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/persistence/sample/JSONOAuth2Persister.java
    shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/oauth2/persistence/OAuth2ClientTest.java

Modified: shindig/trunk/config/oauth2.json
URL: http://svn.apache.org/viewvc/shindig/trunk/config/oauth2.json?rev=1326805&r1=1326804&r2=1326805&view=diff
==============================================================================
--- shindig/trunk/config/oauth2.json (original)
+++ shindig/trunk/config/oauth2.json Mon Apr 16 21:30:49 2012
@@ -28,7 +28,7 @@
  * to attain the information necessary to complete the OAuth 2.0 request       *
  *                                                                             *
  *                                                                             *
- ******************************************************************************* 
+ *******************************************************************************
 */
 {
    "gadgetBindings" : {
@@ -38,6 +38,18 @@
             "allowModuleOverride" : "true"
          }
       },
+      "%origin%%contextRoot%/samplecontainer/examples/oauth2/oauth2_google_shared1.xml" : {
+         "googleAPI" : {
+            "clientName"          : "googleApi_shared_client",
+            "allowModuleOverride" : "true"
+         }
+      },
+      "%origin%%contextRoot%/samplecontainer/examples/oauth2/oauth2_google_shared2.xml" : {
+         "googleAPI" : {
+            "clientName"          : "googleApi_shared_client",
+            "allowModuleOverride" : "true"
+         }
+      },
       "%origin%%contextRoot%/samplecontainer/examples/oauth2/oauth2_facebook.xml" : {
           "facebook" : {
              "clientName"          : "facebook_client1",
@@ -62,8 +74,7 @@
             "allowModuleOverride" : "true"
           }
       }
-   },   
-   
+   },
    "clients" : {
       "googleApi_client1" : {
          "providerName"  : "googleAPI",
@@ -71,9 +82,18 @@
          "type"          : "confidential",
          "grant_type"    : "code",
          "client_id"     : "YOUR_GOOGLE_APP_ID",
-         "client_secret" : "YOUR_GOOGLE_APP_SECRET"
+         "client_secret" : "YOUR_GOOGLE_APP_SECRET",
+         "sharedToken"   : "false"
+      },
+      "googleApi_shared_client" : {
+         "providerName"  : "googleAPI",
+         "redirect_uri"  : "%origin%%contextRoot%/gadgets/oauth2callback",
+         "type"          : "confidential",
+         "grant_type"    : "code",
+         "client_id"     : "YOUR_GOOGLE_APP_ID",
+         "client_secret" : "YOUR_GOOGLE_APP_SECRET",
+         "sharedToken"   : "true"
       },
-      
       "facebook_client1" : {
          "providerName"  : "facebook",
          "redirect_uri"  : "%origin%%contextRoot%/gadgets/oauth2callback",
@@ -82,7 +102,6 @@
          "client_id"     : "YOUR_FACEBOOK_APP_ID",
          "client_secret" : "YOUR_FACEBOOK_APP_SECRET"
       },
-
       "wl_client1" : {
          "providerName"  : "wlProvider",
          "type"          : "confidential",
@@ -104,31 +123,27 @@
          "grant_type"    : "code",
          "client_id"     : "testClientCredentialsClient",
          "client_secret" : "clientCredentialsClient_secret"
-      }            
-      
+      }
    },
-   
    "providers" : {
       "googleAPI" : {
-        "client_authentication" : "STANDARD",   
-        "usesAuthorizationHeader" : "false",    
+        "client_authentication" : "STANDARD",
+        "usesAuthorizationHeader" : "false",
         "usesUrlParameter" : "true",
         "endpoints" : {
             "authorizationUrl"  : "https://accounts.google.com/o/oauth2/auth",
             "tokenUrl"          : "https://accounts.google.com/o/oauth2/token"
         }
       },
-      
       "facebook" : {
          "client_authentication" : "STANDARD",
         "usesAuthorizationHeader" : "false",
-        "usesUrlParameter" : "true",       
+        "usesUrlParameter" : "true",
         "endpoints" : {
             "authorizationUrl"   : "https://www.facebook.com/dialog/oauth",
             "tokenUrl"           : "https://graph.facebook.com/oauth/access_token"
         }
       },
-      
       "wlProvider" : {
          "client_authentication" : "STANDARD",
          "usesAuthorizationHeader" : "false",
@@ -138,7 +153,6 @@
             "tokenUrl"           : "https://oauth.live.com/token"
          }
       },
-  
       "shindigOAuth2Provider" : {
          "client_authentication" : "Basic",
          "usesAuthorizationHeader" : "true",

Added: shindig/trunk/content/samplecontainer/examples/oauth2/oauth2_google_shared1.xml
URL: http://svn.apache.org/viewvc/shindig/trunk/content/samplecontainer/examples/oauth2/oauth2_google_shared1.xml?rev=1326805&view=auto
==============================================================================
--- shindig/trunk/content/samplecontainer/examples/oauth2/oauth2_google_shared1.xml (added)
+++ shindig/trunk/content/samplecontainer/examples/oauth2/oauth2_google_shared1.xml Mon Apr 16 21:30:49 2012
@@ -0,0 +1,130 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+ * 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.
+-->
+<Module>
+  <ModulePrefs title="Demo OAuth2 Authorization Code Gadget, uses sharedToken (1)">
+    <OAuth2>
+      <Service name="googleAPI" scope="https://www.google.com/m8/feeds/">
+      </Service>
+    </OAuth2>
+    <Require feature="oauthpopup" />
+  </ModulePrefs>
+  <Content type="html">
+      <![CDATA[
+
+    <style>
+    #main {
+        margin: 0px;
+        padding: 0px;
+        font-size: small;
+    }
+    </style>
+
+    <div id="main" style="display: none">
+    </div>
+
+    <div id="approval" style="display: none">
+      <a href="#" id="personalize">Personalize this gadget</a>
+      <ol>
+        <b><u>In order to use this Demo Gadget you must</u></b>
+        <li>Have or create a Google account and know your userid and password</li>
+        <li>Register a new application at <a href="https://code.google.com/apis/console">https://code.google.com/apis/console</a></li>
+        <li>Make sure your app's "Redirect URIs" applies to your shindig environment (e.g. http://localhost:8080/gadgets/oauth2callback)</li>
+        <li>Update the Google client "Client ID" and "Client Secret" in the OAuth2 persistence (default is <code>config/oauth2.json</code>)</li>
+        <li>Restart the server</li>
+        <li>Click the link above to initiate the authorization process</li>
+      </ol>
+    </div>
+
+    <div id="waiting" style="display: none">
+      Please click
+      <a href="#" id="approvaldone">I've approved access</a>
+      once you've approved access to your data.
+    </div>
+
+    <div id="error" style="display: none;background-color:yellow;font-size:xx-small;" title="An error occured processing your request">
+       <div id="error_code"><u>code:</u></div>
+       <div id="error_uri"><u>uri:</u></div>
+       <div id="error_description"><u>description:</u></div>
+       <div id="error_explanation"><u>explanation:</u></div>
+       <div id="error_trace"><u>trace:</u></div>
+    </div>
+
+    <script type="text/javascript">
+      function getElement(x) {
+        return document.getElementById(x);
+      }
+
+      function showOneSection(toshow) {
+        var sections = [ 'main', 'approval', 'waiting', 'error' ];
+        for (var i=0; i < sections.length; ++i) {
+          var s = sections[i];
+          var el = getElement(s);
+          if (s === toshow) {
+            el.style.display = "block";
+          } else {
+            el.style.display = "none";
+          }
+        }
+      }
+
+      function fetchData() {
+        url = "https://www.google.com/m8/feeds/contacts/default/full";
+        var params = {};
+        params[gadgets.io.RequestParameters.CONTENT_TYPE] =
+          gadgets.io.ContentType.TEXT;
+        params[gadgets.io.RequestParameters.AUTHORIZATION] =
+          gadgets.io.AuthorizationType.OAUTH2;
+        params[gadgets.io.RequestParameters.METHOD] =
+          gadgets.io.MethodType.GET;
+        params[gadgets.io.RequestParameters.OAUTH_SERVICE_NAME] = "googleAPI";
+        params[gadgets.io.RequestParameters.REFRESH_INTERVAL] = "0";
+
+        gadgets.io.makeRequest(url, function (response) {
+          if (response.oauthApprovalUrl) {
+            var onOpen = function() {
+              showOneSection('waiting');
+            };
+            var onClose = function() {
+              fetchData();
+            };
+            var popup = new gadgets.oauth.Popup(response.oauthApprovalUrl,
+                null, onOpen, onClose);
+            getElement('personalize').onclick = popup.createOpenerOnClick();
+            getElement('approvaldone').onclick = popup.createApprovedOnClick();
+            showOneSection('approval');
+          } else if (response.data) {
+            getElement('main').appendChild(document.createTextNode(response.data));
+            showOneSection('main');
+          } else {
+             getElement('error_code').appendChild(document.createTextNode(response.oauthError));
+             getElement('error_uri').appendChild(document.createTextNode(response.oauthErrorUri));
+             getElement('error_description').appendChild(document.createTextNode(response.oauthErrorText));
+             getElement('error_explanation').appendChild(document.createTextNode(response.oauthErrorExplanation));
+             getElement('error_trace').appendChild(document.createTextNode(response.oauthErrorTrace));
+            showOneSection('error');
+          }
+        }, params);
+      }
+
+      gadgets.util.registerOnLoadHandler(fetchData);
+    </script>
+        ]]>
+  </Content>
+</Module>
\ No newline at end of file

Propchange: shindig/trunk/content/samplecontainer/examples/oauth2/oauth2_google_shared1.xml
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: shindig/trunk/content/samplecontainer/examples/oauth2/oauth2_google_shared2.xml
URL: http://svn.apache.org/viewvc/shindig/trunk/content/samplecontainer/examples/oauth2/oauth2_google_shared2.xml?rev=1326805&view=auto
==============================================================================
--- shindig/trunk/content/samplecontainer/examples/oauth2/oauth2_google_shared2.xml (added)
+++ shindig/trunk/content/samplecontainer/examples/oauth2/oauth2_google_shared2.xml Mon Apr 16 21:30:49 2012
@@ -0,0 +1,130 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+ * 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.
+-->
+<Module>
+  <ModulePrefs title="Demo OAuth2 Authorization Code Gadget, uses sharedToken (2)">
+    <OAuth2>
+      <Service name="googleAPI" scope="https://www.google.com/m8/feeds/">
+      </Service>
+    </OAuth2>
+    <Require feature="oauthpopup" />
+  </ModulePrefs>
+  <Content type="html">
+      <![CDATA[
+
+    <style>
+    #main {
+        margin: 0px;
+        padding: 0px;
+        font-size: small;
+    }
+    </style>
+
+    <div id="main" style="display: none">
+    </div>
+
+    <div id="approval" style="display: none">
+      <a href="#" id="personalize">Personalize this gadget</a>
+      <ol>
+        <b><u>In order to use this Demo Gadget you must</u></b>
+        <li>Have or create a Google account and know your userid and password</li>
+        <li>Register a new application at <a href="https://code.google.com/apis/console">https://code.google.com/apis/console</a></li>
+        <li>Make sure your app's "Redirect URIs" applies to your shindig environment (e.g. http://localhost:8080/gadgets/oauth2callback)</li>
+        <li>Update the Google client "Client ID" and "Client Secret" in the OAuth2 persistence (default is <code>config/oauth2.json</code>)</li>
+        <li>Restart the server</li>
+        <li>Click the link above to initiate the authorization process</li>
+      </ol>
+    </div>
+
+    <div id="waiting" style="display: none">
+      Please click
+      <a href="#" id="approvaldone">I've approved access</a>
+      once you've approved access to your data.
+    </div>
+
+    <div id="error" style="display: none;background-color:yellow;font-size:xx-small;" title="An error occured processing your request">
+       <div id="error_code"><u>code:</u></div>
+       <div id="error_uri"><u>uri:</u></div>
+       <div id="error_description"><u>description:</u></div>
+       <div id="error_explanation"><u>explanation:</u></div>
+       <div id="error_trace"><u>trace:</u></div>
+    </div>
+
+    <script type="text/javascript">
+      function getElement(x) {
+        return document.getElementById(x);
+      }
+
+      function showOneSection(toshow) {
+        var sections = [ 'main', 'approval', 'waiting', 'error' ];
+        for (var i=0; i < sections.length; ++i) {
+          var s = sections[i];
+          var el = getElement(s);
+          if (s === toshow) {
+            el.style.display = "block";
+          } else {
+            el.style.display = "none";
+          }
+        }
+      }
+
+      function fetchData() {
+        url = "https://www.google.com/m8/feeds/contacts/default/full";
+        var params = {};
+        params[gadgets.io.RequestParameters.CONTENT_TYPE] =
+          gadgets.io.ContentType.TEXT;
+        params[gadgets.io.RequestParameters.AUTHORIZATION] =
+          gadgets.io.AuthorizationType.OAUTH2;
+        params[gadgets.io.RequestParameters.METHOD] =
+          gadgets.io.MethodType.GET;
+        params[gadgets.io.RequestParameters.OAUTH_SERVICE_NAME] = "googleAPI";
+        params[gadgets.io.RequestParameters.REFRESH_INTERVAL] = "0";
+
+        gadgets.io.makeRequest(url, function (response) {
+          if (response.oauthApprovalUrl) {
+            var onOpen = function() {
+              showOneSection('waiting');
+            };
+            var onClose = function() {
+              fetchData();
+            };
+            var popup = new gadgets.oauth.Popup(response.oauthApprovalUrl,
+                null, onOpen, onClose);
+            getElement('personalize').onclick = popup.createOpenerOnClick();
+            getElement('approvaldone').onclick = popup.createApprovedOnClick();
+            showOneSection('approval');
+          } else if (response.data) {
+            getElement('main').appendChild(document.createTextNode(response.data));
+            showOneSection('main');
+          } else {
+             getElement('error_code').appendChild(document.createTextNode(response.oauthError));
+             getElement('error_uri').appendChild(document.createTextNode(response.oauthErrorUri));
+             getElement('error_description').appendChild(document.createTextNode(response.oauthErrorText));
+             getElement('error_explanation').appendChild(document.createTextNode(response.oauthErrorExplanation));
+             getElement('error_trace').appendChild(document.createTextNode(response.oauthErrorTrace));
+            showOneSection('error');
+          }
+        }, params);
+      }
+
+      gadgets.util.registerOnLoadHandler(fetchData);
+    </script>
+        ]]>
+  </Content>
+</Module>
\ No newline at end of file

Propchange: shindig/trunk/content/samplecontainer/examples/oauth2/oauth2_google_shared2.xml
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/BasicOAuth2Store.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/BasicOAuth2Store.java?rev=1326805&r1=1326804&r2=1326805&view=diff
==============================================================================
--- shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/BasicOAuth2Store.java (original)
+++ shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/BasicOAuth2Store.java Mon Apr 16 21:30:49 2012
@@ -1,22 +1,24 @@
 /*
- * 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
+ * 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
+ *   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.
+ * 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.oauth2;
 
-import java.util.Set;
+import com.google.inject.Inject;
 
 import org.apache.shindig.gadgets.GadgetException;
 import org.apache.shindig.gadgets.GadgetException.Code;
@@ -24,11 +26,10 @@ import org.apache.shindig.gadgets.oauth2
 import org.apache.shindig.gadgets.oauth2.persistence.OAuth2Cache;
 import org.apache.shindig.gadgets.oauth2.persistence.OAuth2CacheException;
 import org.apache.shindig.gadgets.oauth2.persistence.OAuth2Client;
-import org.apache.shindig.gadgets.oauth2.persistence.OAuth2Encrypter;
 import org.apache.shindig.gadgets.oauth2.persistence.OAuth2PersistenceException;
 import org.apache.shindig.gadgets.oauth2.persistence.OAuth2Persister;
 
-import com.google.inject.Inject;
+import java.util.Set;
 
 /**
  * see {@link OAuth2Store}
@@ -43,7 +44,7 @@ import com.google.inject.Inject;
 public class BasicOAuth2Store implements OAuth2Store {
   private final static String LOG_CLASS = BasicOAuth2Store.class.getName();
   private static final FilteredLogger LOG = FilteredLogger
-      .getFilteredLogger(BasicOAuth2Store.LOG_CLASS);
+          .getFilteredLogger(BasicOAuth2Store.LOG_CLASS);
 
   private final OAuth2Cache cache;
   private final String globalRedirectUri;
@@ -51,7 +52,7 @@ public class BasicOAuth2Store implements
 
   @Inject
   public BasicOAuth2Store(final OAuth2Cache cache, final OAuth2Persister persister,
-      final String globalRedirectUri) {
+          final String globalRedirectUri) {
     this.cache = cache;
     this.persister = persister;
     this.globalRedirectUri = globalRedirectUri;
@@ -101,11 +102,11 @@ public class BasicOAuth2Store implements
   }
 
   public OAuth2Client getClient(final String gadgetUri, final String serviceName)
-      throws GadgetException {
+          throws GadgetException {
     final boolean isLogging = BasicOAuth2Store.LOG.isLoggable();
     if (isLogging) {
       BasicOAuth2Store.LOG.entering(BasicOAuth2Store.LOG_CLASS, "getClient", new Object[] {
-          gadgetUri, serviceName });
+              gadgetUri, serviceName });
     }
 
     final Integer index = this.cache.getClientIndex(gadgetUri, serviceName);
@@ -131,7 +132,7 @@ public class BasicOAuth2Store implements
           BasicOAuth2Store.LOG.log("Error loading OAuth2 client ", e);
         }
         throw new GadgetException(Code.OAUTH_STORAGE_ERROR, "Error loading OAuth2 client "
-            + serviceName, e);
+                + serviceName, e);
       }
     }
 
@@ -158,11 +159,11 @@ public class BasicOAuth2Store implements
   }
 
   public OAuth2Accessor getOAuth2Accessor(final String gadgetUri, final String serviceName,
-      final String user, final String scope) throws GadgetException {
+          final String user, final String scope) throws GadgetException {
     final boolean isLogging = BasicOAuth2Store.LOG.isLoggable();
     if (isLogging) {
       BasicOAuth2Store.LOG.entering(BasicOAuth2Store.LOG_CLASS, "getOAuth2Accessor", new Object[] {
-          gadgetUri, serviceName, user, scope });
+              gadgetUri, serviceName, user, scope });
     }
 
     final Integer index = this.cache.getOAuth2AccessorIndex(gadgetUri, serviceName, user, scope);
@@ -174,12 +175,12 @@ public class BasicOAuth2Store implements
 
       if (client != null) {
         final OAuth2Token accessToken = this.getToken(gadgetUri, serviceName, user, scope,
-            OAuth2Token.Type.ACCESS);
+                OAuth2Token.Type.ACCESS);
         final OAuth2Token refreshToken = this.getToken(gadgetUri, serviceName, user, scope,
-            OAuth2Token.Type.REFRESH);
+                OAuth2Token.Type.REFRESH);
 
         final BasicOAuth2Accessor newAccessor = new BasicOAuth2Accessor(gadgetUri, serviceName,
-            user, scope, client.isAllowModuleOverride(), this, this.globalRedirectUri);
+                user, scope, client.isAllowModuleOverride(), this, this.globalRedirectUri);
         newAccessor.setAccessToken(accessToken);
         newAccessor.setAuthorizationUrl(client.getAuthorizationUrl());
         newAccessor.setClientAuthenticationType(client.getClientAuthenticationType());
@@ -206,30 +207,33 @@ public class BasicOAuth2Store implements
   }
 
   public Integer getOAuth2AccessorIndex(final String gadgetUri, final String serviceName,
-      final String user, final String scope) {
+          final String user, final String scope) {
     return this.cache.getOAuth2AccessorIndex(gadgetUri, serviceName, user, scope);
   }
 
   public OAuth2Token getToken(final String gadgetUri, final String serviceName, final String user,
-      final String scope, final OAuth2Token.Type type) throws GadgetException {
+          final String scope, final OAuth2Token.Type type) throws GadgetException {
 
     final boolean isLogging = BasicOAuth2Store.LOG.isLoggable();
     if (isLogging) {
       BasicOAuth2Store.LOG.entering(BasicOAuth2Store.LOG_CLASS, "getToken", new Object[] {
-          gadgetUri, serviceName, user, scope, type });
+              gadgetUri, serviceName, user, scope, type });
     }
 
-    final Integer index = this.cache.getTokenIndex(gadgetUri, serviceName, user, scope, type);
+    final String processedGadgetUri = this.getGadgetUri(gadgetUri, serviceName);
+
+    final Integer index = this.cache.getTokenIndex(processedGadgetUri, serviceName, user, scope,
+            type);
     OAuth2Token token = this.cache.getToken(index);
     if (token == null) {
       try {
-        token = this.persister.findToken(gadgetUri, serviceName, user, scope, type);
+        token = this.persister.findToken(processedGadgetUri, serviceName, user, scope, type);
         if (token != null) {
           this.cache.storeToken(token);
         }
       } catch (final OAuth2PersistenceException e) {
         throw new GadgetException(Code.OAUTH_STORAGE_ERROR, "Error loading OAuth2 token " + index,
-            e);
+                e);
       }
     }
 
@@ -285,7 +289,7 @@ public class BasicOAuth2Store implements
 
     if (accessor != null) {
       final Integer index = this.cache.getOAuth2AccessorIndex(accessor.getGadgetUri(),
-          accessor.getServiceName(), accessor.getUser(), accessor.getScope());
+              accessor.getServiceName(), accessor.getUser(), accessor.getScope());
       return this.cache.removeOAuth2Accessor(index);
     }
 
@@ -308,7 +312,7 @@ public class BasicOAuth2Store implements
       }
 
       return this.removeToken(token.getGadgetUri(), token.getServiceName(), token.getUser(),
-          token.getScope(), token.getType());
+              token.getScope(), token.getType());
     }
 
     if (isLogging) {
@@ -319,19 +323,23 @@ public class BasicOAuth2Store implements
   }
 
   public OAuth2Token removeToken(final String gadgetUri, final String serviceName,
-      final String user, final String scope, final OAuth2Token.Type type) throws GadgetException {
+          final String user, final String scope, final OAuth2Token.Type type)
+          throws GadgetException {
 
     final boolean isLogging = BasicOAuth2Store.LOG.isLoggable();
     if (isLogging) {
       BasicOAuth2Store.LOG.entering(BasicOAuth2Store.LOG_CLASS, "removeToken", new Object[] {
-          gadgetUri, serviceName, user, scope, type });
+              gadgetUri, serviceName, user, scope, type });
     }
 
-    final Integer index = this.cache.getTokenIndex(gadgetUri, serviceName, user, scope, type);
+    final String processedGadgetUri = this.getGadgetUri(gadgetUri, serviceName);
+
+    final Integer index = this.cache.getTokenIndex(processedGadgetUri, serviceName, user, scope,
+            type);
     try {
       final OAuth2Token token = this.cache.removeToken(index);
       if (token != null) {
-        this.persister.removeToken(gadgetUri, serviceName, user, scope, type);
+        this.persister.removeToken(processedGadgetUri, serviceName, user, scope, type);
       }
 
       if (isLogging) {
@@ -344,15 +352,15 @@ public class BasicOAuth2Store implements
         BasicOAuth2Store.LOG.log("Error loading OAuth2 token ", e);
       }
       throw new GadgetException(Code.OAUTH_STORAGE_ERROR, "Error loading OAuth2 token "
-          + serviceName, e);
+              + serviceName, e);
     }
   }
 
   public static boolean runImport(final OAuth2Persister source, final OAuth2Persister target,
-      final boolean clean) {
+          final boolean clean) {
     if (BasicOAuth2Store.LOG.isLoggable()) {
       BasicOAuth2Store.LOG.entering(BasicOAuth2Store.LOG_CLASS, "runImport", new Object[] { source,
-          target, clean });
+              target, clean });
     }
 
     // No import for default persistence
@@ -366,9 +374,16 @@ public class BasicOAuth2Store implements
     }
 
     if (token != null) {
+      final String gadgetUri = token.getGadgetUri();
+      final String serviceName = token.getServiceName();
+
+      final String processedGadgetUri = this.getGadgetUri(gadgetUri, serviceName);
+
+      token.setGadgetUri(processedGadgetUri);
+
       final Integer index = this.cache.getTokenIndex(token);
-      final OAuth2Token existingToken = this.getToken(token.getGadgetUri(), token.getServiceName(),
-          token.getUser(), token.getScope(), token.getType());
+      final OAuth2Token existingToken = this.getToken(processedGadgetUri, token.getServiceName(),
+              token.getUser(), token.getScope(), token.getType());
       try {
         if (existingToken == null) {
           this.persister.insertToken(token);
@@ -382,13 +397,13 @@ public class BasicOAuth2Store implements
           BasicOAuth2Store.LOG.log("Error storing OAuth2 token " + index, e);
         }
         throw new GadgetException(Code.OAUTH_STORAGE_ERROR, "Error storing OAuth2 token " + index,
-            e);
+                e);
       } catch (final OAuth2PersistenceException e) {
         if (isLogging) {
           BasicOAuth2Store.LOG.log("Error storing OAuth2 token " + index, e);
         }
         throw new GadgetException(Code.OAUTH_STORAGE_ERROR, "Error storing OAuth2 token " + index,
-            e);
+                e);
       }
     }
 
@@ -409,4 +424,17 @@ public class BasicOAuth2Store implements
       BasicOAuth2Store.LOG.exiting(BasicOAuth2Store.LOG_CLASS, "storeOAuth2Accessor");
     }
   }
+
+  protected String getGadgetUri(final String gadgetUri, final String serviceName)
+          throws GadgetException {
+    String ret = gadgetUri;
+    final OAuth2Client client = this.getClient(ret, serviceName);
+    if (client != null) {
+      if (client.isSharedToken()) {
+        ret = client.getClientId() + ':' + client.getServiceName();
+      }
+    }
+
+    return ret;
+  }
 }

Modified: shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/OAuth2Message.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/OAuth2Message.java?rev=1326805&r1=1326804&r2=1326805&view=diff
==============================================================================
--- shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/OAuth2Message.java (original)
+++ shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/OAuth2Message.java Mon Apr 16 21:30:49 2012
@@ -71,6 +71,7 @@ public interface OAuth2Message {
   public final static String RESPONSE_TYPE = "response_type";
   public final static String SCOPE = "scope";
   public final static String SERVER_ERROR = "server_error";
+  public final static String SHARED_TOKEN = "sharedToken";
   public final static String STANDARD_AUTH_TYPE = "STANDARD";
   public final static String STATE = "state";
   public final static String TEMPORARILY_UNAVAILABLE = "temporarily_unavailable";

Modified: shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/persistence/OAuth2Client.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/persistence/OAuth2Client.java?rev=1326805&r1=1326804&r2=1326805&view=diff
==============================================================================
--- shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/persistence/OAuth2Client.java (original)
+++ shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/persistence/OAuth2Client.java Mon Apr 16 21:30:49 2012
@@ -48,6 +48,7 @@ public class OAuth2Client implements Ser
   private String tokenUrl;
   private OAuth2Accessor.Type type = OAuth2Accessor.Type.UNKNOWN;
   private boolean urlParameter;
+  private boolean sharedToken = false;
 
   @Inject
   public OAuth2Client(final OAuth2Encrypter encrypter) {
@@ -77,6 +78,9 @@ public class OAuth2Client implements Ser
     } else if (!this.serviceName.equals(other.serviceName)) {
       return false;
     }
+    if (this.sharedToken != other.sharedToken) {
+      return false;
+    }
     return true;
   }
 
@@ -170,6 +174,10 @@ public class OAuth2Client implements Ser
     return this.authorizationHeader;
   }
 
+  public boolean isSharedToken() {
+    return this.sharedToken;
+  }
+
   public boolean isUrlParameter() {
     return this.urlParameter;
   }
@@ -220,6 +228,10 @@ public class OAuth2Client implements Ser
     this.serviceName = serviceName;
   }
 
+  public void setSharedToken(final boolean sharedToken) {
+    this.sharedToken = sharedToken;
+  }
+
   public void setTokenUrl(final String tokenUrl) {
     this.tokenUrl = tokenUrl;
   }
@@ -239,6 +251,31 @@ public class OAuth2Client implements Ser
         + this.gadgetUri + " , clientId = " + this.clientId + " , grantType = " + this.grantType
         + " , type = " + this.type.name() + " , grantType = " + this.grantType + " , tokenUrl = "
         + this.tokenUrl + " , authorizationUrl = " + this.authorizationUrl
-        + " , this.clientAuthenticationType = " + this.clientAuthenticationType;
+        + " , this.clientAuthenticationType = " + this.clientAuthenticationType
+        + " , this.sharedToken = " + this.sharedToken;
+  }
+
+  @Override
+  public OAuth2Client clone() {
+    final OAuth2Client ret = new OAuth2Client(this.encrypter);
+    ret.setAllowModuleOverride(this.allowModuleOverride);
+    ret.setAuthorizationHeader(this.authorizationHeader);
+    ret.setAuthorizationUrl(authorizationUrl);
+    ret.setClientAuthenticationType(this.clientAuthenticationType);
+    ret.setClientId(this.clientId);
+    try {
+    ret.setClientSecret(this.clientSecret);
+      } catch (OAuth2EncryptionException e) {
+    }
+    ret.setGadgetUri(this.gadgetUri);
+    ret.setGrantType(this.grantType);
+    ret.setRedirectUri(this.redirectUri);
+    ret.setServiceName(this.serviceName);
+    ret.setSharedToken(this.sharedToken);
+    ret.setTokenUrl(this.tokenUrl);
+    ret.setType(this.type);
+    ret.setUrlParameter(this.urlParameter);
+
+    return ret;
   }
 }

Modified: shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/persistence/sample/JSONOAuth2Persister.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/persistence/sample/JSONOAuth2Persister.java?rev=1326805&r1=1326804&r2=1326805&view=diff
==============================================================================
--- shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/persistence/sample/JSONOAuth2Persister.java (original)
+++ shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/persistence/sample/JSONOAuth2Persister.java Mon Apr 16 21:30:49 2012
@@ -1,27 +1,27 @@
 /*
- * 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
+ * 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
+ *   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.
+ * 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.oauth2.persistence.sample;
 
-import java.io.IOException;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Set;
+import com.google.caja.util.Maps;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+import com.google.inject.name.Named;
 
 import org.apache.shindig.common.Nullable;
 import org.apache.shindig.common.servlet.Authority;
@@ -37,17 +37,19 @@ import org.apache.shindig.gadgets.oauth2
 import org.apache.shindig.gadgets.oauth2.persistence.OAuth2PersistenceException;
 import org.apache.shindig.gadgets.oauth2.persistence.OAuth2Persister;
 import org.apache.shindig.gadgets.oauth2.persistence.OAuth2TokenPersistence;
+
 import org.json.JSONException;
 import org.json.JSONObject;
 
-import com.google.caja.util.Maps;
-import com.google.inject.Inject;
-import com.google.inject.Singleton;
-import com.google.inject.name.Named;
+import java.io.IOException;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
 
 /**
- * Persistence implementation that reads <code>config/oauth2.json</code> on
- * startup
+ * Persistence implementation that reads <code>config/oauth2.json</code> on startup
  *
  */
 @Singleton
@@ -77,20 +79,20 @@ public class JSONOAuth2Persister impleme
 
   private final static String LOG_CLASS = JSONOAuth2Persister.class.getName();
   private static final FilteredLogger LOG = FilteredLogger
-      .getFilteredLogger(JSONOAuth2Persister.LOG_CLASS);
+          .getFilteredLogger(JSONOAuth2Persister.LOG_CLASS);
 
   @Inject
   public JSONOAuth2Persister(final OAuth2Encrypter encrypter, final Authority authority,
-      final String globalRedirectUri,
-      @Nullable @Named("shindig.contextroot") final String contextRoot)
-      throws OAuth2PersistenceException {
+          final String globalRedirectUri, @Nullable
+          @Named("shindig.contextroot")
+          final String contextRoot) throws OAuth2PersistenceException {
     this.encrypter = encrypter;
     this.authority = authority;
     this.globalRedirectUri = globalRedirectUri;
     this.contextRoot = contextRoot;
     try {
       this.configFile = new JSONObject(
-          JSONOAuth2Persister.getJSONString(JSONOAuth2Persister.OAUTH2_CONFIG));
+              JSONOAuth2Persister.getJSONString(JSONOAuth2Persister.OAUTH2_CONFIG));
     } catch (final Exception e) {
       if (JSONOAuth2Persister.LOG.isLoggable()) {
         JSONOAuth2Persister.LOG.log("OAuth2PersistenceException", e);
@@ -100,8 +102,9 @@ public class JSONOAuth2Persister impleme
   }
 
   public JSONOAuth2Persister(final OAuth2Encrypter encrypter, final Authority authority,
-      final String globalRedirectUri,
-      @Nullable @Named("shindig.contextroot") final String contextRoot, final JSONObject configFile) {
+          final String globalRedirectUri, @Nullable
+          @Named("shindig.contextroot")
+          final String contextRoot, final JSONObject configFile) {
     this.encrypter = encrypter;
     this.authority = authority;
     this.globalRedirectUri = globalRedirectUri;
@@ -113,29 +116,34 @@ public class JSONOAuth2Persister impleme
     return new OAuth2TokenPersistence(this.encrypter);
   }
 
-  public static OAuth2Client findClient(@SuppressWarnings("unused") final Integer index) {
+  public static OAuth2Client findClient(@SuppressWarnings("unused")
+  final Integer index) {
     return null;
   }
 
   public OAuth2Client findClient(final String providerName, final String gadgetUri)
-      throws OAuth2PersistenceException {
+          throws OAuth2PersistenceException {
     return null;
   }
 
-  public static OAuth2Provider findProvider(@SuppressWarnings("unused") final Integer index) {
+  public static OAuth2Provider findProvider(@SuppressWarnings("unused")
+  final Integer index) {
     return null;
   }
 
-  public static OAuth2Provider findProvider(@SuppressWarnings("unused") final String providerName) {
+  public static OAuth2Provider findProvider(@SuppressWarnings("unused")
+  final String providerName) {
     return null;
   }
 
-  public static OAuth2Token findToken(@SuppressWarnings("unused") final Integer index) {
+  public static OAuth2Token findToken(@SuppressWarnings("unused")
+  final Integer index) {
     return null;
   }
 
   public OAuth2Token findToken(final String providerName, final String gadgetUri,
-      final String user, final String scope, final Type type) throws OAuth2PersistenceException {
+          final String user, final String scope, final Type type)
+                  throws OAuth2PersistenceException {
     return null;
   }
 
@@ -173,6 +181,10 @@ public class JSONOAuth2Persister impleme
         final String clientId = settings.getString(OAuth2Message.CLIENT_ID);
         final String typeS = settings.optString(JSONOAuth2Persister.TYPE, null);
         String grantType = settings.optString(OAuth2Message.GRANT_TYPE, null);
+        final String sharedToken = settings.optString(OAuth2Message.SHARED_TOKEN, "false");
+        if ("true".equalsIgnoreCase(sharedToken)) {
+          client.setSharedToken(true);
+        }
 
         try {
           client.setEncryptedSecret(secret.getBytes("UTF-8"));
@@ -216,7 +228,8 @@ public class JSONOAuth2Persister impleme
     final Set<OAuth2Client> ret = new HashSet<OAuth2Client>(gadgetBindings.size());
     for (final OAuth2GadgetBinding binding : gadgetBindings.values()) {
       final String clientName = binding.getClientName();
-      final OAuth2Client client = internalMap.get(clientName);
+      final OAuth2Client cachedClient = internalMap.get(clientName);
+      final OAuth2Client client = cachedClient.clone();
       client.setGadgetUri(binding.getGadgetUri());
       client.setServiceName(binding.getGadgetServiceName());
       client.setAllowModuleOverride(binding.isAllowOverride());
@@ -231,7 +244,7 @@ public class JSONOAuth2Persister impleme
 
     try {
       final JSONObject bindings = this.configFile
-          .getJSONObject(JSONOAuth2Persister.GADGET_BINDGINGS);
+              .getJSONObject(JSONOAuth2Persister.GADGET_BINDGINGS);
       for (final Iterator<?> i = bindings.keys(); i.hasNext();) {
         final String gadgetUriS = (String) i.next();
         String gadgetUri = null;
@@ -247,12 +260,12 @@ public class JSONOAuth2Persister impleme
           final JSONObject settings = binding.getJSONObject(gadgetServiceName);
           final String clientName = settings.getString(JSONOAuth2Persister.CLIENT_NAME);
           final boolean allowOverride = settings
-              .getBoolean(JSONOAuth2Persister.ALLOW_MODULE_OVERRIDE);
+                  .getBoolean(JSONOAuth2Persister.ALLOW_MODULE_OVERRIDE);
           final OAuth2GadgetBinding gadgetBinding = new OAuth2GadgetBinding(gadgetUri,
-              gadgetServiceName, clientName, allowOverride);
+                  gadgetServiceName, clientName, allowOverride);
 
           ret.put(gadgetBinding.getGadgetUri() + ':' + gadgetBinding.getGadgetServiceName(),
-              gadgetBinding);
+                  gadgetBinding);
         }
       }
 
@@ -276,12 +289,12 @@ public class JSONOAuth2Persister impleme
         final JSONObject provider = providers.getJSONObject(providerName);
         final JSONObject endpoints = provider.getJSONObject(JSONOAuth2Persister.ENDPOINTS);
 
-        final String clientAuthenticationType = provider
-            .optString(JSONOAuth2Persister.CLIENT_AUTHENTICATION,
+        final String clientAuthenticationType = provider.optString(
+                JSONOAuth2Persister.CLIENT_AUTHENTICATION,
                 JSONOAuth2Persister.NO_CLIENT_AUTHENTICATION);
 
         final boolean authorizationHeader = provider.optBoolean(
-            JSONOAuth2Persister.AUTHORIZATION_HEADER, false);
+                JSONOAuth2Persister.AUTHORIZATION_HEADER, false);
 
         final boolean urlParameter = provider.optBoolean(JSONOAuth2Persister.URL_PARAMETER, false);
 
@@ -326,13 +339,14 @@ public class JSONOAuth2Persister impleme
     return Collections.emptySet();
   }
 
-  public static boolean removeToken(@SuppressWarnings("unused") final Integer index) {
+  public static boolean removeToken(@SuppressWarnings("unused")
+  final Integer index) {
     // does nothing
     return false;
   }
 
   public boolean removeToken(final String providerName, final String gadgetUri, final String user,
-      final String scope, final Type type) {
+          final String scope, final Type type) {
     return false;
   }
 

Modified: shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/oauth2/persistence/OAuth2ClientTest.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/oauth2/persistence/OAuth2ClientTest.java?rev=1326805&r1=1326804&r2=1326805&view=diff
==============================================================================
--- shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/oauth2/persistence/OAuth2ClientTest.java (original)
+++ shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/oauth2/persistence/OAuth2ClientTest.java Mon Apr 16 21:30:49 2012
@@ -54,9 +54,9 @@ public class OAuth2ClientTest extends Mo
     Assert.assertEquals(false, result.isAuthorizationHeader());
     Assert.assertEquals(false, result.isUrlParameter());
     Assert
-        .assertEquals(
-            "org.apache.shindig.gadgets.oauth2.persistence.sample.OAuth2ClientImpl: serviceName = null , redirectUri = null , gadgetUri = null , clientId = null , grantType = NONE , type = UNKNOWN , grantType = NONE , tokenUrl = null , authorizationUrl = null , this.clientAuthenticationType = null",
-            result.toString());
+    .assertEquals(
+        "org.apache.shindig.gadgets.oauth2.persistence.sample.OAuth2ClientImpl: serviceName = null , redirectUri = null , gadgetUri = null , clientId = null , grantType = NONE , type = UNKNOWN , grantType = NONE , tokenUrl = null , authorizationUrl = null , this.clientAuthenticationType = null , this.sharedToken = false",
+        result.toString());
   }
 
   @Test