Update (07/08/2008):I've updated the usage example at the bottom of the page to reflect the new and easier usage of OAuth and I added a note about magic quotes.
Ok, to let you down already in the first sentence: this actually isn't a key cache. It's more of a way to read the Orkut OAuth certificate from disk instead of using it as a string inline in your PHP code.
Other platforms/languages like Java offer key stores for certificates. That doesn't seem to be the case with PHP; heavy googling didn't produce anything indicating the opposite. So I wrote my own.
If you are - like me - forced to use PHP for your OpenSocial backend you have probably read this wiki page about validating signed requests with Orkut. The note before the PHP example reads: "This example is not meant to be production quality code - merely a demonstration of the steps you would take to validate a signed request server-side. You should not be inlining Orkut's public key certificate in your production code."
Ok, we shouldn't inline it. Makes sense. The top of the page suggests that you should "implement a server side key cache indexed on the value of xoauth_signature_publickey. If the value changes, you will need to pull a new certificate down and store it in your key cache."
Great. So lets do that.
I wrote a small PHP class called "CertFileAccessor":
class CertFileAccessor {
private $_certDirPath;
private $_networkName;
public function __construct($dir, $network) {
$this->_certDirPath = $dir;
$this->_networkName = $network;
}
public function getPublicKey($keyName) {
$fp = fopen($this->_certDirPath . '/' . $this->_networkName . '/' . $this->sanitizeKeyName($keyName), "r");
if ($fp) {
$pubKey = fread($fp, 8192);
fclose($fp);
return $pubKey;
}
return null;
}
/* modified from http://www.devdaily.com/scw/php/www.postnuke.com/PostNuke-0.750/html/includes/pnAPI.php.shtml */
private function sanitizeKeyName($keyName)
{
static $search = array('!\.\./!si', // .. (directory traversal)
'!^.*://!si', // .*:// (start of URL)
'!^/!si', // Forward slash (directory traversal)
'!^\\\\!si'); // Backslash (directory traversal)
static $replace = array('',
'',
'_',
'_');
return preg_replace($search, $replace, $keyName);
}
}
?>
Just copy that in a file called "cert_file_accessor.php" and require it in your PHP script. Then you have to create a directory on your server for the certificates. It should preferably not be accessible for internet users, but if you only store public keys there it's not that bad.
Then you have to create a subdirectory for each opensocial network you want to support and that offers public keys for OAuth requests.
So you create
/path/to/my/certs
and
/path/to/my/certs/orkut
In the Orkut subdirectory you put the cert file, currently called 'pub.1199819524.-1556113204990931254.cer'.
Now instead of inlining the certificate you can do this:
$payload = array();
$cert_accessor = new CertFileAccessor('/path/to/my/certs', 'orkut');
$cert = $cert_accessor->getPublicKey($_REQUEST['xoauth_signature_publickey']);
if ($cert != null) {
//Custom OAuthSignatureMethod class that will return our public cert
class KeystoreRSASignatureMethod extends OAuthSignatureMethod_RSA_SHA1 {
public function __construct($cert) {
$this->_cert = $cert;
}
protected function fetch_public_cert(&$request) {
return $this->_cert;
}
}
//Build a request object from the current request
$request = OAuthRequest::from_request(null, null, array_merge($_GET, $_POST));
//Initialize the new signature method
$signature_method = new KeystoreRSASignatureMethod($cert);
//Check the request signature
$auth_ok = $signature_method->check_signature($request, null, null, $_GET["oauth_signature"]);
} else {
$payload['cert'] = 'missing';
}
if ($auth_ok == 1) {
$payload["auth"] = "OK";
/* do your thing */
} else {
$payload["auth"] = "Failed";
}
print(json_encode($payload));
So when the certificate changes in the xoauth_signature_publickey parameter the certificate won't be found and you'll get a "cert=missing" in your JSON response. New certificates simply have to be dropped into the appropriate directory. That's it!
By being able to switch and add keys easily, you can handle signed makeRequest calls from different containers, all in the same server side code. For example, this allows your application to communicate with the same server and use the same data whether it's running on Orkut or hi5.
One more thing: I ran into an ugly issue on a legacy system which had magic_quotes_gpc enabled. That totally messes up OAuth authentication because it adds slashes to incoming GET and POST data. Use the code on the bottom of this page to safely remove magic quotes from your OAuth signed request.



2 comments:
Can this be used in sandbox only? Any idea where to get the certificate for production?
Ronald,
AFAIK, it's the same cert (on Orkut) for both sandbox and production. if not, you might want to ask that question in the Orkut Developers Google Group.
- Johannes
Post a Comment