fetcher = $fetcher; $this->keyName = $keyName; $this->privateKeyObject = $privateKeyObject; } /** * * @param RemoteContentRequest $request * @return RemoteContentRequest */ public function fetchRequest(RemoteContentRequest $request) { $this->signRequest($request); return $this->fetcher->fetchRequest($request); } /** * * @param array $requests * @return array */ public function multiFetchRequest(array $requests) { foreach ($requests as $request) { $this->signRequest($request); } return $this->fetcher->multiFetchRequest($requests); } /** * * @param RemoteContentRequest $request */ private function signRequest(RemoteContentRequest $request) { $url = $request->getUrl(); $method = $request->getMethod(); 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; $contentType = $request->getHeader('Content-Type'); $signBody = (stripos($contentType, 'application/x-www-form-urlencoded') !== false || $contentType == null); $msgParams = array(); $postParams = array(); if ($request->getPostBody()) { if ($signBody) { // on normal application/x-www-form-urlencoded type post's encode and parse the post vars parse_str($request->getPostBody(), $postParams); $postParams = $this->sanitize($postParams); } else { // on any other content-type of post (application/{json,xml,xml+atom}) use the body signing hash // see http://oauth.googlecode.com/svn/spec/ext/body_hash/1.0/drafts/4/spec.html for details $msgParams['oauth_body_hash'] = base64_encode(sha1($request->getPostBody(), true)); } } if ($signBody && isset($postParams)) { $msgParams = array_merge($msgParams, $postParams); } $this->addOpenSocialParams($msgParams, $request->getToken(), $request->getOptions()->ownerSigned, $request->getOptions()->viewerSigned); $this->addOAuthParams($msgParams, $request->getToken()); $consumer = new \OAuthConsumer(NULL, NULL, NULL); $signatureMethod = new ShindigRsaSha1SignatureMethod($this->privateKeyObject, null); $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(); $postData = false; if ($method == 'POST' && $signBody) { foreach ($postParams as $key => $param) { $forPost[$key] = $param; if ($postData === false) { $postData = array(); } $postData[] = \OAuthUtil::urlencode_rfc3986($key) . "=" . \OAuthUtil::urlencode_rfc3986($param); } if ($postData !== false) { $postData = implode("&", $postData); } } $newQueryParts = array(); foreach ($req_req->get_parameters() as $key => $param) { if (! isset($forPost[$key])) { if (!is_array($param)) { $newQueryParts[] = urlencode($key) . '=' . urlencode($param); } else { foreach($param as $elem) { $newQueryParts[] = urlencode($key) . '=' . urlencode($elem); } } } $newQuery = implode('&', $newQueryParts); } // 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'] . (isset($parsedUri['port']) ? ':' . $parsedUri['port'] : '') . (isset($parsedUri['path']) ? $parsedUri['path'] : '') . '?' . $newQuery; $request->setUri($url); if ($signBody) { $request->setPostBody($postData); } } catch (\Exception $e) { throw new GadgetException($e); } } /** * * @param array $msgParams * @param SecurityToken $token * @param boolean $signOwner * @param boolean $signViewer */ private function addOpenSocialParams(&$msgParams, SecurityToken $token, $signOwner, $signViewer) { if ($signOwner) { $owner = $token->getOwnerId(); if ($owner != null) { $msgParams[SigningFetcher::$OPENSOCIAL_OWNERID] = $owner; } } if ($signViewer) { $viewer = $token->getViewerId(); if ($viewer != null) { $msgParams[SigningFetcher::$OPENSOCIAL_VIEWERID] = $viewer; } } if ($signOwner || $signViewer) { $app = $token->getAppId(); if ($app != null) { $msgParams[SigningFetcher::$OPENSOCIAL_APPID] = $app; } $url = $token->getAppUrl(); if ($url != null) { $msgParams[SigningFetcher::$OPENSOCIAL_APPURL] = $url; } $moduleId = $token->getModuleId(); if ($moduleId != null) { $msgParams[SigningFetcher::$OPENSOCIAL_INSTANCEID] = $moduleId; } } } /** * * @param array $msgParams * @param SecurityToken $token */ private function addOAuthParams(&$msgParams, SecurityToken $token) { $msgParams[ShindigOAuth::$OAUTH_TOKEN] = ''; $domain = $token->getDomain(); if ($domain != null) { $msgParams[ShindigOAuth::$OAUTH_CONSUMER_KEY] = $domain; } if ($this->keyName != null) { $msgParams[SigningFetcher::$XOAUTH_PUBLIC_KEY_OLD] = $this->keyName; $msgParams[SigningFetcher::$XOAUTH_PUBLIC_KEY_NEW] = $this->keyName; } $nonce = ShindigOAuthRequest::generate_nonce(); $msgParams[ShindigOAuth::$OAUTH_NONCE] = $nonce; $timestamp = time(); $msgParams[ShindigOAuth::$OAUTH_TIMESTAMP] = $timestamp; $msgParams[ShindigOAuth::$OAUTH_SIGNATURE_METHOD] = ShindigOAuth::$RSA_SHA1; } /** * Strip out any owner or viewer id passed by the client. * * @param array $params * @return array */ private function sanitize($params) { $list = array(); foreach ($params as $key => $p) { if ($this->allowParam($key)) { $list[$key] = $p; } } return $list; } /** * * @param string $paramName * @return booelan */ 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" || $canonParamName == "container") { return false; } return true; } }