Author: chabotc
Date: Wed Nov 5 13:54:09 2008
New Revision: 711709
URL: http://svn.apache.org/viewvc?rev=711709&view=rev
Log:
Woops missed a couple of files of the oauth work
Added:
incubator/shindig/trunk/php/src/common/OAuthLookupService.php
incubator/shindig/trunk/php/src/common/sample/BasicOAuthDataStore.php
incubator/shindig/trunk/php/src/common/sample/BasicOAuthLookupService.php
incubator/shindig/trunk/php/src/social/oauth/OAuth.php
incubator/shindig/trunk/php/src/social/oauth/OAuthSecurityToken.php
Added: incubator/shindig/trunk/php/src/common/OAuthLookupService.php
URL:
http://svn.apache.org/viewvc/incubator/shindig/trunk/php/src/common/OAuthLookupService.php?rev=711709&view=auto
==============================================================================
--- incubator/shindig/trunk/php/src/common/OAuthLookupService.php (added)
+++ incubator/shindig/trunk/php/src/common/OAuthLookupService.php Wed Nov 5
13:54:09 2008
@@ -0,0 +1,30 @@
+<?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 for handling the validation of OAuth requests.
+ */
+abstract class OAuthLookupService {
+
+ abstract public function thirdPartyHasAccessToUser($oauthRequest,
$appUrl, $userId);
+
+ abstract public function getSecurityToken($appUrl, $userId);
+}
+
Added: incubator/shindig/trunk/php/src/common/sample/BasicOAuthDataStore.php
URL:
http://svn.apache.org/viewvc/incubator/shindig/trunk/php/src/common/sample/BasicOAuthDataStore.php?rev=711709&view=auto
==============================================================================
--- incubator/shindig/trunk/php/src/common/sample/BasicOAuthDataStore.php
(added)
+++ incubator/shindig/trunk/php/src/common/sample/BasicOAuthDataStore.php Wed
Nov 5 13:54:09 2008
@@ -0,0 +1,68 @@
+<?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.
+ *
+ */
+
+/**
+ * Primitive OAuth backing store that doesn't do much.
+ */
+class BasicOAuthDataStore extends OAuthDataStore {
+
+ function __construct()
+ {
+ }
+
+ function lookup_consumer($consumer_key)
+ {
+ return new OAuthConsumer($consumer_key, "fake-consumer-secret");
+ }
+
+ function lookup_token($consumer, $token_type, $token)
+ {
+ if ($token_type == "request") {
+ return new OAuthToken($token, "fake-request-secret");
+ } else {
+ if ($token_type == "access") {
+ return new OAuthToken($token,
"fake-access-secret");
+ } else {
+ throw new OAuthException("unexpected token
type: $token_type");
+ }
+ }
+ return null;
+ }
+
+ function lookup_nonce($consumer, $token, $nonce, $timestamp)
+ {
+ return false; // pretend we've always never seen this nonce
+ }
+
+ function new_request_token($consumer)
+ {
+ return new OAuthToken("fake-request-token",
"fake-request-secret");
+ }
+
+ function new_access_token($oauthToken, $consumer)
+ {
+ return new OAuthToken("fake-access-token",
"fake-access-secret");
+ }
+
+ function authorize_request_token($token)
+ {
+ // mark the given requst token as having been authorized by the
user
+ }
+}
Added: incubator/shindig/trunk/php/src/common/sample/BasicOAuthLookupService.php
URL:
http://svn.apache.org/viewvc/incubator/shindig/trunk/php/src/common/sample/BasicOAuthLookupService.php?rev=711709&view=auto
==============================================================================
--- incubator/shindig/trunk/php/src/common/sample/BasicOAuthLookupService.php
(added)
+++ incubator/shindig/trunk/php/src/common/sample/BasicOAuthLookupService.php
Wed Nov 5 13:54:09 2008
@@ -0,0 +1,61 @@
+<?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.
+ *
+ */
+
+/**
+ * Basic implementation of OAuthLookupService using BasicOAuthDataStore.
+ */
+class BasicOAuthLookupService extends OAuthLookupService {
+
+ public function thirdPartyHasAccessToUser($oauthRequest, $appUrl,
$userId)
+ {
+ $appId = $this->getAppId($appUrl);
+ return $this->hasValidSignature($oauthRequest, $appUrl, $appId)
&& $this->userHasAppInstalled($userId, $appId);
+ }
+
+ private function hasValidSignature($oauthRequest, $appUrl, $appId)
+ {
+ try {
+ $server = new OAuthServer(new BasicOAuthDataStore());
+ $server->add_signature_method(new
OAuthSignatureMethod_HMAC_SHA1());
+ $server->add_signature_method(new
OAuthSignatureMethod_PLAINTEXT());
+ list($consumer, $token) =
$server->verify_request($oauthRequest);
+ return true;
+ } catch (OAuthException $e) {
+ //FIXME seems some old debugging code? should clean
this up if so
+ echo "OAuthException: " . $e->getMessage();
+ }
+ return false;
+ }
+
+ private function userHasAppInstalled($apUrl, $appId)
+ {
+ return true; // a real implementation would look this up
+ }
+
+ public function getSecurityToken($appUrl, $userId)
+ {
+ return new OAuthSecurityToken($userId, $appUrl,
$this->getAppId($appUrl), "samplecontainer");
+ }
+
+ private function getAppId($appUrl)
+ {
+ return 0; // a real implementation would look this up
+ }
+}
Added: incubator/shindig/trunk/php/src/social/oauth/OAuth.php
URL:
http://svn.apache.org/viewvc/incubator/shindig/trunk/php/src/social/oauth/OAuth.php?rev=711709&view=auto
==============================================================================
--- incubator/shindig/trunk/php/src/social/oauth/OAuth.php (added)
+++ incubator/shindig/trunk/php/src/social/oauth/OAuth.php Wed Nov 5 13:54:09
2008
@@ -0,0 +1,807 @@
+<?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.
+ *
+ */
+
+/* Generic exception class
+ */
+class OAuthException extends Exception { // pass
+}
+
+class OAuthConsumer {
+ public $key;
+ public $secret;
+
+ function __construct($key, $secret, $callback_url = NULL)
+ {
+ $this->key = $key;
+ $this->secret = $secret;
+ $this->callback_url = $callback_url;
+ }
+
+ function __toString()
+ {
+ return "OAuthConsumer[key=$this->key,secret=$this->secret]";
+ }
+}
+
+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, ($token) ? $token->secret
: "");
+
+ $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 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 Exception("fetch_private_cert not implemented");
+ }
+
+ public function build_signature(&$request, $consumer, $token)
+ {
+ $base_string = $request->get_signature_base_string();
+ $request->base_string = $base_string;
+
+ // Fetch the private key cert based on the request
+ $cert = $this->fetch_private_cert($request);
+
+ // Pull the private key ID from the certificate
+ $privatekeyid = openssl_get_privatekey($cert);
+
+ // 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;
+ // for debug purposes
+ 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);
+ } else {
+ // collect request parameters from query string (GET)
and post-data (POST) if appropriate (note: POST vars have priority)
+ $req_parameters = $_GET;
+ if ($http_method == "POST" &&
@$request_headers["Content-Type"] == "application/x-www-form-urlencoded") {
+ $req_parameters = array_merge($req_parameters,
$_POST);
+ }
+
+ // 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
+ if (@substr($request_headers['Authorization'], 0, 5) ==
"OAuth") {
+ $header_parameters =
OAuthRequest::split_header($request_headers['Authorization']);
+ $parameters = array_merge($req_parameters,
$header_parameters);
+ $req = new OAuthRequest($http_method,
$http_url, $parameters);
+ } else
+ $req = new OAuthRequest($http_method,
$http_url, $req_parameters);
+ }
+
+ 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_version" => OAuthRequest::$version,
+ "oauth_nonce" =>
OAuthRequest::generate_nonce(),
+ "oauth_timestamp" =>
OAuthRequest::generate_timestamp(),
+ "oauth_consumer_key" => $consumer->key);
+ $parameters = array_merge($defaults, $parameters);
+
+ if ($token) {
+ $parameters['oauth_token'] = $token->key;
+ }
+ return new OAuthRequest($http_method, $http_url, $parameters);
+ }
+
+ public function set_parameter($name, $value)
+ {
+ $this->parameters[$name] = $value;
+ }
+
+ public function get_parameter($name)
+ {
+ return isset($this->parameters[$name]) ?
$this->parameters[$name] : null;
+ }
+
+ public function get_parameters()
+ {
+ return $this->parameters;
+ }
+
+ /**
+ * 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()
+ {
+ $parts = array($this->get_normalized_http_method(),
$this->get_normalized_http_url(),
+ $this->get_signable_parameters());
+
+ $parts = array_map(array('OAuthUtil', 'urlencodeRFC3986'),
$parts);
+
+ 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);
+
+ $port = @$parts['port'];
+ $scheme = $parts['scheme'];
+ $host = $parts['host'];
+ $path = @$parts['path'];
+
+ $port or $port = ($scheme == 'https') ? '443' : '80';
+
+ if (($scheme == 'https' && $port != '443') || ($scheme ==
'http' && $port != '80')) {
+ $host = "$host:$port";
+ }
+ return "$scheme://$host$path";
+ }
+
+ /**
+ * builds a url usable for a GET request
+ */
+ public function to_url()
+ {
+ $out = $this->get_normalized_http_url() . "?";
+ $out .= $this->to_postdata();
+ return $out;
+ }
+
+ /**
+ * 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($realm = "")
+ {
+ $out = 'Authorization: OAuth realm="' . $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
+ */
+ private 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)
+ {
+ // remove 'OAuth ' at the start of a header
+ $header = substr($header, 6);
+
+ // 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");
+ }
+ }
+
+}
+
+abstract class OAuthDataStore {
+
+ abstract function lookup_consumer($consumer_key);
+
+ abstract function lookup_token($consumer, $token_type, $token);
+
+ abstract function lookup_nonce($consumer, $token, $nonce, $timestamp);
+
+ // return a new token attached to this consumer
+ abstract function new_request_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
+ abstract function new_access_token($token, $consumer);
+
+ abstract function authorize_request_token($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)
+ {
+ // TODO: check if request token is authorized first
+ $token = $this->new_token($consumer, 'access');
+ dba_delete("request_" . $token->key, $this->dbh);
+ return $token;
+ }
+
+ function authorize_request_token($token)
+ {
+ dba_insert('request_' . $token->key . '_authorized', 1,
$this->dbh);
+ }
+}
+
+class OAuthUtil {
+
+ public static function urlencodeRFC3986($string)
+ {
+ return str_replace('+', ' ', str_replace('%7E', '~',
rawurlencode($string)));
+
+ }
+
+ // This decode function isn't taking into consideration the above
+ // modifications to the encoding process. However, this method doesn't
+ // seem to be used anywhere so leaving it as is.
+ public static function urldecodeRFC3986($string)
+ {
+ return rawurldecode($string);
+ }
+}
+
Added: incubator/shindig/trunk/php/src/social/oauth/OAuthSecurityToken.php
URL:
http://svn.apache.org/viewvc/incubator/shindig/trunk/php/src/social/oauth/OAuthSecurityToken.php?rev=711709&view=auto
==============================================================================
--- incubator/shindig/trunk/php/src/social/oauth/OAuthSecurityToken.php (added)
+++ incubator/shindig/trunk/php/src/social/oauth/OAuthSecurityToken.php Wed Nov
5 13:54:09 2008
@@ -0,0 +1,77 @@
+<?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.
+ *
+ */
+
+/**
+ * SecurityToken derived from a successful OAuth validation.
+ */
+class OAuthSecurityToken extends SecurityToken {
+ private $userId;
+ private $appUrl;
+ private $appId;
+ private $domain;
+
+ public function __construct($userId, $appUrl, $appId, $domain)
+ {
+ $this->userId = $userId;
+ $this->appUrl = $appUrl;
+ $this->appId = $appId;
+ $this->domain = $domain;
+ }
+
+ public function isAnonymous()
+ {
+ return ($this->userId != null);
+ }
+
+ public function getOwnerId()
+ {
+ return $this->userId;
+ }
+
+ public function getViewerId()
+ {
+ return $this->userId;
+ }
+
+ public function getAppId()
+ {
+ return $this->appId;
+ }
+
+ public function getDomain()
+ {
+ return $this->domain;
+ }
+
+ public function getAppUrl()
+ {
+ return $this->appUrl;
+ }
+
+ public function getModuleId()
+ {
+ return null;
+ }
+
+ public function toSerialForm()
+ {
+ return
"OAuthSecurityToken[userId=$userId,appUrl=$appUrl,appId=$appId,domain=$domain]";
+ }
+}