Inlined patch since the attachment got eaten somehow.. Index: src/test/java/org/apache/shindig/gadgets/BasicGadgetTokenTest.java =================================================================== --- src/test/java/org/apache/shindig/gadgets/BasicGadgetTokenTest.java (revision 0) +++ src/test/java/org/apache/shindig/gadgets/BasicGadgetTokenTest.java (revision 0) @@ -0,0 +1,63 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.shindig.gadgets; + +import junit.framework.Test; +import junit.framework.TestSuite; +import junit.framework.TestCase; + +import java.net.URL; + + +/** + * BasicGadgetToken Tester. + * + * @author <Authors name> + * @since <pre>03/11/2008</pre> + * @version 1.0 + */ +public class BasicGadgetTokenTest extends TestCase { + private GadgetToken token; + + public BasicGadgetTokenTest(String name) { + super(name); + } + + public void setUp() throws Exception { + super.setUp(); + token = new BasicGadgetToken("http://www.example.com/"); + } + + public void tearDown() throws Exception { + super.tearDown(); + } + + public void testToken() throws Exception { + token = new BasicGadgetToken("http://www.example.com/"); + + URL u = token.signUrl(new URL("http://www.example.com/"), "GET", null); + String urlString = u.toString(); + + assertEquals("Found " + urlString, "the correct URL", urlString); + } + +// public static Test suite() { +// return new TestSuite(BasicGadgetTokenTest.class); +// } +} Index: src/main/java/org/apache/shindig/gadgets/BasicGadgetSigner.java =================================================================== --- src/main/java/org/apache/shindig/gadgets/BasicGadgetSigner.java (revision 636144) +++ src/main/java/org/apache/shindig/gadgets/BasicGadgetSigner.java (working copy) @@ -18,6 +18,12 @@ */ package org.apache.shindig.gadgets; +import net.oauth.OAuth; +import net.oauth.OAuthMessage; +import net.oauth.signature.OAuthSignatureMethod; + + + /** * A GadgetSigner implementation that just provides dummy data to satisfy * tests and API calls. Do not use this for any security applications. Index: src/main/java/org/apache/shindig/gadgets/BasicGadgetToken.java =================================================================== --- src/main/java/org/apache/shindig/gadgets/BasicGadgetToken.java (revision 636144) +++ src/main/java/org/apache/shindig/gadgets/BasicGadgetToken.java (working copy) @@ -19,13 +19,71 @@ package org.apache.shindig.gadgets; import java.net.URL; -import java.util.Collection; -import java.util.Map; +import java.net.URI; +import java.util.*; +import java.util.regex.Pattern; +import java.security.SecureRandom; +import java.security.KeyFactory; +import java.security.PrivateKey; +import java.security.spec.EncodedKeySpec; +import java.security.spec.PKCS8EncodedKeySpec; +import net.oauth.OAuth; +import net.oauth.OAuthMessage; +import net.oauth.OAuthConsumer; +import net.oauth.OAuthAccessor; +import net.oauth.signature.OAuthSignatureMethod; +import net.oauth.signature.RSA_SHA1; + + /** * Primitive token implementation that uses stings as tokens. */ class BasicGadgetToken implements GadgetToken { + private static final String OPENSOCIAL_OWNERID = "opensocial_ownerid"; + private static final String OPENSOCIAL_VIEWERID = "opensocial_viewerid"; + private static final String OPENSOCIAL_APPID = "opensocial_appid"; + private static final Random DEFAULT_NONCE_GENERATOR = new SecureRandom(); + private static final Pattern ALLOWED_PARAM_NAME = Pattern + .compile("[\\w_\\-]+"); + + private static final String PRIVATE_KEY = + "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBALRiMLAh9iimur8V" + + "A7qVvdqxevEuUkW4K+2KdMXmnQbG9Aa7k7eBjK1S+0LYmVjPKlJGNXHDGuy5Fw/d" + + "7rjVJ0BLB+ubPK8iA/Tw3hLQgXMRRGRXXCn8ikfuQfjUS1uZSatdLB81mydBETlJ" + + "hI6GH4twrbDJCR2Bwy/XWXgqgGRzAgMBAAECgYBYWVtleUzavkbrPjy0T5FMou8H" + + "X9u2AC2ry8vD/l7cqedtwMPp9k7TubgNFo+NGvKsl2ynyprOZR1xjQ7WgrgVB+mm" + + "uScOM/5HVceFuGRDhYTCObE+y1kxRloNYXnx3ei1zbeYLPCHdhxRYW7T0qcynNmw" + + "rn05/KO2RLjgQNalsQJBANeA3Q4Nugqy4QBUCEC09SqylT2K9FrrItqL2QKc9v0Z" + + "zO2uwllCbg0dwpVuYPYXYvikNHHg+aCWF+VXsb9rpPsCQQDWR9TT4ORdzoj+Nccn" + + "qkMsDmzt0EfNaAOwHOmVJ2RVBspPcxt5iN4HI7HNeG6U5YsFBb+/GZbgfBT3kpNG" + + "WPTpAkBI+gFhjfJvRw38n3g/+UeAkwMI2TJQS4n8+hid0uus3/zOjDySH3XHCUno" + + "cn1xOJAyZODBo47E+67R4jV1/gzbAkEAklJaspRPXP877NssM5nAZMU0/O/NGCZ+" + + "3jPgDUno6WbJn5cqm8MqWhW1xGkImgRk+fkDBquiq4gPiT898jusgQJAd5Zrr6Q8" + + "AO/0isr/3aa6O6NLQxISLKcPDk2NOccAfS/xOtfOz4sJYM3+Bs4Io9+dZGSDCA54" + + "Lw03eHTNQghS0A=="; + + private static final String PUBLIC_KEY = + "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC0YjCwIfYoprq/FQO6lb3asXrx" + + "LlJFuCvtinTF5p0GxvQGu5O3gYytUvtC2JlYzypSRjVxwxrsuRcP3e641SdASwfr" + + "mzyvIgP08N4S0IFzEURkV1wp/IpH7kH41EtbmUmrXSwfNZsnQRE5SYSOhh+LcK2w" + + "yQkdgcMv11l4KoBkcwIDAQAB"; + + private static final String CERTIFICATE = + "-----BEGIN CERTIFICATE-----\n" + + "MIIBpjCCAQ+gAwIBAgIBATANBgkqhkiG9w0BAQUFADAZMRcwFQYDVQQDDA5UZXN0\n" + + "IFByaW5jaXBhbDAeFw03MDAxMDEwODAwMDBaFw0zODEyMzEwODAwMDBaMBkxFzAV\n" + + "BgNVBAMMDlRlc3QgUHJpbmNpcGFsMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB\n" + + "gQC0YjCwIfYoprq/FQO6lb3asXrxLlJFuCvtinTF5p0GxvQGu5O3gYytUvtC2JlY\n" + + "zypSRjVxwxrsuRcP3e641SdASwfrmzyvIgP08N4S0IFzEURkV1wp/IpH7kH41Etb\n" + + "mUmrXSwfNZsnQRE5SYSOhh+LcK2wyQkdgcMv11l4KoBkcwIDAQABMA0GCSqGSIb3\n" + + "DQEBBQUAA4GBAGZLPEuJ5SiJ2ryq+CmEGOXfvlTtEL2nuGtr9PewxkgnOjZpUy+d\n" + + "4TvuXJbNQc8f4AMWL/tO9w0Fk80rWKp9ea8/df4qMq5qlFWlx6yOLQxumNOmECKb\n" + + "WpkUQDIDJEoFUzKMVuJf4KO/FJ345+BNLGgbJ6WujreoM1X/gYfdnJ/J\n" + + "-----END CERTIFICATE-----"; + + + private final String token; /** @@ -48,7 +106,63 @@ * Signer that does not sign. */ public URL signUrl(URL uri, String httpMethod, - Map<String, Collection<String>> parameters) { - return uri; + Map<String, Collection<String>> parameters) { + String strippedUrl = uri.toString().replaceFirst("\\?.*$",""); + + OAuthMessage message = new OAuthMessage(httpMethod,strippedUrl, + new ArrayList<OAuth.Parameter>()); + + // Add passed params to the message + if (parameters== null) { + parameters = Collections.emptyMap(); + } + for (Map.Entry<String, Collection<String>> entry : parameters.entrySet()) { + if (allowParam(entry.getKey())) { + for (String val : entry.getValue()) { + message.addParameter(new OAuth.Parameter(entry.getKey(), val)); + } + } + } + // Add standard OpenSocial params to method + message.addParameter( + new OAuth.Parameter(OPENSOCIAL_OWNERID, "1")); + if (false) { + message.addParameter( + new OAuth.Parameter(OPENSOCIAL_VIEWERID, "1")); + } + + message.addParameter(new OAuth.Parameter(OPENSOCIAL_APPID, "1")); + message.addParameter(new OAuth.Parameter(OAuth.OAUTH_TOKEN, "")); + message.addParameter( + new OAuth.Parameter(OAuth.OAUTH_CONSUMER_KEY, "")); // TODO this is some kind of domain + message.addParameter(new OAuth.Parameter(OAuth.OAUTH_NONCE, Long.toHexString(DEFAULT_NONCE_GENERATOR.nextLong()))); + message.addParameter(new OAuth.Parameter(OAuth.OAUTH_TIMESTAMP, Long.toString(System.currentTimeMillis()/1000L))); + message.addParameter(new OAuth.Parameter(OAuth.OAUTH_SIGNATURE_METHOD, OAuth.RSA_SHA1)); + try { + + OAuthConsumer consumer = new OAuthConsumer(null, null, null, null); + + EncodedKeySpec privKeySpec = + new PKCS8EncodedKeySpec(OAuthSignatureMethod + .decodeBase64(PRIVATE_KEY)); + KeyFactory fac = KeyFactory.getInstance("RSA"); + PrivateKey privateKey = fac.generatePrivate(privKeySpec); + consumer.setProperty (RSA_SHA1.PRIVATE_KEY, privateKey); + OAuthAccessor accessor = new OAuthAccessor(consumer); + message.sign(accessor); + + return new URL(strippedUrl + '?' + OAuth.formEncode(message.getParameters())); + + } catch (Exception e) { + return null; + } } + + private boolean allowParam(String paramName) { + String canonParamName = paramName.toLowerCase(); + return (!(canonParamName.startsWith("oauth") || + canonParamName.startsWith("xoauth") || + canonParamName.startsWith("opensocial")) && + ALLOWED_PARAM_NAME.matcher(canonParamName).matches()); + } } \ No newline at end of file
On 3/11/08 6:33 PM, "Paul Lindner" <[EMAIL PROTECTED]> wrote: > So I¹m hard at work on signed requests. Here¹s what I¹ve come up with so far. > > Ideally one could add in a GadgetToken implementation that supplied the > ownerid/viewerid/appid. > > I¹d appreciate feedback on this implementation. > > >

