mirror of
https://github.com/jrconlin/oauthsimple.git
synced 2026-07-28 04:06:51 +00:00
@@ -0,0 +1,56 @@
|
||||
#OAuthSimple for Javascript
|
||||
|
||||
## A Word of Caution:
|
||||
It might be useful to understand what OAuth is. OAuth is a way for two
|
||||
(or more) parties to confirm the fact that they are who they say they
|
||||
are. This is done by a set of secret handshakes that only both sides
|
||||
know.
|
||||
|
||||
In short, the very first thing that happens is that both sides
|
||||
exchange some secret value. This exchange happens outside of OAuth and
|
||||
the secret is NEVER displayed to anyone other than the two parties.
|
||||
|
||||
This... gets a bit tricky when you're talking about javascript.
|
||||
|
||||
The example code in index.html doesn't even try to hide the secret,
|
||||
and frankly, it's considerably difficult to do that even in the best
|
||||
of situations because users can stop and examine code with most recent
|
||||
browsers.
|
||||
|
||||
So, while your secret may be disclosed, in a properly functioning
|
||||
system, the user's data is only disclosed after the user concents to
|
||||
it.
|
||||
|
||||
If you're building this for your own use on a device you control where
|
||||
your code can't be inspected by malicious parties. Go for it.
|
||||
Otherwise, you probably want to do the OAuth exchange on the server
|
||||
and pass back the final access token to the javascript app. (See the
|
||||
OAuth documentation for whatever site you're working with for details
|
||||
about that.)
|
||||
|
||||
## Webcalls without a Web
|
||||
|
||||
There are lots of environments that let you run javascript outside of
|
||||
a browser. I'm not going to detail all of them (because there are a
|
||||
lot of them), but I'll note that OAuth was designed around using HTTP
|
||||
as the transport mechanism.
|
||||
|
||||
Fortunately, that doesn't mean that you have to fire up your browser
|
||||
of choice in order to make these calls. You do need to have something
|
||||
that talks HTTP, however. Again, there are lots of choices, for
|
||||
instance libcURL is available for darn near everything out there.
|
||||
There are also plenty of systems that provide native calls.
|
||||
|
||||
For the most part, these calls will either want the arguments in-line
|
||||
with the call (use ```OAuthSimple().sign(...).signed_url;```), as a
|
||||
request header ( ```OAuthSimple().sign(...).header```), or as the POST
|
||||
request body (you may want to use _normalizedParameters() for that,
|
||||
but understand that it's not a public function and is subject to
|
||||
change.) Again, see the documentation for the service you wish to
|
||||
connect to for how best to provide this info.
|
||||
|
||||
## How to use it.
|
||||
|
||||
Honestly? Read the source. I commented the heck out of it and there's
|
||||
example code inside there. Plus, unlike this, it is more likely to be
|
||||
documented and included with the distribution.
|
||||
+93
-89
@@ -1,9 +1,9 @@
|
||||
<?php
|
||||
/**
|
||||
/**
|
||||
* OAuthSimple - A simpler version of OAuth
|
||||
*
|
||||
* https://github.com/jrconlin/oauthsimple
|
||||
*
|
||||
*
|
||||
* @author jr conlin <src@jrconlin.com>
|
||||
* @copyright unitedHeroes.net 2011
|
||||
* @version 1.3
|
||||
@@ -17,7 +17,7 @@ class OAuthSimple {
|
||||
private $_action;
|
||||
private $_nonce_chars;
|
||||
|
||||
/**
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @access public
|
||||
@@ -26,47 +26,47 @@ class OAuthSimple {
|
||||
* @return OAuthSimple (Object)
|
||||
*/
|
||||
function __construct ($APIKey = "", $sharedSecret=""){
|
||||
|
||||
|
||||
if (!empty($APIKey))
|
||||
{
|
||||
$this->_secrets['consumer_key'] = $APIKey;
|
||||
}
|
||||
|
||||
|
||||
if (!empty($sharedSecret))
|
||||
{
|
||||
$this->_secrets['shared_secret'] = $sharedSecret;
|
||||
}
|
||||
|
||||
|
||||
$this->_default_signature_method = "HMAC-SHA1";
|
||||
$this->_action = "GET";
|
||||
$this->_nonce_chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
||||
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the parameters and URL
|
||||
*
|
||||
|
||||
/**
|
||||
* Reset the parameters and URL
|
||||
*
|
||||
* @access public
|
||||
* @return OAuthSimple (Object)
|
||||
*/
|
||||
*/
|
||||
public function reset() {
|
||||
$this->_parameters = Array();
|
||||
$this->path = NULL;
|
||||
$this->sbs = NULL;
|
||||
|
||||
return $this;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the parameters either from a hash or a string
|
||||
*
|
||||
/**
|
||||
* Set the parameters either from a hash or a string
|
||||
*
|
||||
* @access public
|
||||
* @param(string, object) List of parameters for the call, this can either be a URI string (e.g. "foo=bar&gorp=banana" or an object/hash)
|
||||
* @return OAuthSimple (Object)
|
||||
*/
|
||||
*/
|
||||
public function setParameters ($parameters=Array()) {
|
||||
|
||||
|
||||
if (is_string($parameters))
|
||||
{
|
||||
$parameters = $this->_parseParameterString($parameters);
|
||||
@@ -103,24 +103,24 @@ class OAuthSimple {
|
||||
{
|
||||
$this->_parameters['oauth_version']="1.0";
|
||||
}
|
||||
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Convenience method for setParameters
|
||||
*
|
||||
*
|
||||
* @access public
|
||||
* @see setParameters
|
||||
*/
|
||||
public function setQueryString ($parameters)
|
||||
*/
|
||||
public function setQueryString ($parameters)
|
||||
{
|
||||
return $this->setParameters($parameters);
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Set the target URL (does not include the parameters)
|
||||
*
|
||||
*
|
||||
* @param path (String) the fully qualified URI (excluding query arguments) (e.g "http://example.org/foo")
|
||||
* @return OAuthSimple (Object)
|
||||
*/
|
||||
@@ -131,28 +131,28 @@ class OAuthSimple {
|
||||
throw new OAuthSimpleException('No path specified for OAuthSimple.setURL');
|
||||
}
|
||||
$this->_path=$path;
|
||||
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Convenience method for setURL
|
||||
*
|
||||
* @param path (String)
|
||||
* @param path (String)
|
||||
* @see setURL
|
||||
*/
|
||||
public function setPath ($path)
|
||||
public function setPath ($path)
|
||||
{
|
||||
return $this->_path=$path;
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Set the "action" for the url, (e.g. GET,POST, DELETE, etc.)
|
||||
*
|
||||
* @param action (String) HTTP Action word.
|
||||
* @return OAuthSimple (Object)
|
||||
*/
|
||||
public function setAction ($action)
|
||||
public function setAction ($action)
|
||||
{
|
||||
if (empty($action))
|
||||
{
|
||||
@@ -164,17 +164,17 @@ class OAuthSimple {
|
||||
throw new OAuthSimpleException('Invalid action specified for OAuthSimple.setAction');
|
||||
}
|
||||
$this->_action = $action;
|
||||
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Set the signatures (as well as validate the ones you have)
|
||||
*
|
||||
* @param signatures (object) object/hash of the token/signature pairs {api_key:, shared_secret:, oauth_token: oauth_secret:}
|
||||
* @return OAuthSimple (Object)
|
||||
*/
|
||||
public function signatures ($signatures)
|
||||
public function signatures ($signatures)
|
||||
{
|
||||
if (!empty($signatures) && !is_array($signatures))
|
||||
{
|
||||
@@ -182,7 +182,7 @@ class OAuthSimple {
|
||||
}
|
||||
if (!empty($signatures))
|
||||
{
|
||||
if (empty($this->_secrets))
|
||||
if (empty($this->_secrets))
|
||||
{
|
||||
$this->_secrets=Array();
|
||||
}
|
||||
@@ -216,16 +216,16 @@ class OAuthSimple {
|
||||
{
|
||||
throw new OAuthSimpleException('Missing oauth_secret for supplied oauth_token in OAuthSimple.signatures');
|
||||
}
|
||||
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setTokensAndSecrets($signatures)
|
||||
public function setTokensAndSecrets($signatures)
|
||||
{
|
||||
return $this->signatures($signatures);
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Set the signature method (currently only Plaintext or SHA-MAC1)
|
||||
*
|
||||
* @param method (String) Method of signing the transaction (only PLAINTEXT and SHA-MAC1 allowed for now)
|
||||
@@ -248,7 +248,7 @@ class OAuthSimple {
|
||||
throw new OAuthSimpleException ("Unknown signing method $method specified for OAuthSimple.setSignatureMethod");
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -259,8 +259,8 @@ class OAuthSimple {
|
||||
*
|
||||
* @param args (Array) hash of arguments for the call {action, path, parameters (array), method, signatures (array)} all arguments are optional.
|
||||
* @return (Array) signed values
|
||||
*/
|
||||
public function sign($args=array())
|
||||
*/
|
||||
public function sign($args=array())
|
||||
{
|
||||
if (!empty($args['action']))
|
||||
{
|
||||
@@ -280,12 +280,11 @@ class OAuthSimple {
|
||||
}
|
||||
if (empty($args['parameters']))
|
||||
{
|
||||
$args['parameters']=array();
|
||||
$args['parameters']=array();
|
||||
}
|
||||
$this->setParameters($args['parameters']);
|
||||
$normParams = $this->_normalizedParameters();
|
||||
$this->_parameters['oauth_signature'] = $this->_generateSignature($normParams);
|
||||
|
||||
|
||||
return Array (
|
||||
'parameters' => $this->_parameters,
|
||||
'signature' => self::_oauthEscape($this->_parameters['oauth_signature']),
|
||||
@@ -295,7 +294,7 @@ class OAuthSimple {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Return a formatted "header" string
|
||||
*
|
||||
* NOTE: This doesn't set the "Authorization: " prefix, which is required.
|
||||
@@ -303,9 +302,9 @@ class OAuthSimple {
|
||||
* ways to do that.
|
||||
*
|
||||
* @param args (Array)
|
||||
* @return $result (String)
|
||||
* @return $result (String)
|
||||
*/
|
||||
public function getHeaderString ($args=array())
|
||||
public function getHeaderString ($args=array())
|
||||
{
|
||||
if (empty($this->_parameters['oauth_signature']))
|
||||
{
|
||||
@@ -335,7 +334,7 @@ class OAuthSimple {
|
||||
return preg_replace('/, $/','',$result);
|
||||
}
|
||||
|
||||
private function _parseParameterString ($paramString)
|
||||
private function _parseParameterString ($paramString)
|
||||
{
|
||||
$elements = explode('&',$paramString);
|
||||
$result = array();
|
||||
@@ -364,7 +363,7 @@ class OAuthSimple {
|
||||
}
|
||||
|
||||
|
||||
private static function _oauthEscape($string)
|
||||
private static function _oauthEscape($string)
|
||||
{
|
||||
if ($string === 0) { return 0; }
|
||||
if ($string == '0') { return '0'; }
|
||||
@@ -372,21 +371,18 @@ class OAuthSimple {
|
||||
if (is_array($string)) {
|
||||
throw new OAuthSimpleException('Array passed to _oauthEscape');
|
||||
}
|
||||
$string = rawurlencode($string);
|
||||
$string = urlencode($string);
|
||||
|
||||
//FIX: rawurlencode of ~
|
||||
$string = str_replace('%7E','~', $string);
|
||||
$string = str_replace('+','%20',$string);
|
||||
$string = str_replace('!','%21',$string);
|
||||
$string = str_replace('*','%2A',$string);
|
||||
$string = str_replace('\'','%27',$string);
|
||||
$string = str_replace('(','%28',$string);
|
||||
$string = str_replace(')','%29',$string);
|
||||
//FIX: urlencode of ~ and '+'
|
||||
$string = str_replace(
|
||||
Array('%7E','+' ), // Replace these
|
||||
Array('~', '%20'), // with these
|
||||
$string);
|
||||
|
||||
return $string;
|
||||
}
|
||||
|
||||
private function _getNonce($length=5)
|
||||
private function _getNonce($length=5)
|
||||
{
|
||||
$result = '';
|
||||
$cLength = strlen($this->_nonce_chars);
|
||||
@@ -396,22 +392,22 @@ class OAuthSimple {
|
||||
$result .= substr($this->_nonce_chars,$rnum,1);
|
||||
}
|
||||
$this->_parameters['oauth_nonce'] = $result;
|
||||
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
private function _getApiKey()
|
||||
private function _getApiKey()
|
||||
{
|
||||
if (empty($this->_secrets['consumer_key']))
|
||||
{
|
||||
throw new OAuthSimpleException('No consumer_key set for OAuthSimple');
|
||||
}
|
||||
$this->_parameters['oauth_consumer_key']=$this->_secrets['consumer_key'];
|
||||
|
||||
|
||||
return $this->_parameters['oauth_consumer_key'];
|
||||
}
|
||||
|
||||
private function _getAccessToken()
|
||||
private function _getAccessToken()
|
||||
{
|
||||
if (!isset($this->_secrets['oauth_secret']))
|
||||
{
|
||||
@@ -422,69 +418,77 @@ class OAuthSimple {
|
||||
throw new OAuthSimpleException('No access token (oauth_token) set for OAuthSimple.');
|
||||
}
|
||||
$this->_parameters['oauth_token'] = $this->_secrets['oauth_token'];
|
||||
|
||||
|
||||
return $this->_parameters['oauth_token'];
|
||||
}
|
||||
|
||||
private function _getTimeStamp()
|
||||
private function _getTimeStamp()
|
||||
{
|
||||
return $this->_parameters['oauth_timestamp'] = time();
|
||||
}
|
||||
|
||||
private function _normalizedParameters()
|
||||
private function _normalizedParameters()
|
||||
{
|
||||
$normalized_keys = array();
|
||||
$return_array = array();
|
||||
|
||||
foreach ( $this->_parameters as $paramName=>$paramValue) {
|
||||
if (!preg_match('/\w+_secret/',$paramName) OR (strpos($paramValue, '@') !== 0 && !file_exists(substr($paramValue, 1))) )
|
||||
foreach ( $this->_parameters as $paramName=>$paramValue) {
|
||||
if (preg_match('/w+_secret/', $paramName) OR
|
||||
$paramName == "oauth_signature") {
|
||||
continue;
|
||||
}
|
||||
// Read parameters from a file. Hope you're practicing safe PHP.
|
||||
if (strpos($paramValue, '@') !== 0 && !file_exists(substr($paramValue, 1)))
|
||||
{
|
||||
if (is_array($paramValue))
|
||||
if (is_array($paramValue))
|
||||
{
|
||||
$normalized_keys[self::_oauthEscape($paramName)] = array();
|
||||
foreach($paramValue as $item)
|
||||
foreach($paramValue as $item)
|
||||
{
|
||||
array_push($normalized_keys[self::_oauthEscape($paramName)], self::_oauthEscape($item));
|
||||
}
|
||||
}
|
||||
else
|
||||
else
|
||||
{
|
||||
$normalized_keys[self::_oauthEscape($paramName)] = self::_oauthEscape($paramValue);
|
||||
$normalized_keys[self::_oauthEscape($paramName)] = self::_oauthEscape($paramValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ksort($normalized_keys);
|
||||
|
||||
foreach($normalized_keys as $key=>$val)
|
||||
|
||||
foreach($normalized_keys as $key=>$val)
|
||||
{
|
||||
if (is_array($val))
|
||||
if (is_array($val))
|
||||
{
|
||||
sort($val);
|
||||
foreach($val as $element)
|
||||
foreach($val as $element)
|
||||
{
|
||||
array_push($return_array, $key . "=" . $element);
|
||||
}
|
||||
}
|
||||
else
|
||||
else
|
||||
{
|
||||
array_push($return_array, $key .'='. $val);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
$presig = join("&", $return_array);
|
||||
$sig = $this->_generateSignature($presig);
|
||||
$this->_parameters['oauth_signature']=$sig;
|
||||
array_push($return_array, "oauth_signature=$sig");
|
||||
return join("&", $return_array);
|
||||
}
|
||||
|
||||
|
||||
private function _generateSignature ($parameters="")
|
||||
private function _generateSignature ($parameters="")
|
||||
{
|
||||
$secretKey = '';
|
||||
if(isset($this->_secrets['shared_secret']))
|
||||
{
|
||||
$secretKey = self::_oauthEscape($this->_secrets['shared_secret']);
|
||||
}
|
||||
|
||||
|
||||
$secretKey .= '&';
|
||||
if(isset($this->_secrets['oauth_secret']))
|
||||
{
|
||||
@@ -509,8 +513,8 @@ class OAuthSimple {
|
||||
}
|
||||
|
||||
class OAuthSimpleException extends Exception {
|
||||
|
||||
public function __construct($err, $isDebug = FALSE)
|
||||
|
||||
public function __construct($err, $isDebug = FALSE)
|
||||
{
|
||||
self::log_error($err);
|
||||
if ($isDebug)
|
||||
@@ -518,12 +522,12 @@ class OAuthSimpleException extends Exception {
|
||||
self::display_error($err, TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static function log_error($err)
|
||||
{
|
||||
error_log($err, 0);
|
||||
error_log($err, 0);
|
||||
}
|
||||
|
||||
|
||||
public static function display_error($err, $kill = FALSE)
|
||||
{
|
||||
print_r($err);
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
<?php
|
||||
|
||||
// Craptastic UNIT test for PHP OAuthSimple
|
||||
|
||||
require 'OAuthSimple.php';
|
||||
|
||||
$path = 'http://example.com/test';
|
||||
$static_nonce = 'abcd123';
|
||||
$static_time = 1234567890;
|
||||
$signatures = array('consumer_key' => 'test_key',
|
||||
'shared_secret' => 'test_secret',
|
||||
'oauth_token' => 'access_key',
|
||||
'oauth_secret' => 'access_secret');
|
||||
$parameters = array(
|
||||
'fruit'=>'bananas are <Awe+some!>',
|
||||
'number'=>42,
|
||||
// defining these here overrides the auto-generator.
|
||||
'oauth_nonce'=>$static_nonce,
|
||||
'oauth_timestamp'=>$static_time);
|
||||
$oauth = new OAuthSimple();
|
||||
$results = $oauth->sign(array('path'=>$path,
|
||||
'parameters'=>$parameters,
|
||||
'signatures'=>$signatures));
|
||||
|
||||
// ====
|
||||
$expected = array(
|
||||
'fruit'=>'bananas are <Awe+some!>',
|
||||
'number'=>42,
|
||||
'oauth_nonce'=>$static_nonce,
|
||||
'oauth_timestamp'=>$static_time,
|
||||
'oauth_consumer_key'=>$signatures['consumer_key'],
|
||||
'oauth_token'=>$signatures['oauth_token'],
|
||||
'oauth_signature_method'=>'HMAC-SHA1',
|
||||
'oauth_version'=>1.0,
|
||||
'oauth_signature'=>'IkTXsl3d/FV7uOY0p9CFFCxpdyQ=');
|
||||
if ($results['parameters'] != $expected) {
|
||||
print_r($results['parameters']);
|
||||
throw new OAuthSimpleException("Failure: incorrect parameters returned");
|
||||
}
|
||||
|
||||
|
||||
// ====
|
||||
$expected="IkTXsl3d%2FFV7uOY0p9CFFCxpdyQ%3D";
|
||||
if ($results['signature'] != $expected) {
|
||||
print $results['signature']."\n$expected\n";
|
||||
throw new OAuthSimpleException("Failure: incorrect signature returned");
|
||||
}
|
||||
|
||||
|
||||
// ====
|
||||
$expected="http://example.com/test?fruit=bananas%20are%20%3CAwe%2Bsome%21%3E&number=42&oauth_consumer_key=test_key&oauth_nonce=abcd123&oauth_signature_method=HMAC-SHA1&oauth_timestamp=1234567890&oauth_token=access_key&oauth_version=1.0&oauth_signature=IkTXsl3d/FV7uOY0p9CFFCxpdyQ=";
|
||||
if ($results['signed_url'] != $expected){
|
||||
print $results['signed_url']."\n$expected\n";
|
||||
throw new OAuthSimpleException("Failure: Invalid signed URL returned");
|
||||
}
|
||||
|
||||
// ====
|
||||
$expected='OAuth oauth_nonce="abcd123", oauth_timestamp="1234567890", oauth_consumer_key="test_key", oauth_token="access_key", oauth_signature_method="HMAC-SHA1", oauth_version="1.0", oauth_signature="IkTXsl3d%2FFV7uOY0p9CFFCxpdyQ%3D"';
|
||||
if ($results['header'] != $expected) {
|
||||
print $results['header']."\n$expected\n";
|
||||
throw new OAuthSimpleException("Failure: Invalid Header returned");
|
||||
}
|
||||
|
||||
// ====
|
||||
$expected='GET&http%3A%2F%2Fexample.com%2Ftest&fruit%3Dbananas%2520are%2520%253CAwe%252Bsome%2521%253E%26number%3D42%26oauth_consumer_key%3Dtest_key%26oauth_nonce%3Dabcd123%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1234567890%26oauth_token%3Daccess_key%26oauth_version%3D1.0';
|
||||
if ($results['sbs'] != $expected) {
|
||||
print $results['sbs']."\n$expected\n";
|
||||
throw new OAuthSimpleException("Failure: Invalid Base String returned");
|
||||
}
|
||||
|
||||
print("ok\n");
|
||||
Reference in New Issue
Block a user