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/05/21 18:58:53 UTC
svn commit: r658758 [2/2] - in /incubator/shindig/trunk/php: ./ src/common/
src/common/Zend/ src/gadgets/ src/gadgets/http/ src/gadgets/oauth/
src/gadgets/samplecontainer/ src/socialdata/http/
Added: incubator/shindig/trunk/php/src/gadgets/oauth/GadgetOAuthTokenStore.php
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/php/src/gadgets/oauth/GadgetOAuthTokenStore.php?rev=658758&view=auto
==============================================================================
--- incubator/shindig/trunk/php/src/gadgets/oauth/GadgetOAuthTokenStore.php (added)
+++ incubator/shindig/trunk/php/src/gadgets/oauth/GadgetOAuthTokenStore.php Wed May 21 09:58:52 2008
@@ -0,0 +1,283 @@
+<?php
+/*
+ * 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.
+ */
+
+class OAuthStoreException extends GadgetException {}
+
+/**
+ * Higher-level interface that allows callers to store and retrieve
+ * OAuth-related data directly from {@code GadgetSpec}s, {@code GadgetContext}s,
+ * etc. See {@link OAuthStore} for a more detailed explanation of the OAuth
+ * Data Store.
+ */
+class GadgetOAuthTokenStore {
+
+ /**
+ * Internal class used to communicate results of parsing the gadget spec
+ * between methods.
+ */
+ // name of the OAuth feature in the gadget spec
+ public static $OAUTH_FEATURE = "oauth";
+ // name of the Param that identifies the service name
+ public static $SERVICE_NAME = "service_name";
+ // name of the Param that identifies the access URL
+ public static $ACCESS_URL = "access_url";
+ // name of the optional Param that identifies the HTTP method for access URL
+ public static $ACCESS_HTTP_METHOD = "access_method";
+ // name of the Param that identifies the request URL
+ public static $REQUEST_URL = "request_url";
+ // name of the optional Param that identifies the HTTP method for request URL
+ public static $REQUEST_HTTP_METHOD = "request_method";
+ // name of the Param that identifies the user authorization URL
+ public static $AUTHORIZE_URL = "authorize_url";
+ // name of the Param that identifies the location of OAuth parameters
+ public static $OAUTH_PARAM_LOCATION = "param_location";
+ public static $AUTH_HEADER = "auth_header";
+ public static $POST_BODY = "post_body";
+ public static $URI_QUERY = "uri_query";
+
+ //public static $DEFAULT_OAUTH_PARAM_LOCATION = AUTH_HEADER;
+ public static $DEFAULT_OAUTH_PARAM_LOCATION = "auth_header"; //It has to be like the line above this.
+ //TODO: Check why java use AUTH_HEADER
+
+ // we use POST if no HTTP method is specified for access and request URLs
+ // (user authorization always uses GET)
+ public static $DEFAULT_HTTP_METHOD = "POST";
+ private $store;
+
+ /**
+ * Public constructor.
+ *
+ * @param store an {@link OAuthStore} that can store and retrieve OAuth
+ * tokens, as well as information about service providers.
+ */
+ public function __construct($store)
+ {
+ $this->store = $store;
+ }
+
+ /**
+ * Parses a gadget spec and stores the service provider information found
+ * in the spec into the OAuth store. The spec passed in <b>must</b> require
+ * "oauth" as a feature. It is an error to pass in a spec that does not
+ * require oauth.
+ *
+ * @param gadgetUrl the URL of the gadget
+ * @param spec the parsed GadgetSpec of the gadget.
+ */
+
+ public function storeServiceInfoFromGadgetSpec($gadgetUrl, Gadget $specGadget)
+ {
+ $gadgetInfo = $this->getGadgetOAuthInfo($specGadget);
+ $providerKey = new ProviderKey();
+ $providerKey->setGadgetUri($gadgetUrl);
+ $providerKey->setServiceName($gadgetInfo->getServiceName());
+ $this->store->setOAuthServiceProviderInfo($providerKey, $gadgetInfo->getProviderInfo());
+ }
+
+ /**
+ * Stores a negotiated consumer key and secret in the gadget store.
+ * The "secret" can either be a consumer secret in the strict OAuth sense,
+ * or it can be a PKCS8-then-Base64 encoded private key that we'll be using
+ * with this service provider.
+ *
+ * @param gadgetUrl the URL of the gadget
+ * @param serviceName the service provider with whom we have negotiated a
+ * consumer key and secret.
+ */
+ public function storeConsumerKeyAndSecret($gadgetUrl, $serviceName, $keyAndSecret)
+ {
+ $providerKey = new ProviderKey();
+ $providerKey->setGadgetUri($gadgetUrl);
+ $providerKey->setServiceName($serviceName);
+ $this->store->setOAuthConsumerKeyAndSecret($providerKey, $keyAndSecret);
+ }
+
+ /**
+ * Stores an access token in the OAuth Data Store.
+ * @param tokenKey information about the Gadget storing the token.
+ * @param tokenInfo the TokenInfo to be stored in the OAuth data store.
+ */
+ public function storeTokenKeyAndSecret($tokenKey, $tokenInfo)
+ {
+ $getGadgetUri = $tokenKey->getGadgetUri();
+ if (empty($getGadgetUri)) {
+ throw new Exception("found empty gadget URI in TokenKey");
+ }
+ $getServiceName = $tokenKey->getServiceName();
+ if (empty($getServiceName)) {
+ throw new Exception("found empty service name in TokenKey");
+ }
+ $getUserId = $tokenKey->getUserId();
+ if (empty($getUserId)) {
+ throw new Exception("found empty userId in TokenKey");
+ }
+ $this->store->setTokenAndSecret($tokenKey, $tokenInfo);
+ }
+
+ /**
+ * Retrieve an OAuthAccessor that is ready to sign OAuthMessages.
+ *
+ * @param tokenKey information about the gadget retrieving the accessor.
+ *
+ * @return an OAuthAccessorInfo containing an OAuthAccessor (whic can be
+ * passed to an OAuthMessage.sign method), as well as httpMethod and
+ * signatureType fields.
+ */
+ public function getOAuthAccessor(TokenKey $tokenKey)
+ {
+ $getGadgetUri = $tokenKey->getGadgetUri();
+ if (empty($getGadgetUri)) {
+ throw new OAuthStoreException("found empty gadget URI in TokenKey");
+ }
+ $getServiceName = $tokenKey->getServiceName();
+ if (empty($getServiceName)) {
+ throw new OAuthStoreException("found empty service name in TokenKey");
+ }
+ $getUserId = $tokenKey->getUserId();
+ if (empty($getUserId)) {
+ throw new OAuthStoreException("found empty userId in TokenKey");
+ }
+ return $this->store->getOAuthAccessorTokenKey($tokenKey);
+ }
+
+ /**
+ * Reads OAuth provider information out of gadget spec.
+ * @param spec
+ * @return a GadgetInfo
+ * @throws GadgetException if some information is missing, or something else
+ * is wrong with the spec.
+ */
+ public function getGadgetOAuthInfo(Gadget $specGadget)
+ {
+ $requires = $specGadget->getRequires();
+ $oauthFeature = $requires[GadgetOAuthTokenStore::$OAUTH_FEATURE];
+ if ($oauthFeature == null) {
+ $message = "gadget spec is missing oauth feature section";
+ throw new GadgetException($message);
+ }
+ $oauthParams = $oauthFeature->getParams();
+ $serviceName = $this->getOAuthParameter($oauthParams, GadgetOAuthTokenStore::$SERVICE_NAME, false);
+ $requestUrl = $this->getOAuthParameter($oauthParams, GadgetOAuthTokenStore::$REQUEST_URL, false);
+ $requestMethod = $this->getOAuthParameter($oauthParams, GadgetOAuthTokenStore::$REQUEST_HTTP_METHOD, true);
+ if (! isset($requestMethod)) {
+ $requestMethod = GadgetOAuthTokenStore::$DEFAULT_HTTP_METHOD;
+ }
+ $accessUrl = $this->getOAuthParameter($oauthParams, GadgetOAuthTokenStore::$ACCESS_URL, false);
+ $accessMethod = $this->getOAuthParameter($oauthParams, GadgetOAuthTokenStore::$ACCESS_HTTP_METHOD, true);
+ if (! isset($accessMethod)) {
+ $accessMethod = GadgetOAuthTokenStore::$DEFAULT_HTTP_METHOD;
+ }
+ if (! strtoupper($accessMethod) == strtoupper($requestMethod)) {
+ $message = "HTTP methods of access and request URLs have to match. " . "access method was: " . $accessMethod . ". request method was: " . $requestMethod;
+ throw new GadgetException($message);
+ }
+ $authorizeUrl = $this->getOAuthParameter($oauthParams, GadgetOAuthTokenStore::$AUTHORIZE_URL, false);
+ $provider = new OAuthServiceProvider($requestUrl, $authorizeUrl, $accessUrl);
+ $httpMethod = '';
+ if (strtoupper($accessMethod) == "GET") {
+ $httpMethod = "GET";
+ } else if (strtoupper($accessMethod) == "POST") {
+ $httpMethod = "POST";
+ } else {
+ $message = "unknown http method in gadget spec: " . $accessMethod;
+ throw new GadgetException($message);
+ }
+ $paramLocationStr = $this->getOAuthParameter($oauthParams, GadgetOAuthTokenStore::$OAUTH_PARAM_LOCATION, true);
+ if (! isset($paramLocationStr)) {
+ $paramLocationStr = GadgetOAuthTokenStore::$DEFAULT_OAUTH_PARAM_LOCATION;
+ }
+ $paramLocation = '';
+ if (strtoupper($paramLocationStr) == strtoupper(GadgetOAuthTokenStore::$POST_BODY)) {
+ $paramLocation = GadgetOAuthTokenStore::$POST_BODY;
+ } else if (strtoupper($paramLocationStr) == strtoupper(GadgetOAuthTokenStore::$AUTH_HEADER)) {
+ $paramLocation = GadgetOAuthTokenStore::$AUTH_HEADER;
+ } else if (strtoupper($paramLocationStr) == strtoupper(GadgetOAuthTokenStore::$URI_QUERY)) {
+ $paramLocation = GadgetOAuthTokenStore::$URI_QUERY;
+ } else {
+ $message = "unknown OAuth param location in gadget spec: " . $paramLocationStr;
+ throw new GadgetException($message);
+ }
+ if ($httpMethod == "GET" && $paramLocation == GadgetOAuthTokenStore::$POST_BODY) {
+ $message = "found incompatible param_location requirement of POST_BODY and http method GET.";
+ throw new GadgetException($message);
+ }
+ $provInfo = new ProviderInfo();
+ $provInfo->setHttpMethod($httpMethod);
+ $provInfo->setParamLocation($paramLocation);
+
+ // TODO: for now, we'll just set the signature type to HMAC_SHA1
+ // as this will be ignored later on when retrieving consumer information.
+ // There, if we find a negotiated HMAC key, we will use HMAC_SHA1. If we
+ // find a negotiated RSA key, we will use RSA_SHA1. And if we find neither,
+ // we may use RSA_SHA1 with a default signing key.
+ $provInfo->setSignatureType('HMAC_SHA1');
+ $provInfo->setProvider($provider);
+ $gadgetInfo = new GadgetInfo();
+ $gadgetInfo->setProviderInfo($provInfo);
+ $gadgetInfo->setServiceName($serviceName);
+ return $gadgetInfo;
+ }
+
+ /**
+ * Extracts a single oauth-related parameter from a key-value map,
+ * throwing an exception if the parameter could not be found (unless the
+ * parameter is optional, in which case null is returned).
+ *
+ * @param params the key-value map from which to pull the value (parameter)
+ * @param paramName the name of the parameter (key).
+ * @param isOptional if it's optional, don't throw an exception if it's not
+ * found.
+ * @return the value corresponding to the key (paramName)
+ * @throws GadgetException if the parameter value couldn't be found.
+ */
+ static function getOAuthParameter($params, $paramName, $isOptional)
+ {
+ $param = @$params[$paramName];
+ if ($param == null && !$isOptional) {
+ $message = "parameter '" . $paramName . "' missing in oauth feature section of gadget spec";
+ throw new GadgetException($message);
+ }
+ return ($param == null) ? null : trim($param);
+ }
+}
+
+class GadgetInfo {
+ private $serviceName;
+ private $providerInfo;
+
+ public function getServiceName()
+ {
+ return $this->serviceName;
+ }
+
+ public function setServiceName($serviceName)
+ {
+ $this->serviceName = $serviceName;
+ }
+
+ public function getProviderInfo()
+ {
+ return $this->providerInfo;
+ }
+
+ public function setProviderInfo($providerInfo)
+ {
+ $this->providerInfo = $providerInfo;
+ }
+}
Added: incubator/shindig/trunk/php/src/gadgets/oauth/OAuth.php
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/php/src/gadgets/oauth/OAuth.php?rev=658758&view=auto
==============================================================================
--- incubator/shindig/trunk/php/src/gadgets/oauth/OAuth.php (added)
+++ incubator/shindig/trunk/php/src/gadgets/oauth/OAuth.php Wed May 21 09:58:52 2008
@@ -0,0 +1,842 @@
+<?php
+/*
+ * 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.
+ */
+
+class OAuth {
+ public static $VERSION_1_0 = "1.0";
+ public static $ENCODING = "UTF-8";
+ public static $FORM_ENCODED = "application/x-www-form-urlencoded";
+ public static $OAUTH_CONSUMER_KEY = "oauth_consumer_key";
+ public static $OAUTH_TOKEN = "oauth_token";
+ public static $OAUTH_TOKEN_SECRET = "oauth_token_secret";
+ public static $OAUTH_SIGNATURE_METHOD = "oauth_signature_method";
+ public static $OAUTH_SIGNATURE = "oauth_signature";
+ public static $OAUTH_TIMESTAMP = "oauth_timestamp";
+ public static $OAUTH_NONCE = "oauth_nonce";
+ public static $OAUTH_VERSION = "oauth_version";
+ public static $HMAC_SHA1 = "HMAC_SHA1";
+ public static $RSA_SHA1 = "RSA_SHA1";
+}
+
+/* Generic exception class
+ */
+class OAuthException extends Exception {}
+
+class OAuthConsumer {
+ public $key;
+ public $secret;
+ public $callback_url;
+ private $properties = array();
+
+ function __construct($key, $secret, $callback_url = NULL)
+ {
+ $this->key = $key;
+ $this->secret = $secret;
+ $this->callback_url = $callback_url;
+ }
+
+ public function getProperty($name)
+ {
+ return $this->properties[$name];
+ }
+
+ public function setProperty($name, $value)
+ {
+ $this->properties[$name] = $value;
+ }
+
+}
+
+class OAuthToken {
+ // access tokens and request tokens
+ public $key;
+ public $secret;
+
+ /**
+ * key = the token
+ * secret = the token secret
+ */
+ function __construct($key, $secret)
+ {
+ $this->key = $key;
+ $this->secret = $secret;
+ }
+
+ /**
+ * generates the basic string serialization of a token that a server
+ * would respond to request_token and access_token calls with
+ */
+ function to_string()
+ {
+ return "oauth_token=" . OAuthUtil::urlencodeRFC3986($this->key) . "&oauth_token_secret=" . OAuthUtil::urlencodeRFC3986($this->secret);
+ }
+
+ function __toString()
+ {
+ return $this->to_string();
+ }
+}
+
+class OAuthSignatureMethod {
+
+ public function check_signature(&$request, $consumer, $token, $signature)
+ {
+ $built = $this->build_signature($request, $consumer, $token);
+ return $built == $signature;
+ }
+}
+
+class OAuthSignatureMethod_HMAC_SHA1 extends OAuthSignatureMethod {
+
+ function get_name()
+ {
+ return "HMAC-SHA1";
+ }
+
+ public function build_signature($request, $consumer, $token)
+ {
+ $base_string = $request->get_signature_base_string();
+ $request->base_string = $base_string;
+ $key_parts = array($consumer->secret, (isset($token)) ? $token : "");
+ $key_parts = array_map(array('OAuthUtil', 'urlencodeRFC3986'), $key_parts);
+ $key = implode('&', $key_parts);
+ return base64_encode(hash_hmac('sha1', $base_string, $key, true));
+ }
+}
+
+class OAuthSignatureMethod_PLAINTEXT extends OAuthSignatureMethod {
+
+ public function get_name()
+ {
+ return "PLAINTEXT";
+ }
+
+ public function build_signature($request, $consumer, $token)
+ {
+ $sig = array(OAuthUtil::urlencodeRFC3986($consumer->secret));
+ if ($token) {
+ array_push($sig, OAuthUtil::urlencodeRFC3986($token->secret));
+ } else {
+ array_push($sig, '');
+ }
+ $raw = implode("&", $sig);
+ // for debug purposes
+ $request->base_string = $raw;
+ return OAuthUtil::urlencodeRFC3986($raw);
+ }
+}
+
+class OAuthSignatureMethod_RSA_SHA1 extends OAuthSignatureMethod {
+ public static $PRIVATE_KEY = "RSA-SHA1.PrivateKey";
+
+ public function get_name()
+ {
+ return "RSA-SHA1";
+ }
+
+ protected function fetch_public_cert(&$request)
+ {
+ // not implemented yet, ideas are:
+ // (1) do a lookup in a table of trusted certs keyed off of consumer
+ // (2) fetch via http using a url provided by the requester
+ // (3) some sort of specific discovery code based on request
+ //
+ // either way should return a string representation of the certificate
+ throw Exception("fetch_public_cert not implemented");
+ }
+
+ protected function fetch_private_cert(&$request)
+ {
+ // not implemented yet, ideas are:
+ // (1) do a lookup in a table of trusted certs keyed off of consumer
+ //
+ // either way should return a string representation of the certificate
+ throw new Exception("fetch_private_cert not implemented");
+ }
+
+ public function build_signature(&$request, OAuthConsumer $consumer, $token)
+ {
+ $base_string = $request->get_signature_base_string();
+ // Fetch the private key cert based on the request
+ $cert = $consumer->getProperty("RSA-SHA1.PrivateKey");
+ // Pull the private key ID from the certificate
+ //FIXME this function seems to be called both for a oauth.json action where
+ // there is no phrase required, but for signed requests too, which do require it
+ // this is a dirty hack to make it work .. kinda
+ if (!$privatekeyid = @openssl_pkey_get_private($cert)) {
+ if (!$privatekeyid = @openssl_pkey_get_private($cert, Config::get('private_key_phrase') != '' ? (Config::get('private_key_phrase')) : null)) {
+ throw new Exception("Could not load private key");
+ }
+ }
+ // Sign using the key
+ $ok = openssl_sign($base_string, $signature, $privatekeyid);
+ // Release the key resource
+ openssl_free_key($privatekeyid);
+ return base64_encode($signature);
+ }
+
+ public function check_signature(&$request, $consumer, $token, $signature)
+ {
+ $decoded_sig = base64_decode($signature);
+ $base_string = $request->get_signature_base_string();
+ // Fetch the public key cert based on the request
+ $cert = $this->fetch_public_cert($request);
+ // Pull the public key ID from the certificate
+ $publickeyid = openssl_get_publickey($cert);
+ // Check the computed signature against the one passed in the query
+ $ok = openssl_verify($base_string, $decoded_sig, $publickeyid);
+ // Release the key resource
+ openssl_free_key($publickeyid);
+ return $ok == 1;
+ }
+}
+
+class OAuthRequest {
+ private $parameters;
+ private $http_method;
+ private $http_url;
+ public $base_string;
+ public static $version = '1.0';
+
+ function __construct($http_method, $http_url, $parameters = NULL)
+ {
+ @$parameters or $parameters = array();
+ $this->parameters = $parameters;
+ $this->http_method = $http_method;
+ $this->http_url = $http_url;
+ }
+
+ /**
+ * attempt to build up a request from what was passed to the server
+ */
+ public static function from_request($http_method = NULL, $http_url = NULL, $parameters = NULL)
+ {
+ $scheme = (! isset($_SERVER['HTTPS']) || $_SERVER['HTTPS'] != "on") ? 'http' : 'https';
+ @$http_url or $http_url = $scheme . '://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
+ @$http_method or $http_method = $_SERVER['REQUEST_METHOD'];
+ $request_headers = OAuthRequest::get_headers();
+ // let the library user override things however they'd like, if they know
+ // which parameters to use then go for it, for example XMLRPC might want to
+ // do this
+ if ($parameters) {
+ $req = new OAuthRequest($http_method, $http_url, $parameters);
+ } elseif (@substr($request_headers['Authorization'], 0, 5) == "OAuth") {
+ // next check for the auth header, we need to do some extra stuff
+ // if that is the case, namely suck in the parameters from GET or POST
+ // so that we can include them in the signature
+ $header_parameters = OAuthRequest::split_header($request_headers['Authorization']);
+ if ($http_method == "GET") {
+ $req_parameters = $_GET;
+ } else if ($http_method = "POST") {
+ $req_parameters = $_POST;
+ }
+ $parameters = array_merge($header_parameters, $req_parameters);
+ $req = new OAuthRequest($http_method, $http_url, $parameters);
+ } elseif ($http_method == "GET") {
+ $req = new OAuthRequest($http_method, $http_url, $_GET);
+ } elseif ($http_method == "POST") {
+ $req = new OAuthRequest($http_method, $http_url, $_POST);
+ }
+ return $req;
+ }
+
+ /**
+ * pretty much a helper function to set up the request
+ */
+ public static function from_consumer_and_token($consumer, $token, $http_method, $http_url, $parameters = NULL)
+ {
+ @$parameters or $parameters = array();
+ $defaults = array("oauth_nonce" => OAuthRequest::generate_nonce(), "oauth_timestamp" => OAuthRequest::generate_timestamp(), "oauth_consumer_key" => $consumer->key);
+ $parameters = array_merge($defaults, $parameters);
+ if (isset($token)) {
+ $parameters['oauth_token'] = $token;
+ }
+ return new OAuthRequest($http_method, $http_url, $parameters);
+ }
+
+ public function set_parameter($name, $value)
+ {
+ $this->parameters[$name] = $value;
+ }
+
+ public function get_parameter($name)
+ {
+ return @$this->parameters[$name];
+ }
+
+ public function get_parameters()
+ {
+ return $this->parameters;
+ }
+
+ public function set_parameters($params)
+ {
+ $arrParams = array();
+ foreach ($params as $param) {
+ $keyValuePair = explode('=', $param);
+ $arrParams[$keyValuePair[0]] = @$keyValuePair[1];
+ }
+ return $this->parameters = $arrParams;
+ }
+
+ //TODO double check if hash can be used
+ public function requireParameters($names)
+ {
+ $present = $this->parameters;
+ $absent = array();
+ foreach ($names as $required) {
+ if (! in_array($required, $present)) {
+ $absent[] = $required;
+ }
+ }
+ if (count($absent) == 0) {
+ throw new OAuthProblemException("oauth_parameters_absent: " . OAuthUtil::urlencodeRFC3986($absent));
+ }
+ }
+
+ /**
+ * Returns the normalized parameters of the request
+ *
+ * This will be all (except oauth_signature) parameters,
+ * sorted first by key, and if duplicate keys, then by
+ * value.
+ *
+ * The returned string will be all the key=value pairs
+ * concated by &.
+ *
+ * @return string
+ */
+ public function get_signable_parameters()
+ {
+ // Grab all parameters
+ $params = $this->parameters;
+ // Remove oauth_signature if present
+ if (isset($params['oauth_signature'])) {
+ unset($params['oauth_signature']);
+ }
+ // Urlencode both keys and values
+ $keys = array_map(array('OAuthUtil', 'urlencodeRFC3986'), array_keys($params));
+ $values = array_map(array('OAuthUtil', 'urlencodeRFC3986'), array_values($params));
+ $params = array_combine($keys, $values);
+ // Sort by keys (natsort)
+ uksort($params, 'strnatcmp');
+ // Generate key=value pairs
+ $pairs = array();
+ foreach ($params as $key => $value) {
+ if (is_array($value)) {
+ // If the value is an array, it's because there are multiple
+ // with the same key, sort them, then add all the pairs
+ natsort($value);
+ foreach ($value as $v2) {
+ $pairs[] = $key . '=' . $v2;
+ }
+ } else {
+ $pairs[] = $key . '=' . $value;
+ }
+ }
+ // Return the pairs, concated with &
+ return implode('&', $pairs);
+ }
+
+ /**
+ * Returns the base string of this request
+ *
+ * The base string defined as the method, the url
+ * and the parameters (normalized), each urlencoded
+ * and the concated with &.
+ */
+ public function get_signature_base_string()
+ {
+ $tmp = $this->parameters;
+ $parts = parse_url($this->http_url);
+ $params = split('[&=]', @$parts['query']);
+ if (count($params) > 1) {
+ for ($i = 0; $i < count($params); $i += 2) {
+ $this->parameters[$params[$i]] = urldecode($params[$i + 1]);
+ }
+ }
+ $parts = array($this->get_normalized_http_method(), $this->get_normalized_http_url(), $this->get_signable_parameters());
+ $parts = array_map(array('OAuthUtil', 'urlencodeRFC3986'), $parts);
+ $this->parameters = $tmp;
+ return implode('&', $parts);
+ }
+
+ /**
+ * just uppercases the http method
+ */
+ public function get_normalized_http_method()
+ {
+ return strtoupper($this->http_method);
+ }
+
+ /**
+ * parses the url and rebuilds it to be
+ * scheme://host/path
+ */
+ public function get_normalized_http_url()
+ {
+ $parts = parse_url($this->http_url);
+ // FIXME: port should handle according to http://groups.google.com/group/oauth/browse_thread/thread/1b203a51d9590226
+ $port = (isset($parts['port']) && $parts['port'] != '80') ? ':' . $parts['port'] : '';
+ $path = (isset($parts['path'])) ? $parts['path'] : '';
+
+ return $parts['scheme'] . '://' . $parts['host'] . $port . $path;
+ }
+
+ /**
+ * builds a url usable for a GET request
+ */
+ public function to_url()
+ {
+ $out = $this->get_normalized_http_url() . "?";
+ $out .= $this->to_postdata();
+ $parts = parse_url($this->http_url);
+ $out .= "&" . @$parts['query'];
+ return $out;
+ }
+
+ public function get_url()
+ {
+ return $this->http_url;
+ }
+
+ /**
+ * builds the data one would send in a POST request
+ */
+ public function to_postdata()
+ {
+ $total = array();
+ foreach ($this->parameters as $k => $v) {
+ $total[] = OAuthUtil::urlencodeRFC3986($k) . "=" . OAuthUtil::urlencodeRFC3986($v);
+ }
+ $out = implode("&", $total);
+ return $out;
+ }
+
+ /**
+ * builds the Authorization: header
+ */
+ public function to_header()
+ {
+ $out = '"Authorization: OAuth realm="",';
+ $total = array();
+ foreach ($this->parameters as $k => $v) {
+ if (substr($k, 0, 5) != "oauth")
+ continue;
+ $out .= ',' . OAuthUtil::urlencodeRFC3986($k) . '="' . OAuthUtil::urlencodeRFC3986($v) . '"';
+ }
+ return $out;
+ }
+
+ public function __toString()
+ {
+ return $this->to_url();
+ }
+
+ public function sign_request($signature_method, $consumer, $token)
+ {
+ $this->set_parameter("oauth_signature_method", $signature_method->get_name());
+ $signature = $this->build_signature($signature_method, $consumer, $token);
+ $this->set_parameter("oauth_signature", $signature);
+ }
+
+ public function build_signature($signature_method, $consumer, $token)
+ {
+ $signature = $signature_method->build_signature($this, $consumer, $token);
+ return $signature;
+ }
+
+ /**
+ * util function: current timestamp
+ */
+ private static function generate_timestamp()
+ {
+ return time();
+ }
+
+ /**
+ * util function: current nonce
+ */
+ public static function generate_nonce()
+ {
+ $mt = microtime();
+ $rand = mt_rand();
+ return md5($mt . $rand); // md5s look nicer than numbers
+ }
+
+ /**
+ * util function for turning the Authorization: header into
+ * parameters, has to do some unescaping
+ */
+ private static function split_header($header)
+ {
+ // this should be a regex
+ // error cases: commas in parameter values
+ $parts = explode(",", $header);
+ $out = array();
+ foreach ($parts as $param) {
+ $param = ltrim($param);
+ // skip the "realm" param, nobody ever uses it anyway
+ if (substr($param, 0, 5) != "oauth")
+ continue;
+ $param_parts = explode("=", $param);
+ // rawurldecode() used because urldecode() will turn a "+" in the
+ // value into a space
+ $out[$param_parts[0]] = rawurldecode(substr($param_parts[1], 1, - 1));
+ }
+ return $out;
+ }
+
+ /**
+ * helper to try to sort out headers for people who aren't running apache
+ */
+ private static function get_headers()
+ {
+ if (function_exists('apache_request_headers')) {
+ // we need this to get the actual Authorization: header
+ // because apache tends to tell us it doesn't exist
+ return apache_request_headers();
+ }
+ // otherwise we don't have apache and are just going to have to hope
+ // that $_SERVER actually contains what we need
+ $out = array();
+ foreach ($_SERVER as $key => $value) {
+ if (substr($key, 0, 5) == "HTTP_") {
+ // this is chaos, basically it is just there to capitalize the first
+ // letter of every word that is not an initial HTTP and strip HTTP
+ // code from przemek
+ $key = str_replace(" ", "-", ucwords(strtolower(str_replace("_", " ", substr($key, 5)))));
+ $out[$key] = $value;
+ }
+ }
+ return $out;
+ }
+}
+
+class OAuthServer {
+ protected $timestamp_threshold = 300; // in seconds, five minutes
+ protected $version = 1.0; // hi blaine
+ protected $signature_methods = array();
+ protected $data_store;
+
+ function __construct($data_store)
+ {
+ $this->data_store = $data_store;
+ }
+
+ public function add_signature_method($signature_method)
+ {
+ $this->signature_methods[$signature_method->get_name()] = $signature_method;
+ }
+
+ // high level functions
+ /**
+ * process a request_token request
+ * returns the request token on success
+ */
+ public function fetch_request_token(&$request)
+ {
+ $this->get_version($request);
+ $consumer = $this->get_consumer($request);
+ // no token required for the initial token request
+ $token = NULL;
+ $this->check_signature($request, $consumer, $token);
+ $new_token = $this->data_store->new_request_token($consumer);
+ return $new_token;
+ }
+
+ /**
+ * process an access_token request
+ * returns the access token on success
+ */
+ public function fetch_access_token(&$request)
+ {
+ $this->get_version($request);
+ $consumer = $this->get_consumer($request);
+ // requires authorized request token
+ $token = $this->get_token($request, $consumer, "request");
+ $this->check_signature($request, $consumer, $token);
+ $new_token = $this->data_store->new_access_token($token, $consumer);
+ return $new_token;
+ }
+
+ /**
+ * verify an api call, checks all the parameters
+ */
+ public function verify_request(&$request)
+ {
+ $this->get_version($request);
+ $consumer = $this->get_consumer($request);
+ $token = $this->get_token($request, $consumer, "access");
+ $this->check_signature($request, $consumer, $token);
+ return array($consumer, $token);
+ }
+
+ // Internals from here
+ /**
+ * version 1
+ */
+ private function get_version(&$request)
+ {
+ $version = $request->get_parameter("oauth_version");
+ if (! $version) {
+ $version = 1.0;
+ }
+ if ($version && $version != $this->version) {
+ throw new OAuthException("OAuth version '$version' not supported");
+ }
+ return $version;
+ }
+
+ /**
+ * figure out the signature with some defaults
+ */
+ private function get_signature_method(&$request)
+ {
+ $signature_method = @$request->get_parameter("oauth_signature_method");
+ if (! $signature_method) {
+ $signature_method = "PLAINTEXT";
+ }
+ if (! in_array($signature_method, array_keys($this->signature_methods))) {
+ throw new OAuthException("Signature method '$signature_method' not supported try one of the following: " . implode(", ", array_keys($this->signature_methods)));
+ }
+ return $this->signature_methods[$signature_method];
+ }
+
+ /**
+ * try to find the consumer for the provided request's consumer key
+ */
+ private function get_consumer(&$request)
+ {
+ $consumer_key = @$request->get_parameter("oauth_consumer_key");
+ if (! $consumer_key) {
+ throw new OAuthException("Invalid consumer key");
+ }
+ $consumer = $this->data_store->lookup_consumer($consumer_key);
+ if (! $consumer) {
+ throw new OAuthException("Invalid consumer");
+ }
+ return $consumer;
+ }
+
+ /**
+ * try to find the token for the provided request's token key
+ */
+ private function get_token(&$request, $consumer, $token_type = "access")
+ {
+ $token_field = @$request->get_parameter('oauth_token');
+ $token = $this->data_store->lookup_token($consumer, $token_type, $token_field);
+ if (! $token) {
+ throw new OAuthException("Invalid $token_type token: $token_field");
+ }
+ return $token;
+ }
+
+ /**
+ * all-in-one function to check the signature on a request
+ * should guess the signature method appropriately
+ */
+ private function check_signature(&$request, $consumer, $token)
+ {
+ // this should probably be in a different method
+ $timestamp = @$request->get_parameter('oauth_timestamp');
+ $nonce = @$request->get_parameter('oauth_nonce');
+ $this->check_timestamp($timestamp);
+ $this->check_nonce($consumer, $token, $nonce, $timestamp);
+ $signature_method = $this->get_signature_method($request);
+ $signature = $request->get_parameter('oauth_signature');
+ $valid_sig = $signature_method->check_signature($request, $consumer, $token, $signature);
+ if (! $valid_sig) {
+ throw new OAuthException("Invalid signature");
+ }
+ }
+
+ /**
+ * check that the timestamp is new enough
+ */
+ private function check_timestamp($timestamp)
+ {
+ // verify that timestamp is recentish
+ $now = time();
+ if ($now - $timestamp > $this->timestamp_threshold) {
+ throw new OAuthException("Expired timestamp, yours $timestamp, ours $now");
+ }
+ }
+
+ /**
+ * check that the nonce is not repeated
+ */
+ private function check_nonce($consumer, $token, $nonce, $timestamp)
+ {
+ // verify that the nonce is uniqueish
+ $found = $this->data_store->lookup_nonce($consumer, $token, $nonce, $timestamp);
+ if ($found) {
+ throw new OAuthException("Nonce already used: $nonce");
+ }
+ }
+}
+
+class OAuthDataStore {
+
+ function lookup_consumer($consumer_key)
+ { // implement me
+ }
+
+ function lookup_token($consumer, $token_type, $token)
+ { // implement me
+ }
+
+ function lookup_nonce($consumer, $token, $nonce, $timestamp)
+ { // implement me
+ }
+
+ function fetch_request_token($consumer)
+ { // return a new token attached to this consumer
+ }
+
+ function fetch_access_token($token, $consumer)
+ { // return a new access token attached to this consumer
+ // for the user associated with this token if the request token
+ // is authorized
+ // should also invalidate the request token
+ }
+}
+
+/* A very naive dbm-based oauth storage
+ */
+class SimpleOAuthDataStore extends OAuthDataStore {
+ private $dbh;
+
+ function __construct($path = "oauth.gdbm")
+ {
+ $this->dbh = dba_popen($path, 'c', 'gdbm');
+ }
+
+ function __destruct()
+ {
+ dba_close($this->dbh);
+ }
+
+ function lookup_consumer($consumer_key)
+ {
+ $rv = dba_fetch("consumer_$consumer_key", $this->dbh);
+ if ($rv === FALSE) {
+ return NULL;
+ }
+ $obj = unserialize($rv);
+ if (! ($obj instanceof OAuthConsumer)) {
+ return NULL;
+ }
+ return $obj;
+ }
+
+ function lookup_token($consumer, $token_type, $token)
+ {
+ $rv = dba_fetch("${token_type}_${token}", $this->dbh);
+ if ($rv === FALSE) {
+ return NULL;
+ }
+ $obj = unserialize($rv);
+ if (! ($obj instanceof OAuthToken)) {
+ return NULL;
+ }
+ return $obj;
+ }
+
+ function lookup_nonce($consumer, $token, $nonce, $timestamp)
+ {
+ if (dba_exists("nonce_$nonce", $this->dbh)) {
+ return TRUE;
+ } else {
+ dba_insert("nonce_$nonce", "1", $this->dbh);
+ return FALSE;
+ }
+ }
+
+ function new_token($consumer, $type = "request")
+ {
+ $key = md5(time());
+ $secret = time() + time();
+ $token = new OAuthToken($key, md5(md5($secret)));
+ if (! dba_insert("${type}_$key", serialize($token), $this->dbh)) {
+ throw new OAuthException("doooom!");
+ }
+ return $token;
+ }
+
+ function new_request_token($consumer)
+ {
+ return $this->new_token($consumer, "request");
+ }
+
+ function new_access_token($token, $consumer)
+ {
+ $token = $this->new_token($consumer, 'access');
+ dba_delete("request_" . $token->key, $this->dbh);
+ return $token;
+ }
+}
+
+class OAuthUtil {
+
+ public static function urlencodeRFC3986($string)
+ {
+ return str_replace('%7E', '~', rawurlencode($string));
+ }
+
+ public static function urldecodeRFC3986($string)
+ {
+ return rawurldecode($string);
+ }
+
+ /** Return true if the given Content-Type header means FORM_ENCODED. */
+ public static function isFormEncoded($contentType)
+ {
+ if (! isset($contentType)) {
+ return false;
+ }
+ $semi = strstr($contentType, ";");
+ if ($semi >= 0) {
+ $contentType = substr($contentType, 0, $semi);
+ }
+ return strtolower(OAuth::$FORM_ENCODED) == strtolower(trim($contentType));
+ }
+
+ //TODO review foreach, use array_map
+ public static function addParameters($url, $oauthParams)
+ {
+ $url .= strchr($url, '?') === false ? '?' : '&';
+ foreach ($oauthParams as $key => $value) {
+ $url .= "$key=$value&";
+ }
+ return $url;
+ }
+
+ public static function decodeForm($form)
+ {
+ $explodedForm = explode("&", $form);
+
+ foreach ($explodedForm as $value) {
+ $value = OAuthUtil::urlencodeRFC3986($value);
+ }
+
+ return $explodedForm;
+ }
+
+}
\ No newline at end of file
Added: incubator/shindig/trunk/php/src/gadgets/oauth/OAuthAccessor.php
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/php/src/gadgets/oauth/OAuthAccessor.php?rev=658758&view=auto
==============================================================================
--- incubator/shindig/trunk/php/src/gadgets/oauth/OAuthAccessor.php (added)
+++ incubator/shindig/trunk/php/src/gadgets/oauth/OAuthAccessor.php Wed May 21 09:58:52 2008
@@ -0,0 +1,70 @@
+<?php
+/*
+ * 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.
+ */
+
+class OAuthAccessor {
+ public $consumer;
+ public $requestToken;
+ public $accessToken;
+ public $tokenSecret;
+ private $properties = array();
+
+ public function __construct(OAuthConsumer $consumer)
+ {
+ $this->consumer = $consumer;
+ $this->requestToken = null;
+ $this->accessToken = null;
+ $this->tokenSecret = null;
+ }
+
+ public function getProperty($name)
+ {
+ return $this->properties[$name];
+ }
+
+ public function setProperty($name, $value)
+ {
+ $this->properties[$name] = $value;
+ }
+
+ public function newRequestMessage($method, $url, $parameters)
+ {
+ if (! isset($method)) {
+ $method = $this->getProperty("httpMethod");
+ if ($method == null) {
+ $method = $this->consumer->getProperty("httpMethod");
+ if ($method == null) {
+ $method = "GET";
+ }
+ }
+ }
+ $message = OAuthRequest::from_consumer_and_token($this->consumer, $this->accessToken, $method, $url, $parameters);
+ $signatureMethod = null;
+ if ($parameters[OAuth::$OAUTH_SIGNATURE_METHOD] == OAuth::$RSA_SHA1) {
+ $signatureMethod = new OAuthSignatureMethod_RSA_SHA1();
+ } else if ($parameters[OAuth::$OAUTH_SIGNATURE_METHOD] == OAuth::$HMAC_SHA1) {
+ $signatureMethod = new OAuthSignatureMethod_HMAC_SHA1();
+ } else { //PLAINTEXT
+ $signatureMethod = new OAuthSignatureMethod_PLAINTEXT();
+ }
+ $message->sign_request($signatureMethod, $this->consumer, $this->tokenSecret);
+ return $message;
+ }
+
+}
\ No newline at end of file
Added: incubator/shindig/trunk/php/src/gadgets/oauth/OAuthFetcher.php
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/php/src/gadgets/oauth/OAuthFetcher.php?rev=658758&view=auto
==============================================================================
--- incubator/shindig/trunk/php/src/gadgets/oauth/OAuthFetcher.php (added)
+++ incubator/shindig/trunk/php/src/gadgets/oauth/OAuthFetcher.php Wed May 21 09:58:52 2008
@@ -0,0 +1,508 @@
+<?php
+/*
+ * 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.
+ */
+
+/**
+ * Implements the OAuth dance (http://oauth.net/core/1.0/) for gadgets.
+ *
+ * Reading the example in the appendix to the OAuth spec will be helpful to
+ * those reading this code.
+ *
+ * This class is not thread-safe; create a new one for each request that
+ * requires OAuth signing.
+ */
+class OAuthFetcher extends RemoteContentFetcher {
+
+ // We store some blobs of data on the client for later reuse; the blobs
+ // contain key/value pairs, and these are the key names.
+ private static $REQ_TOKEN_KEY = "r";
+ private static $REQ_TOKEN_SECRET_KEY = "rs";
+ private static $ACCESS_TOKEN_KEY = "a";
+ private static $ACCESS_TOKEN_SECRET_KEY = "as";
+ private static $OWNER_KEY = "o";
+
+ // names for the JSON values we return to the client
+ public static $CLIENT_STATE = "oauthState";
+ public static $APPROVAL_URL = "approvalUrl";
+
+ /**
+ * Maximum age for our client state; if this is exceeded we start over. One
+ * hour is a fairly arbitrary time limit here.
+ */
+ private static $CLIENT_STATE_MAX_AGE_SECS = 3600;
+
+ /**
+ * The gadget security token, with info about owner/viewer/gadget.
+ */
+ protected $authToken;
+
+ /**
+ * The gadget's nickname for the service provider.
+ */
+ protected $serviceName;
+
+ /**
+ * The gadget's nickname for the token.
+ */
+ protected $tokenName;
+
+ /**
+ * Reference to our persistent store for OAuth metadata.
+ */
+ protected $tokenStore;
+
+ /**
+ * The accessor we use for signing messages. This also holds metadata about
+ * the service provider, such as their URLs and the keys we use to access
+ * those URLs.
+ */
+ private $accessorInfo;
+
+ /**
+ * We use this to encrypt and sign the state we cache on the client.
+ */
+ private $oauthCrypter;
+
+ /**
+ * State the client sent with their request.
+ */
+ private $origClientState = array();
+
+ /**
+ * The request the client really wants to make.
+ */
+ private $realRequest;
+
+ /**
+ * State to cache on the client.
+ */
+ private $newClientState;
+
+ /**
+ * Authorization URL for the client
+ */
+ private $aznUrl;
+
+ /**
+ *
+ * @param oauthCrypter used to encrypt transient information we store on the
+ * client.
+ * @param authToken user's gadget security token
+ * @param params OAuth fetch parameters sent from makeRequest
+ * @param tokenStore storage for long lived tokens.
+ */
+ public function __construct($tokenStore, $oauthCrypter, $nextFetcher, $authToken, OAuthRequestParams $params)
+ {
+ parent::setNextFetcher($nextFetcher);
+ $this->oauthCrypter = $oauthCrypter;
+ $this->authToken = $authToken;
+ $this->serviceName = $params->getServiceName();
+ $this->tokenName = $params->getTokenName();
+ $this->newClientState = null;
+ $this->aznUrl = null;
+ $origClientState = $params->getOrigClientState();
+ if ($origClientState != null && strlen($origClientState) > 0) {
+ try {
+ $this->origClientState = $this->oauthCrypter->unwrap($origClientState, OAuthFetcher::$CLIENT_STATE_MAX_AGE_SECS);
+ } catch (BlobCrypterException $e) { // Probably too old, pretend we never saw it at all.
+ }
+ }
+ if ($this->origClientState == null) {
+ $this->origClientState = array();
+ }
+ $this->tokenStore = $tokenStore;
+ }
+
+ public function init()
+ {
+ $this->lookupOAuthMetadata();
+ }
+
+ /**
+ * Retrieves metadata from our persistent store.
+ *
+ * @throws GadgetException
+ */
+ protected function lookupOAuthMetadata()
+ {
+ $tokenKey = $this->buildTokenKey();
+ $this->accessorInfo = $this->tokenStore->getOAuthAccessor($tokenKey);
+ // The persistent data store may be out of sync with reality; we trust
+ // the state we stored on the client to be accurate.
+ $accessor = $this->accessorInfo->getAccessor();
+ if (isset($this->origClientState[OAuthFetcher::$REQ_TOKEN_KEY])) {
+ $accessor->requestToken = $this->origClientState[OAuthFetcher::$REQ_TOKEN_KEY];
+ $accessor->tokenSecret = $this->origClientState[OAuthFetcher::$REQ_TOKEN_SECRET_KEY];
+ } else if (isset($this->origClientState[OAuthFetcher::$ACCESS_TOKEN_KEY])) {
+ $accessor->accessToken = $this->origClientState[OAuthFetcher::$ACCESS_TOKEN_KEY];
+ $accessor->tokenSecret = $this->origClientState[OAuthFetcher::$ACCESS_TOKEN_SECRET_KEY];
+ }
+ }
+
+ private function buildTokenKey()
+ {
+ $tokenKey = new TokenKey();
+ // need to URLDecode so when comparing with the ProviderKey it goes thought
+ $tokenKey->setGadgetUri(urldecode($this->authToken->getAppUrl()));
+ $tokenKey->setModuleId($this->authToken->getModuleId());
+ $tokenKey->setServiceName($this->serviceName);
+ $tokenKey->setTokenName($this->tokenName);
+ // At some point we might want to let gadgets specify whether to use OAuth
+ // for the owner, the viewer, or someone else. For now always using the
+ // owner identity seems reasonable.
+ $tokenKey->setUserId($this->authToken->getOwnerId());
+ return $tokenKey;
+ }
+
+ public function fetchRequest($request)
+ {
+ $this->realRequest = $request;
+ if ($this->needApproval()) {
+ // This is section 6.1 of the OAuth spec.
+ $this->checkCanApprove();
+ $this->fetchRequestToken();
+ // This is section 6.2 of the OAuth spec.
+ $this->buildClientApprovalState();
+ $this->buildAznUrl();
+ // break out of the content fetching chain, we need permission from
+ // the user to do this
+ return null;
+ } elseif ($this->needAccessToken()) {
+ // This is section 6.3 of the OAuth spec
+ $this->checkCanApprove();
+ $this->exchangeRequestToken();
+ $this->saveAccessToken();
+ $this->buildClientAccessState();
+ }
+ return $this->fetchData();
+ }
+
+ /**
+ * Do we need to get the user's approval to access the data?
+ */
+ private function needApproval()
+ {
+ return ($this->accessorInfo->getAccessor()->requestToken == null && $this->accessorInfo->getAccessor()->accessToken == null);
+ }
+
+ /**
+ * Make sure the user is authorized to approve access tokens. At the moment
+ * we restrict this to page owner's viewing their own pages.
+ *
+ * @throws GadgetException
+ */
+ private function checkCanApprove()
+ {
+ $pageOwner = $this->authToken->getOwnerId();
+ $pageViewer = $this->authToken->getViewerId();
+ $stateOwner = @$this->origClientState[OAuthFetcher::$OWNER_KEY];
+ if (! $pageOwner == $pageViewer) {
+ throw new GadgetException("Only page owners can grant OAuth approval");
+ }
+ if ($stateOwner != null && ! $stateOwner == $pageOwner) {
+ throw new GadgetException("Client state belongs to a different person.");
+ }
+ }
+
+ /**
+ *
+ * @throws GadgetException
+ */
+ private function fetchRequestToken()
+ {
+ try {
+ $accessor = $this->accessorInfo->getAccessor();
+ //TODO The implementations of oauth differs from the one in JAVA. Fix the type OAuthMessage
+ $url = $accessor->consumer->callback_url->requestTokenURL;
+ $request = $this->newRequestMessage($url);
+ $reply = $this->sendOAuthMessage($request);
+ $reply->requireParameters(array(OAuth::$OAUTH_TOKEN, OAuth::$OAUTH_TOKEN_SECRET));
+ $accessor->requestToken = $reply->get_parameter(OAuth::$OAUTH_TOKEN);
+ $accessor->tokenSecret = $reply->get_parameter(OAuth::$OAUTH_TOKEN_SECRET);
+ } catch (Exception $e) {
+ // It's unfortunate the OAuth libraries throw a generic Exception.
+ throw new GadgetException($e);
+ }
+ }
+
+ private function newRequestMessageMethod($method, $url, $params)
+ {
+ if (! isset($params)) {
+ throw new Exception("params was null in " + "newRequestMessage " + "Use newRequesMessage if you don't have a params to pass");
+ }
+
+ switch ($this->accessorInfo->getSignatureType()) {
+ case OAuth::$RSA_SHA1:
+ $params[OAuth::$OAUTH_SIGNATURE_METHOD] = OAuth::$RSA_SHA1;
+ break;
+ case "PLAINTEXT":
+ $params[OAuth::$OAUTH_SIGNATURE_METHOD] = "PLAINTEXT";
+ break;
+ default:
+ $params[OAuth::$OAUTH_SIGNATURE_METHOD] = OAuth::$HMAC_SHA1;
+ }
+ $accessor = $this->accessorInfo->getAccessor();
+ return $accessor->newRequestMessage($method, $url, $params);
+ }
+
+ private function newRequestMessageUrlOnly($url)
+ {
+ $params = array();
+ return $this->newRequestMessageParams($url, $params);
+ }
+
+ private function newRequestMessageParams($url, $params)
+ {
+ $method = "POST";
+ if ($this->accessorInfo->getHttpMethod() == OAuthStoreVars::$HttpMethod['GET']) {
+ $method = "GET";
+ }
+ return $this->newRequestMessageMethod($method, $url, $params);
+ }
+
+ private function newRequestMessage($url = null, $method = null, $params = null)
+ {
+ if (isset($method) && isset($url) && isset($params)) {
+ return $this->newRequestMessageMethod($method, $url, $params);
+ } else if (isset($url) && isset($params)) {
+ return $this->newRequestMessageParams($url, $params);
+ } else if (isset($url)) {
+ return $this->newRequestMessageUrlOnly($url);
+ }
+ }
+
+ private function getAuthorizationHeader($oauthParams)
+ {
+ $result = "OAuth ";
+ $first = true;
+ foreach ($oauthParams as $key => $val) {
+ if (! $first) {
+ $result .= ", ";
+ } else {
+ $first = false;
+ }
+ $result .= OAuthUtil::urlencodeRFC3986($key) . "=\"" . OAuthUtil::urlencodeRFC3986($val) . '"';
+ }
+ return $result;
+ }
+
+ private function createRemoteContentRequest($oauthParams, $method, $url, $headers, $contentType, $postBody, $options)
+ {
+ $paramLocation = $this->accessorInfo->getParamLocation();
+ $newHeaders = array();
+
+ // paramLocation could be overriden by a run-time parameter to fetchRequest
+ switch ($paramLocation) {
+ case OAuthStoreVars::$OAuthParamLocation['AUTH_HEADER']:
+ if ($headers != null) {
+ $newHeaders = $headers;
+ }
+ $authHeader = array();
+ $authHeader = $this->getAuthorizationHeader($oauthParams);
+ $newHeaders["Authorization"] = $authHeader;
+ break;
+
+ case OAuthStoreVars::$OAuthParamLocation['POST_BODY']:
+ if (! OAuthUtil::isFormEncoded($contentType)) {
+ throw new GadgetException("Invalid param: OAuth param location can only " . "be post_body if post body if of type x-www-form-urlencoded");
+ }
+ if (! isset($postBody) || count($postBody) == 0) {
+ $postBody = OAuthUtil::urlencodeRFC3986($oauthParams);
+ } else {
+ $postBody = $postBody . "&" . OAuthUtil::urlencodeRFC3986($oauthParams);
+ }
+ break;
+
+ case OAuthStoreVars::$OAuthParamLocation['URI_QUERY']:
+ $url = OAuthUtil::addParameters($url, $oauthParams);
+ break;
+ }
+
+ $postBodyBytes = ($postBody == null) ? null : $postBody->getBytes("UTF-8");
+ $rcr = new RemoteContentRequest($url);
+ $rcr->createRemoteContentRequest($method, $url, $newHeaders, $postBodyBytes, $options);
+ return $rcr;
+ }
+
+ /**
+ * Sends OAuth request token and access token messages.
+ */
+ private function sendOAuthMessage(OAuthRequest $request)
+ {
+
+ $rcr = $this->createRemoteContentRequest($this->filterOAuthParams($request), $request->get_normalized_http_method(), $request->get_url(), null, RemoteContentRequest::$DEFAULT_CONTENT_TYPE, null, RemoteContentRequest::$DEFAULT_OPTIONS);
+ $content = $this->getNextFetcher()->fetchRequest($rcr);
+ $reply = OAuthRequest::from_request();
+ $params = OAuthUtil::decodeForm($content->getResponseContent());
+ $reply->set_parameters($params);
+ return $reply;
+ }
+
+ /**
+ * Builds the data we'll cache on the client while we wait for approval.
+ */
+ private function buildClientApprovalState()
+ {
+ try {
+ $accessor = $this->accessorInfo->getAccessor();
+ $oauthState = array();
+ $oauthState[OAuthFetcher::$REQ_TOKEN_KEY] = $accessor->requestToken;
+ $oauthState[OAuthFetcher::$REQ_TOKEN_SECRET_KEY] = $accessor->tokenSecret;
+ $oauthState[OAuthFetcher::$OWNER_KEY] = $this->authToken->getOwnerId();
+ $this->newClientState = $this->oauthCrypter->wrap($oauthState);
+ } catch (BlobCrypterException $e) {
+ throw new GadgetException("INTERNAL SERVER ERROR: " . $e);
+ }
+ }
+
+ /**
+ * Builds the URL the client needs to visit to approve access.
+ */
+ private function buildAznUrl()
+ {
+ // At some point we can be clever and use a callback URL to improve
+ // the user experience, but that's too complex for now.
+ $accessor = $this->accessorInfo->getAccessor();
+ $azn = $accessor->consumer->callback_url->userAuthorizationURL;
+ if (strstr($azn, "?") != - 1) {
+ $azn .= "?";
+ } else {
+ $azn .= "&";
+ }
+ $azn .= OAuth::$OAUTH_TOKEN;
+ $azn .= "=";
+ $azn .= OAuthUtil::urlencodeRFC3986($accessor->requestToken);
+ $this->aznUrl = $azn;
+ }
+
+ /**
+ * Do we need to exchange a request token for an access token?
+ */
+ private function needAccessToken()
+ {
+ return ($this->accessorInfo->getAccessor()->requestToken != null && $this->accessorInfo->getAccessor()->accessToken == null);
+ }
+
+ /**
+ * Implements section 6.3 of the OAuth spec.
+ */
+ private function exchangeRequestToken()
+ {
+ try {
+ $accessor = $this->accessorInfo->getAccessor();
+ $url = $accessor->consumer->callback_url->accessTokenURL;
+ $msgParams = array();
+ $msgParams[OAuth::$OAUTH_TOKEN] = $accessor->requestToken;
+ $request = $this->newRequestMessageParams($url, $msgParams);
+ $reply = $this->sendOAuthMessage($request);
+ $reply->requireParameters(array(OAuth::$OAUTH_TOKEN, OAuth::$OAUTH_TOKEN_SECRET));
+ $accessor->accessToken = $reply->get_parameter(OAuth::$OAUTH_TOKEN);
+ $accessor->tokenSecret = $reply->get_parameter(OAuth::$OAUTH_TOKEN_SECRET);
+ } catch (Exception $e) {
+ // It's unfortunate the OAuth libraries throw a generic Exception.
+ throw new GadgetException("INTERNAL SERVER ERROR: " . $e);
+ }
+ }
+
+ /**
+ * Save off our new token and secret to the persistent store.
+ *
+ * @throws GadgetException
+ */
+ private function saveAccessToken()
+ {
+ $accessor = $this->accessorInfo->getAccessor();
+ $tokenKey = $this->buildTokenKey();
+ $tokenInfo = new TokenInfo($accessor->accessToken, $accessor->tokenSecret);
+ $this->tokenStore->storeTokenKeyAndSecret($tokenKey, $tokenInfo);
+ }
+
+ /**
+ * Builds the data we'll cache on the client while we make requests.
+ */
+ private function buildClientAccessState()
+ {
+ try {
+ $oauthState = array();
+ $accessor = $this->accessorInfo->getAccessor();
+ $oauthState[OAuthFetcher::$ACCESS_TOKEN_KEY] = $accessor->accessToken;
+ $oauthState[OAuthFetcher::$ACCESS_TOKEN_SECRET_KEY] = $accessor->tokenSecret;
+ $oauthState[OAuthFetcher::$OWNER_KEY] = $this->authToken->getOwnerId();
+ $this->newClientState = $this->oauthCrypter->wrap($oauthState);
+ } catch (BlobCrypterException $e) {
+ throw new GadgetException("INTERNAL SERVER ERROR: " . $e);
+ }
+ }
+
+ /**
+ * Get honest-to-goodness user data.
+ */
+ private function fetchData()
+ {
+ try {
+ $msgParams = OAuthUtil::isFormEncoded($this->realRequest->getContentType()) ? OAuthUtil::urldecodeRFC3986($this->realRequest->getPostBody()) : array();
+ $method = $this->realRequest->getMethod();
+ // Build and sign the message.
+ $oauthRequest = $this->newRequestMessageMethod($method, $this->realRequest->getUrl(), $msgParams);
+ $rcr = $this->createRemoteContentRequest($this->filterOAuthParams($oauthRequest), $this->realRequest->getMethod(), $this->realRequest->getUrl(), $this->realRequest->getHeaders(), $this->realRequest->getContentType(), $this->realRequest->getPostBody(), $this->realRequest->getOptions());
+ $content = $this->getNextFetcher()->fetchRequest($rcr);
+ return $content;
+ } catch (Exception $e) {
+ throw new GadgetException("INTERNAL SERVER ERROR: " . $e);
+ }
+ }
+
+ /**
+ * Extracts only those parameters from an OAuthMessage that are OAuth-related.
+ * An OAuthMessage may hold a whole bunch of non-OAuth-related parameters
+ * because they were all needed for signing. But when constructing a request
+ * we need to be able to extract just the OAuth-related parameters because
+ * they, and only they, may have to be put into an Authorization: header or
+ * some such thing.
+ *
+ * @param message the OAuthMessage object, which holds non-OAuth parameters
+ * such as foo=bar (which may have been in the original URI query part, or
+ * perhaps in the POST body), as well as OAuth-related parameters (such as
+ * oauth_timestamp or oauth_signature).
+ *
+ * @return a list that contains only the oauth_related parameters.
+ *
+ * @throws IOException
+ */
+ private function filterOAuthParams($message)
+ {
+ $result = array();
+ foreach ($message->get_parameters() as $key => $value) {
+ if (strstr(strtolower($key), "oauth") != - 1 || strstr(strtolower($key), "xoauth") != - 1) {
+ $result[$key] = $value;
+ }
+ }
+ return $result;
+ }
+
+ public function getResponseMetadata()
+ {
+ $extra = array();
+ if ($this->newClientState != null) {
+ $extra[OAuthFetcher::$CLIENT_STATE] = $this->newClientState;
+ }
+ if ($this->aznUrl != null) {
+ $extra[OAuthFetcher::$APPROVAL_URL] = $this->aznUrl;
+ }
+ return $extra;
+ }
+}
\ No newline at end of file
Added: incubator/shindig/trunk/php/src/gadgets/oauth/OAuthFetcherFactory.php
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/php/src/gadgets/oauth/OAuthFetcherFactory.php?rev=658758&view=auto
==============================================================================
--- incubator/shindig/trunk/php/src/gadgets/oauth/OAuthFetcherFactory.php (added)
+++ incubator/shindig/trunk/php/src/gadgets/oauth/OAuthFetcherFactory.php Wed May 21 09:58:52 2008
@@ -0,0 +1,91 @@
+<?php
+/*
+ * 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.
+ */
+
+
+/**
+ * Produces OAuth content fetchers for input tokens.
+ */
+class OAuthFetcherFactory {
+
+ /** used to encrypt state stored on the client */
+ protected $oauthCrypter;
+
+ /** persistent storage for OAuth tokens */
+ protected $tokenStore;
+
+ public function __construct($fetcher = null, $oauthCrypter = null, $tokenStore = null)
+ {
+ if (isset($oauthCrypter) && isset($tokenStore)) {
+ return $this->OAuthFetcherFactoryCreate($oauthCrypter, $tokenStore);
+ } elseif (isset($fetcher)) {
+ return $this->OAuthFetcherFactoryInit($fetcher);
+ } else {
+ throw new Exception('Wrong number of parameters in the OAuthFetcherFactory constuct');
+ }
+ }
+
+ /**
+ * Initialize the OAuth factory with a default implementation of
+ * BlobCrypter and consumer keys/secrets read from oauth.js
+ */
+ public function OAuthFetcherFactoryInit($fetcher)
+ {
+ try {
+ $BBC = new BasicBlobCrypter();
+ $this->oauthCrypter = new BasicBlobCrypter(srand($BBC->MASTER_KEY_MIN_LEN));
+ $basicStore = new BasicGadgetOAuthTokenStore(new BasicOAuthStore());
+ $basicStore->initFromConfigFile($fetcher);
+ $this->tokenStore = $basicStore;
+ } catch (Exeption $t) {
+ // Since this happens at startup, we don't want to kill the server just
+ // because we can't initialize the OAuth config.
+ // php variant?
+ }
+ }
+
+ /**
+ * Creates an OAuthFetcherFactory based on prepared crypter and token store.
+ *
+ * @param oauthCrypter used to wrap client side state
+ * @param tokenStore used as interface to persistent token store.
+ */
+ protected function OAuthFetcherFactoryCreate($oauthCrypter, $tokenStore)
+ {
+ $this->oauthCrypter = $oauthCrypter;
+ $this->tokenStore = $tokenStore;
+ }
+
+ /**
+ * Produces an OAuthFetcher that will sign requests and delegate actual
+ * network retrieval to the {@code nextFetcher}
+ *
+ * @param nextFetcher The fetcher that will fetch real content
+ * @param token The gadget token used to identity the user and gadget
+ * @param params The parsed parameters the gadget requested
+ * @return The oauth fetcher.
+ * @throws GadgetException
+ */
+ public function getOAuthFetcher($nextFetcher, $token, $params)
+ {
+ $fetcher = new OAuthFetcher($this->tokenStore, $this->oauthCrypter, $nextFetcher, $token, $params);
+ $fetcher->init();
+ return $fetcher;
+ }
+}
Added: incubator/shindig/trunk/php/src/gadgets/oauth/OAuthRequestParams.php
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/php/src/gadgets/oauth/OAuthRequestParams.php?rev=658758&view=auto
==============================================================================
--- incubator/shindig/trunk/php/src/gadgets/oauth/OAuthRequestParams.php (added)
+++ incubator/shindig/trunk/php/src/gadgets/oauth/OAuthRequestParams.php Wed May 21 09:58:52 2008
@@ -0,0 +1,54 @@
+<?php
+/*
+ * 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.
+ */
+
+
+/**
+ * Bundles information about a proxy request that requires OAuth
+ */
+class OAuthRequestParams {
+ public static $SERVICE_PARAM = "oauthService";
+ public static $TOKEN_PARAM = "oauthToken";
+ public static $CLIENT_STATE_PARAM = "oauthState";
+ private $serviceName;
+ private $tokenName;
+ private $origClientState;
+
+ public function __construct()
+ {
+ $this->serviceName = $_REQUEST[OAuthRequestParams::$SERVICE_PARAM];
+ $this->tokenName = $_REQUEST[OAuthRequestParams::$TOKEN_PARAM];
+ $this->origClientState = $_REQUEST[OAuthRequestParams::$CLIENT_STATE_PARAM];
+ }
+
+ public function getServiceName()
+ {
+ return $this->serviceName;
+ }
+
+ public function getTokenName()
+ {
+ return $this->tokenName;
+ }
+
+ public function getOrigClientState()
+ {
+ return $this->origClientState;
+ }
+}
Added: incubator/shindig/trunk/php/src/gadgets/oauth/OAuthServiceProvider.php
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/php/src/gadgets/oauth/OAuthServiceProvider.php?rev=658758&view=auto
==============================================================================
--- incubator/shindig/trunk/php/src/gadgets/oauth/OAuthServiceProvider.php (added)
+++ incubator/shindig/trunk/php/src/gadgets/oauth/OAuthServiceProvider.php Wed May 21 09:58:52 2008
@@ -0,0 +1,33 @@
+<?php
+/*
+ * 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.
+ */
+
+class OAuthServiceProvider {
+
+ public $requestTokenURL;
+ public $userAuthorizationURL;
+ public $accessTokenURL;
+
+ public function __construct($requestTokenURL, $userAuthorizationURL, $accessTokenURL)
+ {
+ $this->requestTokenURL = $requestTokenURL;
+ $this->userAuthorizationURL = $userAuthorizationURL;
+ $this->accessTokenURL = $accessTokenURL;
+ }
+}
Added: incubator/shindig/trunk/php/src/gadgets/oauth/OAuthStore.php
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/php/src/gadgets/oauth/OAuthStore.php?rev=658758&view=auto
==============================================================================
--- incubator/shindig/trunk/php/src/gadgets/oauth/OAuthStore.php (added)
+++ incubator/shindig/trunk/php/src/gadgets/oauth/OAuthStore.php Wed May 21 09:58:52 2008
@@ -0,0 +1,354 @@
+<?php
+/*
+ * 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.
+ */
+
+interface OAuthStore {
+ public function setOAuthServiceProviderInfo($providerKey, $providerInfo);
+ public function getOAuthServiceProviderInfo($providerKey);
+ public function setOAuthConsumerKeyAndSecret($providerKey, $keyAndSecret);
+ public function setTokenAndSecret($tokenKey, $tokenInfo);
+ public function getOAuthAccessorTokenKey(TokenKey $tokenKey);
+
+}
+
+class OAuthStoreVars {
+ public static $HttpMethod = array('GET' => 'GET', 'POST' => 'POST');
+ public static $SignatureType = array('HMAC_SHA1' => 'HMAC_SHA1', 'RSA_SHA1' => 'RSA_SHA1', 'PLAINTEXT' => 'PLAINTEXT');
+ public static $KeyType = array('HMAC_SYMMETRIC' => 'HMAC_SYMMETRIC', 'RSA_PRIVATE' => 'RSA_PRIVATE');
+ public static $OAuthParamLocation = array('AUTH_HEADER' => 'auth_header', 'POST_BODY' => 'post_body', 'URI_QUERY' => 'uri_query');
+}
+
+class AccesorInfo {
+ public $accessor;
+ public $httpMethod;
+ public $signatureType;
+ public $paramLocation;
+
+ public function getParamLocation()
+ {
+ return $this->paramLocation;
+ }
+
+ public function setParamLocation($paramLocation)
+ {
+ $this->paramLocation = $paramLocation;
+ }
+
+ public function getAccessor()
+ {
+ return $this->accessor;
+ }
+
+ public function setAccessor($accessor)
+ {
+ $this->accessor = $accessor;
+ }
+
+ public function getHttpMethod()
+ {
+ return $this->httpMethod;
+ }
+
+ public function setHttpMethod($httpMethod)
+ {
+ $this->httpMethod = $httpMethod;
+ }
+
+ public function getSignatureType()
+ {
+ return $this->signatureType;
+ }
+
+ public function setSignatureType($signatureType)
+ {
+ $this->signatureType = $signatureType;
+ }
+}
+
+class ConsumerKeyAndSecret {
+ private $consumerKey;
+ private $consumerSecret;
+ private $keyType;
+
+ public function ConsumerKeyAndSecret($key, $secret, $type)
+ {
+ $this->consumerKey = $key;
+ $this->consumerSecret = $secret;
+ $this->keyType = $type;
+ }
+
+ public function getConsumerKey()
+ {
+ return $this->consumerKey;
+ }
+
+ public function getConsumerSecret()
+ {
+ return $this->consumerSecret;
+ }
+
+ public function getKeyType()
+ {
+ return $this->keyType;
+ }
+}
+
+class ProviderKey {
+ private $gadgetUri;
+ private $serviceName;
+
+ public function getGadgetUri()
+ {
+ return $this->gadgetUri;
+ }
+
+ public function setGadgetUri($gadgetUri)
+ {
+ $this->gadgetUri = $gadgetUri;
+ }
+
+ public function getServiceName()
+ {
+ return $this->serviceName;
+ }
+
+ public function setServiceName($serviceName)
+ {
+ $this->serviceName = $serviceName;
+ }
+
+ public function hashCode()
+ {
+ $prime = 31;
+ $result = 1;
+ $result = $prime * $result + (($gadgetUri == null) ? 0 : $gadgetUri->hashCode());
+ $result = $prime * $result + (($serviceName == null) ? 0 : $serviceName->hashCode());
+ return $result;
+ }
+
+ public function equals($obj)
+ {
+ if ($this == $obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj . getClass())
+ return false;
+ $other = $obj;
+ if ($gadgetUri == null) {
+ if ($other->gadgetUri != null)
+ return false;
+ } else if (! $gadgetUri->equals(other . gadgetUri))
+ return false;
+ if ($serviceName == null) {
+ if ($other->serviceName != null)
+ return false;
+ } else if (! $serviceName->equals($other->serviceName))
+ return false;
+ return true;
+ }
+}
+
+class ProviderInfo {
+ private $provider;
+ private $httpMethod;
+ private $signatureType;
+ private $paramLocation;
+
+ // this can be null if we have not negotiated a consumer key and secret
+ // yet with the provider, or if we decided that we want to use a global
+ // public key
+ private $keyAndSecret;
+
+ public function getParamLocation()
+ {
+ return $this->paramLocation;
+ }
+
+ public function setParamLocation($paramLocation)
+ {
+ $this->paramLocation = $paramLocation;
+ }
+
+ public function getKeyAndSecret()
+ {
+ return $this->keyAndSecret;
+ }
+
+ public function setKeyAndSecret($keyAndSecret)
+ {
+ $this->keyAndSecret = $keyAndSecret;
+ }
+
+ public function getProvider()
+ {
+ return $this->provider;
+ }
+
+ public function setProvider($provider)
+ {
+ $this->provider = $provider;
+ }
+
+ public function getHttpMethod()
+ {
+ return $this->httpMethod;
+ }
+
+ public function setHttpMethod($httpMethod)
+ {
+ $this->httpMethod = $httpMethod;
+ }
+
+ public function getSignatureType()
+ {
+ return $this->signatureType;
+ }
+
+ public function setSignatureType($signatureType)
+ {
+ $this->signatureType = $signatureType;
+ }
+}
+
+class TokenKey {
+ private $userId;
+ private $gadgetUri;
+ private $moduleId;
+ private $tokenName;
+ private $serviceName;
+
+ public function getUserId()
+ {
+ return $this->userId;
+ }
+
+ public function setUserId($userId)
+ {
+ $this->userId = $userId;
+ }
+
+ public function getGadgetUri()
+ {
+ return $this->gadgetUri;
+ }
+
+ public function setGadgetUri($gadgetUri)
+ {
+ $this->gadgetUri = $gadgetUri;
+ }
+
+ public function getModuleId()
+ {
+ return $this->moduleId;
+ }
+
+ public function setModuleId($moduleId)
+ {
+ $this->moduleId = $moduleId;
+ }
+
+ public function getTokenName()
+ {
+ return $this->tokenName;
+ }
+
+ public function setTokenName($tokenName)
+ {
+ $this->tokenName = $tokenName;
+ }
+
+ public function getServiceName()
+ {
+ return $this->serviceName;
+ }
+
+ public function setServiceName($serviceName)
+ {
+ $this->serviceName = $serviceName;
+ }
+
+ public function hashCode()
+ {
+ $prime = 31;
+ $result = 1;
+ $result = $prime * $result + (($gadgetUri == null) ? 0 : $gadgetUri->hashCode());
+ $result = $prime * $result + (int)($moduleId ^ ($moduleId >> 32));
+ $result = $prime * $result + (($serviceName == null) ? 0 : $serviceName->hashCode());
+ $result = $prime * $result + (($tokenName == null) ? 0 : $tokenName->hashCode());
+ $result = $prime * $result + (($userId == null) ? 0 : $userId->hashCode());
+ return $result;
+ }
+
+ public function equals($obj)
+ {
+ if ($this == $obj)
+ return true;
+ if ($obj == null)
+ return false;
+ /*?*/ if (getClass() != $obj->getClass())
+ return false;
+
+ $other = $obj;
+ if ($gadgetUri == null) {
+ if ($other->gadgetUri != null)
+ return false;
+ } else if (! $gadgetUri->equals($other->gadgetUri))
+ return false;
+ if ($moduleId != $other->moduleId)
+ return false;
+ if ($serviceName == null) {
+ if ($other->serviceName != null)
+ return false;
+ } else if (! $serviceName->equals($other->serviceName))
+ return false;
+ if ($tokenName == null) {
+ if ($other->tokenName != null)
+ return false;
+ } else if (! $tokenName->equals($other->tokenName))
+ return false;
+ if ($userId == null) {
+ if ($other->userId != null)
+ return false;
+ } else if (! $userId->equals($other->userId))
+ return false;
+ return true;
+ }
+}
+
+class TokenInfo {
+ private $accessToken;
+ private $tokenSecret;
+
+ public function __constructor($token, $secret)
+ {
+ $this->accessToken = $token;
+ $this->tokenSecret = $secret;
+ }
+
+ public function getAccessToken()
+ {
+ return $this->accessToken;
+ }
+
+ public function getTokenSecret()
+ {
+ return $this->tokenSecret;
+ }
+}
Modified: incubator/shindig/trunk/php/src/gadgets/samplecontainer/BasicBlobCrypter.php
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/php/src/gadgets/samplecontainer/BasicBlobCrypter.php?rev=658758&r1=658757&r2=658758&view=diff
==============================================================================
--- incubator/shindig/trunk/php/src/gadgets/samplecontainer/BasicBlobCrypter.php (original)
+++ incubator/shindig/trunk/php/src/gadgets/samplecontainer/BasicBlobCrypter.php Wed May 21 09:58:52 2008
@@ -1,15 +1,15 @@
<?php
+class BlobExpiredException extends Exception {}
+
/**
* This class provides basic binary blob encryption and decryption, for use with the security token
*
*/
-
-class BlobExpiredException extends Exception {}
-
-//FIXME make this compatible with the java's blobcrypter
class BasicBlobCrypter extends BlobCrypter {
+ //FIXME make this compatible with the java's blobcrypter
+
// Labels for key derivation
private $CIPHER_KEY_LABEL = 0;
private $HMAC_KEY_LABEL = 1;
@@ -89,11 +89,14 @@
{
$map = array();
$items = split("[&=]", $plain);
+ /*
+ //TODO: See if this can work or isn't necessary.
if ((count($items) / 2) != 7) {
// A valid token should decrypt to 14 items, aka 7 pairs.
// If not, this wasn't valid & untampered data and we abort
throw new BlobExpiredException("Invalid security token");
}
+ */
for ($i = 0; $i < count($items); ) {
$key = urldecode($items[$i ++]);
$value = urldecode($items[$i ++]);
Modified: incubator/shindig/trunk/php/src/socialdata/http/GadgetDataServlet.php
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/php/src/socialdata/http/GadgetDataServlet.php?rev=658758&r1=658757&r2=658758&view=diff
==============================================================================
--- incubator/shindig/trunk/php/src/socialdata/http/GadgetDataServlet.php (original)
+++ incubator/shindig/trunk/php/src/socialdata/http/GadgetDataServlet.php Wed May 21 09:58:52 2008
@@ -49,7 +49,7 @@
class GadgetDataServlet extends HttpServlet {
private $handlers = array();
-
+
public function __construct()
{
parent::__construct();
@@ -64,7 +64,7 @@
}
}
}
-
+
public function doPost()
{
$requestParam = isset($_POST['request']) ? $_POST['request'] : '';
@@ -87,7 +87,7 @@
}
echo json_encode($response);
}
-
+
private function createResponse($requestParam, $token)
{
if (empty($token)) {
@@ -116,7 +116,7 @@
}
return $responseItems;
}
-
+
public function doGet()
{
echo header("HTTP/1.0 400 Bad Request", true, 400);