From fadb0192b64f044b57e9306bca89d23cc46bc21e Mon Sep 17 00:00:00 2001 From: Christian Amor Kvalheim Date: Wed, 14 Apr 2010 20:49:49 +0200 Subject: [PATCH] Fixed code to work with google signature style and standard oauth --- lib/oauth/oauth.js | 19 +++++++++++++--- lib/oauth/oauth_services.js | 43 +++++++++++++++++++++++++++++++------ 2 files changed, 52 insertions(+), 10 deletions(-) diff --git a/lib/oauth/oauth.js b/lib/oauth/oauth.js index 5884adc..dcd6b73 100644 --- a/lib/oauth/oauth.js +++ b/lib/oauth/oauth.js @@ -46,13 +46,19 @@ exports.OAuth = Plugin.extend({ **/ var requestTokenMethod = function() { var self = this; - plugin.oauth_service.requestToken(this.method, 'http', this.headers['host'], this.url.href, this.headers, this.params, function(err, result) { + var finalPath = this.url.href.split(/\?/)[0]; + + plugin.oauth_service.requestToken(this.method, 'http', this.headers['host'], finalPath, this.headers, this.params, function(err, result) { if(err) { + sys.puts("======================== status:" + err.statusCode); + sys.puts("======================== message:" + err.message); + self.halt(err.statusCode, err.message) } else { self.halt(200, ["oauth_token=" + result["token"], "oauth_token_secret=" + result["token_secret"], "oauth_callback_confirmed=" + result["oauth_callback_confirmed"]].join("&")); } }); + // self.halt(400, querystring.escape("oauth_token=82fac54b189e080000010000&oauth_token_secret=82fac54b3eba010000020000&oauth_callback_confirmed=true")); }; // Handle both get and request methods post(options['request_token_url'], requestTokenMethod); @@ -96,8 +102,11 @@ exports.OAuth = Plugin.extend({ plugin.authorize_provider.call(self, err, false, {token:oauth_token}); } else { if(result.callback != null && result.callback != "oob") { + var callback = querystring.unescape(result.callback); + // Correctly add the tokens if the callback has a ? allready + var redirect_url = callback.match(/\?/) != null ? "&oauth_token=" + result.token + "&oauth_verifier=" + result.verifier : "?oauth_token=" + result.token + "&oauth_verifier=" + result.verifier; // Signal that a redirect is in order after finished process - self.redirect(querystring.unescape(result.callback) + "?oauth_token=" + result.token + "&oauth_verifier=" + result.verifier); + self.redirect(querystring.unescape(result.callback) + redirect_url); } else { plugin.authorization_finished_provider.call(self, err, result); } @@ -111,9 +120,13 @@ exports.OAuth = Plugin.extend({ **/ var accessTokenMethod = function() { var self = this; + var finalPath = this.url.href.split(/\?/)[0]; - plugin.oauth_service.accessToken(this.method, 'http', this.headers['host'], this.url.href, this.headers, this.params, function(err, result) { + plugin.oauth_service.accessToken(this.method, 'http', this.headers['host'], finalPath, this.headers, this.params, function(err, result) { if(err) { + sys.puts("======================== status:" + err.statusCode); + sys.puts("======================== message:" + err.message); + self.halt(err.statusCode, err.message); } else { self.halt(200, "oauth_token=" + result.access_token + "&oauth_token_secret=" + result.token_secret); diff --git a/lib/oauth/oauth_services.js b/lib/oauth/oauth_services.js index ac99b3a..c9c2dd4 100644 --- a/lib/oauth/oauth_services.js +++ b/lib/oauth/oauth_services.js @@ -36,9 +36,9 @@ OAuthServices.prototype.authorize = function(method, protocol, url, path, header self.provider.applicationByConsumerKey(token.consumer_key, function(err, user) { if(user.consumer_key == null || user.secret == null) { callback(new errors.OAuthProviderError("provider: applicationByConsumerKey must return a object with fields [token, secret]"), null); return;} // If we have a user for this consumer key let's calculate the signature - var calculatedSignature = self.calculateSignature(method, protocol, url, path, requestParameters, token.token_secret, user.secret); + var calculatedSignature = self.calculateSignature(method, protocol, url, path, requestParameters, token.token_secret, user.secret); // Check if the signature is correct and return a access token - if(calculatedSignature == requestParameters.oauth_signature) { + if(calculatedSignature == requestParameters.oauth_signature || self.calculateSignatureGoogleWay(method, protocol, url, path, requestParameters, token.token_secret, user.secret) == requestParameters.oauth_signature) { callback(null, true); } else { callback(new errors.OAuthBadRequestError("Invalid signature"), null); @@ -80,7 +80,7 @@ OAuthServices.prototype.requestToken = function(method, protocol, url, path, hea // If we have a user for this consumer key let's calculate the signature var calculatedSignature = self.calculateSignature(method, protocol, url, path, requestParameters, user.token, user.secret); // Check if the signature is correct and return a request token - if(calculatedSignature == requestParameters.oauth_signature) { + if(calculatedSignature == requestParameters.oauth_signature || self.calculateSignatureGoogleWay(method, protocol, url, path, requestParameters, user.token, user.secret) == requestParameters.oauth_signature) { self.provider.generateRequestToken(requestParameters.oauth_consumer_key, requestParameters.oauth_callback, function(err, result) { if(err) { callback(new errors.OAuthProviderError("internal error"), null); @@ -101,6 +101,10 @@ OAuthServices.prototype.requestToken = function(method, protocol, url, path, hea OAuthServices.prototype.accessToken = function(method, protocol, url, path, headers, parameters, callback) { var requestParameters = this.parseParameters(headers, parameters); if(requestParameters == null) { callback(new errors.OAuthBadRequestError("Missing required parameter"), null); return }; + + sys.puts(sys.inspect(requestParameters)); + sys.puts(sys.inspect(headers)); + // Ensure correct parameters are available if(!this.validateParameters(requestParameters, ['oauth_consumer_key', 'oauth_token', 'oauth_signature_method', 'oauth_signature', 'oauth_timestamp', 'oauth_nonce', 'oauth_verifier'])) { callback(new errors.OAuthBadRequestError("Missing required parameter")); return }; var self = this; @@ -127,7 +131,7 @@ OAuthServices.prototype.accessToken = function(method, protocol, url, path, head // If we have a user for this consumer key let's calculate the signature var calculatedSignature = self.calculateSignature(method, protocol, url, path, requestParameters, tokenObject.token_secret, user.secret); // Check if the signature is correct and return a access token - if(calculatedSignature == requestParameters.oauth_signature) { + if(calculatedSignature == requestParameters.oauth_signature || self.calculateSignatureGoogleWay(method, protocol, url, path, requestParameters, tokenObject.token_secret, user.secret) == requestParameters.oauth_signature) { self.provider.generateAccessToken(requestParameters['oauth_token'], function(err, result) { if(result.access_token == null || result.token_secret == null) { callback(new errors.OAuthProviderError("generateAccessToken must return a object with fields [access_token, token_secret]"), null); return; } callback(null, result); @@ -185,18 +189,43 @@ OAuthServices.prototype.calculateSignature = function(method, protocol, url, pat var values = []; for(var name in parameters) { if(name != 'oauth_signature') values.push(name); }; values = values.sort(); - // Let's build the actual string for the signature var concatString = method + "&" + querystring.escape(protocol + "://" + url + path) + "&" + querystring.escape(values.map(function(value) { return value + "=" + parameters[value]; }, '').join("&")); + // + // sys.puts("---------------------------------------------------------------------------"); + // sys.puts(concatString); + // sys.puts("---------------------------------------------------------------------------"); + // // Calculated signature return querystring.escape(crypto.SHA1.b64_hmac_sha1(key, concatString) + "="); } +OAuthServices.prototype.calculateSignatureGoogleWay = function(method, protocol, url, path, parameters, token, secret) { + // Create secret key for encryption + var key = secret + "&" + (token != null ? token : ''); + // Create array of names and sort it + var values = []; + for(var name in parameters) { if(name != 'oauth_signature') values.push(name); }; + values = values.sort(); + var concatString = method + "&" + querystring.escape(protocol + "://" + url + path) + "&" + querystring.escape(values.map(function(value) { + return querystring.escape(value) + "=" + querystring.escape(parameters[value]); + }, '').join("&")); + + // sys.puts("---------------------------------------------------------------------------"); + // sys.puts(concatString); + // sys.puts("---------------------------------------------------------------------------"); + + // Calculated signature + return crypto.SHA1.b64_hmac_sha1(key, concatString) + "="; +} + OAuthServices.prototype.parseParameters = function(headers, parameters) { // Check if this is sent by headers or parameters - if(parameters['oauth_consumer_key'] != null) { - return parameters; + if(parameters.get != null && parameters.get['oauth_consumer_key'] != null) { + return parameters.get; + } else if(parameters.post != null && parameters.post['oauth_consumer_key'] != null) { + return parameters.post; } else if(headers['authorization'] != null && headers['authorization'].indexOf('OAuth') != -1) { var authorizationString = headers['authorization'].substring('OAuth '.length, headers['authorization'].length); // Trim the strings and split the values