package com.ibm.sbt.opensocial.domino.oauth; import java.util.Map; import net.oauth.OAuth; import net.oauth.OAuthConsumer; import net.oauth.OAuthServiceProvider; import net.oauth.signature.RSA_SHA1; import org.apache.shindig.auth.SecurityToken; import org.apache.shindig.common.servlet.Authority; import org.apache.shindig.gadgets.GadgetException; import org.apache.shindig.gadgets.GadgetException.Code; import org.apache.shindig.gadgets.oauth.BasicOAuthStore; import org.apache.shindig.gadgets.oauth.BasicOAuthStoreTokenIndex; import com.google.caja.util.Maps; import com.ibm.sbt.opensocial.domino.container.ContainerExtPoint; import com.ibm.sbt.opensocial.domino.container.ContainerExtPointException; import com.ibm.sbt.opensocial.domino.container.ContainerExtPointManager; import com.ibm.sbt.opensocial.domino.oauth.DominoOAuthClient.KeyType; /** * OAuth 1.0a store for OpenSocial gadgets on Domino. * */ //TODO Right now every container is forced to let every gadget share OAuth tokens. Some containers may not want that. We should allow //containers to specify that in their configuration and handle that here. public class InternalDominoOAuthStore extends BasicOAuthStore { private ContainerExtPointManager extPointManager; private Authority authority; private String defaultCallbackUrl; private final Map<BasicOAuthStoreTokenIndex, TokenInfo> tokens; /** * Token store for the OpenSocial implementation. This store just delegates to * the token stores for the individual containers. */ public InternalDominoOAuthStore(ContainerExtPointManager extPointManager, Authority authority, String defaultCallbackUrl) { super(); this.extPointManager = extPointManager; this.authority = authority; this.defaultCallbackUrl = defaultCallbackUrl; tokens = Maps.newHashMap(); } @Override public ConsumerInfo getConsumerKeyAndSecret(SecurityToken securityToken, String serviceName, OAuthServiceProvider provider) throws GadgetException { if(securityToken.isAnonymous() || "@anonymous".equals(securityToken.getViewerId())) { throw new GadgetException(Code.INVALID_SECURITY_TOKEN, "Anonymous users cannot use OAuth in gadgets"); } ContainerExtPoint extPoint = getContainerExtPoint(securityToken.getContainer()); DominoOAuthStore store = null; try { store = extPoint.getContainerOAuthStore(); } catch (ContainerExtPointException e) { throw new GadgetException(GadgetException.Code.INTERNAL_SERVER_ERROR, "Exception thrown when getting the DominoOAuthStore for the container " + securityToken.getContainer()); } if(store == null) { throw new GadgetException(GadgetException.Code.INTERNAL_SERVER_ERROR, "No DominoOAuthStore provided for the container " + securityToken.getContainer()); } DominoOAuthClient client = store.getClient(securityToken.getViewerId(), securityToken.getContainer(), serviceName, securityToken.getAppUrl()); if(client == null) { throw new GadgetException(GadgetException.Code.INTERNAL_SERVER_ERROR, "The Domino OAuth Store for container " + securityToken.getContainer() + " did not return client information for viewer: " + securityToken.getViewerId() + ", service: " + serviceName + " gadget: " + securityToken.getAppUrl()); } OAuthConsumer consumer; final KeyType keyType = client.getKeyType(); if (keyType == KeyType.RSA_PRIVATE) { consumer = new OAuthConsumer(null, client.getConsumerKey(), null, provider); // The oauth.net java code has lots of magic. By setting this property here, code thousands // of lines away knows that the consumerSecret value in the consumer should be treated as // an RSA private key and not an HMAC key. consumer.setProperty(OAuth.OAUTH_SIGNATURE_METHOD, OAuth.RSA_SHA1); consumer.setProperty(RSA_SHA1.PRIVATE_KEY, client.getConsumerSecret()); } else if (keyType == KeyType.PLAINTEXT) { consumer = new OAuthConsumer(null, client.getConsumerKey(), client.getConsumerSecret(), provider); consumer.setProperty(OAuth.OAUTH_SIGNATURE_METHOD, "PLAINTEXT"); } else { consumer = new OAuthConsumer(null, client.getConsumerKey(), client.getConsumerSecret(), provider); consumer.setProperty(OAuth.OAUTH_SIGNATURE_METHOD, OAuth.HMAC_SHA1); } String callback = createCallback(client.isForceCallbackOverHttps()); return new ConsumerInfo(consumer, null, callback, false); } private String createCallback(boolean forceHttps) { String callback = defaultCallbackUrl; if (authority != null) { callback = callback.replace("%authority%", authority.getAuthority()); } if(callback.contains("http")) { callback = callback.replace(":80", ""); } if(callback.contains("https")) { callback = callback.replace(":443", ""); } if(forceHttps) { if(!callback.contains("https")) { callback = callback.replace("http", "https"); } } return callback; } private ContainerExtPoint getContainerExtPoint(String container) throws GadgetException { ContainerExtPoint extPoint = extPointManager.getExtPoint(container); if(extPoint == null) { throw new GadgetException(Code.OAUTH_STORAGE_ERROR, "No container extension point could be found for the container with the name " + container + "."); } return extPoint; } private BasicOAuthStoreTokenIndex makeBasicOAuthStoreTokenIndex( SecurityToken securityToken, String serviceName, String tokenName) { BasicOAuthStoreTokenIndex tokenKey = new BasicOAuthStoreTokenIndex(); tokenKey.setGadgetUri(""); tokenKey.setModuleId(securityToken.getModuleId()); tokenKey.setServiceName(serviceName); tokenKey.setTokenName(tokenName); tokenKey.setUserId(securityToken.getViewerId()); return tokenKey; } @Override public TokenInfo getTokenInfo(SecurityToken securityToken, ConsumerInfo consumerInfo, String serviceName, String tokenName) { BasicOAuthStoreTokenIndex tokenKey = makeBasicOAuthStoreTokenIndex(securityToken, serviceName, tokenName); return tokens.get(tokenKey); } @Override public void setTokenInfo(SecurityToken securityToken, ConsumerInfo consumerInfo, String serviceName, String tokenName, TokenInfo tokenInfo) { BasicOAuthStoreTokenIndex tokenKey = makeBasicOAuthStoreTokenIndex(securityToken, serviceName, tokenName); tokens.put(tokenKey, tokenInfo); } @Override public void removeToken(SecurityToken securityToken, ConsumerInfo consumerInfo, String serviceName, String tokenName) { BasicOAuthStoreTokenIndex tokenKey = makeBasicOAuthStoreTokenIndex(securityToken, serviceName, tokenName); tokens.remove(tokenKey); } }