You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@shindig.apache.org by ch...@apache.org on 2008/08/01 21:17:25 UTC
svn commit: r681787 -
/incubator/shindig/trunk/php/src/gadgets/SigningFetcher.php
Author: chabotc
Date: Fri Aug 1 12:17:25 2008
New Revision: 681787
URL: http://svn.apache.org/viewvc?rev=681787&view=rev
Log:
SHINDIG-447 signing fetcher fix by Karsten Beyer, cleaned up to apply by Gonzalo Aune
Modified:
incubator/shindig/trunk/php/src/gadgets/SigningFetcher.php
Modified: incubator/shindig/trunk/php/src/gadgets/SigningFetcher.php
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/php/src/gadgets/SigningFetcher.php?rev=681787&r1=681786&r2=681787&view=diff
==============================================================================
--- incubator/shindig/trunk/php/src/gadgets/SigningFetcher.php (original)
+++ incubator/shindig/trunk/php/src/gadgets/SigningFetcher.php Fri Aug 1 12:17:25 2008
@@ -1,4 +1,4 @@
-<?php
+<?php
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -11,8 +11,8 @@
* 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.
- */
-
+ */
+
/**
* Implements signed fetch based on the OAuth request signing algorithm.
*
@@ -21,32 +21,30 @@
*
* Instances of this class are only accessed by a single thread at a time,
* but instances may be created by multiple threads.
- */
-class SigningFetcher extends RemoteContentFetcher {
-
- protected static $OPENSOCIAL_OWNERID = "opensocial_owner_id";
- protected static $OPENSOCIAL_VIEWERID = "opensocial_viewer_id";
- protected static $OPENSOCIAL_APPID = "opensocial_app_id";
- protected static $XOAUTH_PUBLIC_KEY = "xoauth_signature_publickey";
- protected static $ALLOWED_PARAM_NAME = "[-:\\w]+";
-
- //protected final TimeSource clock = new TimeSource();
-
+ */
+class SigningFetcher extends RemoteContentFetcher {
+
+ protected static $OPENSOCIAL_OWNERID = "opensocial_owner_id";
+ protected static $OPENSOCIAL_VIEWERID = "opensocial_viewer_id";
+ protected static $OPENSOCIAL_APPID = "opensocial_app_id";
+ protected static $XOAUTH_PUBLIC_KEY = "xoauth_signature_publickey";
+ protected static $ALLOWED_PARAM_NAME = '^[-_[:alnum:]]+$';
+
/**
* Authentication token for the user and gadget making the request.
- */
- protected $authToken;
-
+ */
+ protected $authToken;
+
/**
* Private key we pass to the OAuth RSA_SHA1 algorithm.This can be a
* PrivateKey object, or a PEM formatted private key, or a DER encoded byte
* array for the private key.(No, really, they accept any of them.)
- */
- protected $privateKeyObject;
-
+ */
+ protected $privateKeyObject;
+
/**
* The name of the key, included in the fetch to help with key rotation.
- */
+ */
protected $keyName;
/**
@@ -91,11 +89,11 @@
$this->authToken = $authToken;
$this->keyName = $keyName;
$this->privateKeyObject = $privateKeyObject;
- }
-
+ }
+
public function fetchRequest($request)
- {
- return $this->getNextFetcher()->fetchRequest($request);
+ {
+ return $this->getNextFetcher()->fetchRequest($request);
}
public function fetch($url, $method)
@@ -109,59 +107,74 @@
try {
// Parse the request into parameters for OAuth signing, stripping out
// any OAuth or OpenSocial parameters injected by the client
- ///////////////////////////////////////////////
$parsedUri = parse_url($url);
$resource = $url;
$queryParams = $this->sanitize($_GET);
$postParams = $this->sanitize($_POST);
+ // The data that is supposed to be posted to the target page is contained in the postData field
+ // in the $_POST to the Shindig proxy server
+ // Here we parse it and put it into the $postDataParams array which then is merged into the postParams
+ // to be used for the GET/POST request and the building of the signature
+ $postDataParams = array();
+ if (isset($_POST['postData']) && count($postDataParts = split('&', urldecode($_POST['postData']))) > 0) {
+ foreach ($postDataParts as $postDataPart) {
+ $postDataPartsPair = split('=', $postDataPart);
+ if (count($postDataPartsPair) === 2) {
+ $postDataParams[$postDataPartsPair[0]] = $postDataPartsPair[1];
+ }
+ }
+ }
+ $postParams = array_merge($postParams, $this->sanitize($postDataParams));
$msgParams = array();
$msgParams = array_merge($msgParams, $queryParams);
$msgParams = array_merge($msgParams, $postParams);
-
- // TODO: is this ok?
- //$msgParams = array();
- $this->addOpenSocialParams($msgParams);
+ $this->addOpenSocialParams($msgParams);
$this->addOAuthParams($msgParams);
-
- // Build and sign the OAuthMessage; note that the resource here has
- // no query string, the parameters are all in msgParams
- //$message = new OAuthMessage($method, $resource, $msgParams);
-
- ////////////////////////////////////////////////
$consumer = new OAuthConsumer(NULL, NULL, NULL);
$consumer->setProperty(OAuthSignatureMethod_RSA_SHA1::$PRIVATE_KEY, $this->privateKeyObject);
$signatureMethod = new OAuthSignatureMethod_RSA_SHA1();
-
$req_req = OAuthRequest::from_consumer_and_token($consumer, NULL, $method, $resource, $msgParams);
$req_req->sign_request($signatureMethod, $consumer, NULL);
-
// Rebuild the query string, including all of the parameters we added.
// We have to be careful not to copy POST parameters into the query.
// If post and query parameters share a name, they end up being removed
// from the query.
- $forPost = array();
- foreach ($postParams as $key => $param) {
- $forPost[$key] = $param;
+ $forPost = array();
+ $postData = false;
+ if ($method == 'POST') {
+ foreach ($postParams as $key => $param) {
+ $forPost[$key] = $param;
+ if ($postData === false) {
+ $postData = array();
+ }
+ $postData[] = OAuthUtil::urlencodeRFC3986($key) . "=" . OAuthUtil::urlencodeRFC3986($param);
+ }
+ if ($postData !== false) {
+ $postData = implode("&", $postData);
+ }
}
$newQuery = '';
foreach ($req_req->get_parameters() as $key => $param) {
if (! isset($forPost[$key])) {
- $newQuery .= urlencode($key).'='.urlencode($param).'&';
+ $newQuery .= urlencode($key) . '=' . urlencode($param) . '&';
}
}
// and stick on the original query params too
- if (isset($parsedUri['query']) && !empty($parsedUri['query'])) {
+ if (isset($parsedUri['query']) && ! empty($parsedUri['query'])) {
$oldQuery = array();
parse_str($parsedUri['query'], $oldQuery);
foreach ($oldQuery as $key => $val) {
- $newQuery .= urlencode($key).'='.urlencode($val).'&';
+ $newQuery .= urlencode($key) . '=' . urlencode($val) . '&';
}
}
// Careful here; the OAuth form encoding scheme is slightly different than
// the normal form encoding scheme, so we have to use the OAuth library
// formEncode method.
- $url = $parsedUri['scheme'].'://'.$parsedUri['host'].$parsedUri['path'].'?'.$newQuery;
- return new RemoteContentRequest($url);
+ $url = $parsedUri['scheme'] . '://' . $parsedUri['host'] . $parsedUri['path'] . '?' . $newQuery;
+ // The headers are transmitted in the POST-data array in the field 'headers'
+ // if no post should be made, the value should be false for this parameter
+ $postHeaders = ((isset($_POST['headers']) && $method == 'POST') ? $_POST['headers'] : false);
+ return new RemoteContentRequest($url, $postHeaders, $postData);
} catch (Exception $e) {
throw new GadgetException($e);
}
@@ -188,7 +201,7 @@
$msgParams[OAuth::$OAUTH_TOKEN] = '';
$domain = $this->authToken->getDomain();
if ($domain != null) {
- $msgParams[OAuth::$OAUTH_CONSUMER_KEY] = $domain;
+ $msgParams[OAuth::$OAUTH_CONSUMER_KEY] = $domain;
}
if ($this->keyName != null) {
$msgParams[SigningFetcher::$XOAUTH_PUBLIC_KEY] = $this->keyName;
@@ -214,9 +227,24 @@
return $list;
}
+ /*
private function allowParam($paramName)
{
$canonParamName = strtolower($paramName);
return (! (substr($canonParamName, 0, 5) == "oauth" || substr($canonParamName, 0, 6) == "xoauth" || substr($canonParamName, 0, 9) == "opensocial")) && ereg(SigningFetcher::$ALLOWED_PARAM_NAME, $canonParamName);
}
+ */
+
+ private function allowParam($paramName)
+ {
+ $canonParamName = strtolower($paramName);
+ // Exclude the fields which are only used to tell the proxy what to do
+ // and the fields which should be added by signing the request later on
+ if ($canonParamName == "output" || $canonParamName == "httpmethod" || $canonParamName == "authz" || $canonParamName == "st" || $canonParamName == "headers" || $canonParamName == "url" || $canonParamName == "contenttype" || $canonParamName == "postdata" || $canonParamName == "numentries" || $canonParamName == "getsummaries" || $canonParamName == "signowner" || $canonParamName == "signviewer" || $canonParamName == "gadget" || $canonParamName == "bypassspeccache" || substr($canonParamName, 0, 5) == "oauth" || substr($canonParamName, 0, 6) == "xoauth" || substr($canonParamName, 0, 9) == "opensocial") {
+ return false;
+ }
+ // make a last sanity check on the key of the data by using a regular expression
+ return ereg(SigningFetcher::$ALLOWED_PARAM_NAME, $canonParamName);
+ }
+
}