OpenSocial Oauth SIGN verification

I encountered this problem when I was implementing authentication for Gmail Gadget. Gadget talks with our API endpoint via osapi.http which is designed for OpenSoical. Basically when sending request via osapi.http it will sign the request using OAuth1.0, and we need to verify the signature in our API side. Here is a pretty good document explaining why and how OpenSoical sign the request. https://opensocial.atlassian.net/wiki/display/OSREF/Introduction+To+Signed+Requests

It also has a very detailed example of how to validate the signature on the service provider side, ie. ALAPI, however, as always, there is no Perl implementation! It again leaves me no option but building this from nothing.

  • In order to verify the signature we need to have the public key, please notice we DO NOT need a private key for verifying when is it using RSA-SHA1 method, however, what I can get is a certificate rather than a public key. Honestly speaking, I had no security subjects in Uni so I am very bad at these security stuff, consequently it took me a huge chunk of time to figure out the relationship between a certificate and a public key and how to extract the key from the certificate, and the painful thing is I can’t immediately verify the key extracted from the certificate until the last minute the entire thing works. Here is how to extract key:

openssl x509 -inform pem -in igoogle.cer -pubkey -noout > igoogle.pem
  • The next problem is how to implement in perl. There are two CPAN modules you can use for doing this, OAuth::Lite::SignatureMethod::RSA_SHA1 and Net::OAuth, I believe both of them will work but I just can’t make OAuth::Lite::SignatureMethod::RSA_SHA1 happy and I just don’t bother trying again after so many times fail. Here tells you how to do the verification but it is really rough, my code is this:

my $cert = read_file('/data/bin/cert/igoogle.pem');
my $public_key = Crypt::OpenSSL::RSA->new_public_key($cert);
my $request = Net::OAuth->request('request token')->new(
                consumer_key => $oauth_consumer_key,
                consumer_secret =>’’,
                request_method => 'GET',
                request_url => $r_url,
                signature_method => 'RSA-SHA1',
                version => '1.0',
                nonce => $oauth_nonce,
                timestamp => $oauth_timestamp,
                signature => $oauth_signature);
$request->verify($public_key);

There are a key few points regarding Net::OAuth:

  1. consumer_secret. As I said we don’t need it, but I still need to specify it here, just setting it to anything is fine
  2. request_url. This is the most painful part, should it be just the API endpoint, eg. http://nisee.dev.affinitylive.com:8002/api/0.5/anon/integration/google/gadget, or should it be with params, ie. http://nisee.dev.affinitylive.com:8002/api/0.5/anon/integration/google/gadget?oauth_body_hash=2jmj7l5rSw0yVb/vlWAYkK/YBwk=&opensocial_owner_id=110498915825481989798&opensocial_viewer_id=110498915825481989798&opensocial_app_id=102181831276096394509&opensocial_app_url=http://nisee.dev.affinitylive.com:8002/dev/gmail_spec.xml&xoauth_signature_publickey=pub.1210278512.2713152949996518384.cer&xoauth_public_key=pub.1210278512.2713152949996518384.cer&oauth_version=1.0&oauth_timestamp=1368518566&oauth_nonce=434077884281550564&opensocial_container=http://mail.google.com&oauth_consumer_key=www.google.com&oauth_signature_method=RSA-SHA1 ? Okay, the answer is with params, HOWEVER, oauth_signature=xxxxx param MUST be excluded from the string! And you must NOT escape the URL.

After suffering two days I finally got this bloody hell nasty thing work!

Money comes in

Money comes in

A phone taken a few years ago in Xitang, an amazing small town near Shanghai. Love the pure Chinese red and writing artwork, imagining myself as a traditional artist living in hundred years ago’s China, tea, poem and researching authentic Chinese cuisine.