Did you take a look at Brian Eaton's patch (forget exactly the number...it was from a while ago)? I was just speaking with him a bit ago and he indicated that he would like to work on this as well. He's pretty knowledgeable here, you guys should talk.
One known bug that we just discovered on orkut is that the current interface doesn't accommodate post body being included in the signing process. We should do this. On Tue, Mar 11, 2008 at 7:44 PM, Paul Lindner <[EMAIL PROTECTED]> wrote: > 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. > > > > > > > > -- ~Kevin

