Skip to content

Commit

Permalink
Merge branch 'master' of https://github.com/meltingice/node-oauth int…
Browse files Browse the repository at this point in the history
…o meltingice-master

Conflicts:
	Readme.md
  • Loading branch information
ciaranj committed May 10, 2011
2 parents 1fe0f3c + 50a7039 commit c1c9270
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 30 deletions.
15 changes: 8 additions & 7 deletions Readme.md
@@ -1,37 +1,38 @@
node-oauth
===========
A simple oauth API for node.js . This API allows users to authenticate against OAUTH providers, and thus act as OAuth consumers
A simple oauth API for node.js . This API allows users to authenticate against OAUTH providers, and thus act as OAuth consumers. It also has support for OAuth Echo, which is used for communicating with 3rd party media providers such as TwitPic and yFrog.

Tested against both Twitter (http://twitter.com), term.ie (http://term.ie/oauth/example/) and Yahoo!
Tested against Twitter (http://twitter.com), term.ie (http://term.ie/oauth/example/), TwitPic, and Yahoo!

Also provides rudimentary OAuth2 support, tested against facebook connect and github. For more complete usage examples please take a look
at connect-auth (http://github.com/ciaranj/connect-auth)
at connect-auth (http://github.com/ciaranj/connect-auth)

If you're running a node.js version more recent than 0.4 then you will need to use a version of node-oauth greater than or equal to 0.9.0.
If you're running a node.js version in the 0.2x stable branc, then you will need to use version 0.8.4.
If you're running a node.js version in the 0.2x stable branch, then you will need to use version 0.8.4.

Please be aware that when moving from 0.8.x to 0.9.0 there are no major API changes your, I've bumped the semi-major version element
so that I can release fixes to the 0.8.x stream if problems come out.

Change History
==============
* 0.9.1 - Added support for automatically following 302 redirects (Thanks neyric)
* 0.9.1 - Added support for automatically following 302 redirects (Thanks neyric) Added support for OAuth Echo (Thanks Ryan LeFevre)
* 0.9.0 - Compatibility fixes to bring node-oauth up to speed with node.js 0.4x [thanks to Rasmus Andersson for starting the work ]
* 0.8.4 - Fixed issue #14 (Parameter ordering ignored encodings). Added support for repeated parameter names. Implements issue #15 (Use native SHA1 if available, 10x speed improvement!). Fixed issue #16 (Should use POST when requesting access tokens.). Fixed Issue #17 (OAuth2 spec compliance). Implemented enhancement #13 (Adds support for PUT & DELETE http verbs). Fixes issue #18 (Complex/Composite url arguments [thanks novemberborn])
* 0.8.3 - Fixed an issue where the auth header code depended on the Array's toString method (Yohei Sasaki) Updated the getOAuthRequestToken method so we can access google's OAuth secured methods. Also re-implemented and fleshed out the test suite.
* 0.8.2 - The request returning methods will now write the POST body if provided (Chris Anderson), the code responsible for manipulating the headers is a bit safe now when working with other code (Paul McKellar) and tweaked the package.json to use index.js instead of main.js
* 0.8.1 - Added mechanism to get hold of a signed Node Request object, ready for attaching response listeners etc. (Perfect for streaming APIs)
* 0.8.0 - Standardised method capitalisation, the old getOauthAccessToken is now getOAuthAccessToken (Breaking change to existing code)
* 0.8.0 - Standardised method capitalisation, the old getOauthAccessToken is now getOAuthAccessToken (Breaking change to existing code)
* 0.7.7 - Looks like non oauth_ parameters where appearing within the Authorization headers, which I believe to be inccorrect.
* 0.7.6 - Added in oauth_verifier property to getAccessToken required for 1.0A
* 0.7.5 - Added in a main.js to simplify the require'ing of OAuth
* 0.7.4 - Minor change to add an error listener to the OAuth client (thanks troyk)
* 0.7.3 - OAuth 2 now sends a Content-Length Http header to keep nginx happy :)
* 0.7.2 - Fixes some broken unit tests!
* 0.7.2 - Fixes some broken unit tests!
* 0.7.0 - Introduces support for HTTPS end points and callback URLS for OAuth 1.0A and Oauth 2 (Please be aware that this was a breaking change to the constructor arguments order)

Contributors
============

* Ciaran Jessup - ciaranj@gmail.com
* Mark Wubben - http://equalmedia.com/
* Ryan LeFevre - http://meltingice.net
3 changes: 2 additions & 1 deletion index.js
@@ -1,2 +1,3 @@
exports.OAuth = require("./lib/oauth").OAuth;
exports.OAuth = require("./lib/oauth").OAuth;
exports.OAuthEcho = require("./lib/oauth").OAuthEcho;
exports.OAuth2 = require("./lib/oauth2").OAuth2;
82 changes: 61 additions & 21 deletions lib/oauth.js
Expand Up @@ -6,6 +6,8 @@ var crypto= require('crypto'),
querystring= require('querystring');

exports.OAuth= function(requestUrl, accessUrl, consumerKey, consumerSecret, version, authorize_callback, signatureMethod, nonceSize, customHeaders) {
this._echo = false;

this._requestUrl= requestUrl;
this._accessUrl= accessUrl;
this._consumerKey= consumerKey;
Expand All @@ -27,6 +29,26 @@ exports.OAuth= function(requestUrl, accessUrl, consumerKey, consumerSecret, vers
"User-Agent" : "Node authentication"}
};

exports.OAuthEcho= function(realm, verify_credentials, consumerKey, consumerSecret, version, signatureMethod, nonceSize, customHeaders) {
this._echo = true;

this._realm= realm;
this._verifyCredentials = verify_credentials;
this._consumerKey= consumerKey;
this._consumerSecret= this._encodeData( consumerSecret );
this._version= version;

if( signatureMethod != "PLAINTEXT" && signatureMethod != "HMAC-SHA1")
throw new Error("Un-supported signature method: " + signatureMethod );
this._signatureMethod= signatureMethod;
this._nonceSize= nonceSize || 32;
this._headers= customHeaders || {"Accept" : "*/*",
"Connection" : "close",
"User-Agent" : "Node authentication"};
}

exports.OAuthEcho.prototype = exports.OAuth.prototype;

exports.OAuth.prototype._getTimestamp= function() {
return Math.floor( (new Date()).getTime() / 1000 );
}
Expand Down Expand Up @@ -85,13 +107,18 @@ exports.OAuth.prototype._isParameterNameAnOAuthParameter= function(parameter) {
// build the OAuth request authorization header
exports.OAuth.prototype._buildAuthorizationHeaders= function(orderedParameters) {
var authHeader="OAuth ";
if (this._echo) {
authHeader += 'realm="' + this._realm + '",';
}

for( var i= 0 ; i < orderedParameters.length; i++) {
// Whilst the all the parameters should be included within the signature, only the oauth_ arguments
// should appear within the authorization header.
if( this._isParameterNameAnOAuthParameter(orderedParameters[i][0]) ) {
authHeader+= this._encodeData(orderedParameters[i][0])+"=\""+ this._encodeData(orderedParameters[i][1])+"\",";
authHeader+= "" + this._encodeData(orderedParameters[i][0])+"=\""+ this._encodeData(orderedParameters[i][1])+"\",";
}
}

authHeader= authHeader.substring(0, authHeader.length-1);
return authHeader;
}
Expand Down Expand Up @@ -223,30 +250,37 @@ exports.OAuth.prototype._prepareParameters= function( oauth_token, oauth_token_s
if( oauth_token ) {
oauthParameters["oauth_token"]= oauth_token;
}
if( extra_params ) {
for( var key in extra_params ) {
oauthParameters[key]= extra_params[key];

var sig;
if (!this._echo) {
if( extra_params ) {
for( var key in extra_params ) {
oauthParameters[key]= extra_params[key];
}
}
}
var parsedUrl= URL.parse( url, false );

if( parsedUrl.query ) {
var key2;
var extraParameters= querystring.parse(parsedUrl.query);
for(var key in extraParameters ) {
var value= extraParameters[key];
if( typeof value == "object" ){
// TODO: This probably should be recursive
for(key2 in value){
oauthParameters[key + "[" + key2 + "]"] = value[key2];
var parsedUrl= URL.parse( url, false );

if( parsedUrl.query ) {
var key2;
var extraParameters= querystring.parse(parsedUrl.query);
for(var key in extraParameters ) {
var value= extraParameters[key];
if( typeof value == "object" ){
// TODO: This probably should be recursive
for(key2 in value){
oauthParameters[key + "[" + key2 + "]"] = value[key2];
}
} else {
oauthParameters[key]= value;
}
} else {
oauthParameters[key]= value;
}
}
}

sig = this._getSignature( method, url, this._normaliseRequestParams(oauthParameters), oauth_token_secret);
} else {
sig = this._getSignature( "GET", this._verifyCredentials, this._normaliseRequestParams(oauthParameters), oauth_token_secret);
}

var sig= this._getSignature( method, url, this._normaliseRequestParams(oauthParameters), oauth_token_secret);
var orderedParameters= this._sortRequestParams( this._makeArrayOfArgumentsHash(oauthParameters) );
orderedParameters[orderedParameters.length]= ["oauth_signature", sig];
return orderedParameters;
Expand All @@ -263,7 +297,13 @@ exports.OAuth.prototype._performSecureRequest= function( oauth_token, oauth_toke
if( parsedUrl.protocol == "https:" && !parsedUrl.port ) parsedUrl.port= 443;

var headers= {};
headers["Authorization"]= this._buildAuthorizationHeaders(orderedParameters);
var authorization = this._buildAuthorizationHeaders(orderedParameters);
if (this._echo) {
headers["X-Verify-Credentials-Authorization"]= authorization;
} else {
headers["Authorization"]= authorization;
}

headers["Host"] = parsedUrl.host

for( var key in this._headers ) {
Expand Down
16 changes: 15 additions & 1 deletion tests/oauth.js
@@ -1,7 +1,8 @@
var vows = require('vows'),
assert = require('assert'),
events = require('events'),
OAuth= require('../lib/oauth').OAuth;
OAuth= require('../lib/oauth').OAuth,
OAuthEcho= require('../lib/oauth').OAuthEcho;

vows.describe('OAuth').addBatch({
'When generating the signature base string described in http://oauth.net/core/1.0/#sig_base_example': {
Expand Down Expand Up @@ -124,6 +125,19 @@ vows.describe('OAuth').addBatch({
assert.equal( oa.authHeader("http://somehost.com:3323/foo/poop?bar=foo", "token", "tokensecret"), 'OAuth oauth_consumer_key="consumerkey",oauth_nonce="ybHPeOEkAUJ3k2wJT9Xb43MjtSgTvKqp",oauth_signature_method="HMAC-SHA1",oauth_timestamp="1272399856",oauth_token="token",oauth_version="1.0",oauth_signature="zeOR0Wsm6EG6XSg0Vw%2FsbpoSib8%3D"');
}
},
'When get the OAuth Echo authorization header': {
topic: function () {
var realm = "http://foobar.com/";
var verifyCredentials = "http://api.foobar.com/verify.json";
var oa = new OAuthEcho(realm, verifyCredentials, "consumerkey", "consumersecret", "1.0A", "HMAC-SHA1");
oa._getTimestamp= function(){ return "1272399856"; }
oa._getNonce= function(){ return "ybHPeOEkAUJ3k2wJT9Xb43MjtSgTvKqp"; }
return oa;
},
'Provide a valid signature when a token and token secret is present': function (oa) {
assert.equal( oa.authHeader("http://somehost.com:3323/foo/poop?bar=foo", "token", "tokensecret"), 'OAuth realm="http://foobar.com/",oauth_consumer_key="consumerkey",oauth_nonce="ybHPeOEkAUJ3k2wJT9Xb43MjtSgTvKqp",oauth_signature_method="HMAC-SHA1",oauth_timestamp="1272399856",oauth_token="token",oauth_version="1.0A",oauth_signature="0rr1LhSxACX2IEWRq3uCb4IwtOs%3D"');
}
},
'When non standard ports are used': {
topic: function() {
var oa= new OAuth(null, null, null, null, null, null, "HMAC-SHA1"),
Expand Down

0 comments on commit c1c9270

Please sign in to comment.