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);