Skip to content

Commit

Permalink
Merge branch 'pr-1253' into devel
Browse files Browse the repository at this point in the history
  • Loading branch information
n1mmy committed Sep 27, 2013
2 parents c6b8c65 + eda50d2 commit 1582372
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 22 deletions.
3 changes: 3 additions & 0 deletions History.md
Expand Up @@ -21,6 +21,9 @@
running on Linux machines with glibc 2.9 or newer (Ubuntu 10.04+, RHEL
and CentOS 6+, Fedora 10+, Debian 6+).

* Support OAuth1 services that require request token secrets as well as
authentication token secrets. #1253

## v0.6.5.1

* Fix syntax errors on lines that end with a backslash. #1326
Expand Down
39 changes: 28 additions & 11 deletions packages/oauth1/oauth1_binding.js
Expand Up @@ -4,16 +4,16 @@ var querystring = Npm.require("querystring");
// An OAuth1 wrapper around http calls which helps get tokens and
// takes care of HTTP headers
//
// @param consumerKey {String} As supplied by the OAuth1 provider
// @param consumerSecret {String} As supplied by the OAuth1 provider
// @param config {Object}
// - consumerKey (String): oauth consumer key
// - secret (String): oauth consumer secret
// @param urls {Object}
// - requestToken (String): url
// - authorize (String): url
// - accessToken (String): url
// - authenticate (String): url
OAuth1Binding = function(consumerKey, consumerSecret, urls) {
this._consumerKey = consumerKey;
this._secret = consumerSecret;
OAuth1Binding = function(config, urls) {
this._config = config;
this._urls = urls;
};

Expand All @@ -27,15 +27,26 @@ OAuth1Binding.prototype.prepareRequestToken = function(callbackUrl) {
var response = self._call('POST', self._urls.requestToken, headers);
var tokens = querystring.parse(response.content);

// XXX should we also store oauth_token_secret here?
if (!tokens.oauth_callback_confirmed)
throw new Error("oauth_callback_confirmed false when requesting oauth1 token", tokens);
throw new Error(
"oauth_callback_confirmed false when requesting oauth1 token", tokens);

self.requestToken = tokens.oauth_token;
self.requestTokenSecret = tokens.oauth_token_secret;
};

OAuth1Binding.prototype.prepareAccessToken = function(query) {
OAuth1Binding.prototype.prepareAccessToken = function(query, requestTokenSecret) {
var self = this;

// support implementations that use request token secrets. This is
// read by self._call.
//
// XXX make it a param to call, not something stashed on self? It's
// kinda confusing right now, everything except this is passed as
// arguments, but this is stored.
if (requestTokenSecret)
self.accessTokenSecret = requestTokenSecret;

var headers = self._buildHeader({
oauth_token: query.oauth_token
});
Expand Down Expand Up @@ -76,7 +87,7 @@ OAuth1Binding.prototype.post = function(url, params, callback) {
OAuth1Binding.prototype._buildHeader = function(headers) {
var self = this;
return _.extend({
oauth_consumer_key: self._consumerKey,
oauth_consumer_key: self._config.consumerKey,
oauth_nonce: Random.id().replace(/\W/g, ''),
oauth_signature_method: 'HMAC-SHA1',
oauth_timestamp: (new Date().valueOf()/1000).toFixed().toString(),
Expand All @@ -98,7 +109,7 @@ OAuth1Binding.prototype._getSignature = function(method, url, rawHeaders, access
self._encodeString(parameters)
].join('&');

var signingKey = self._encodeString(self._secret) + '&';
var signingKey = self._encodeString(self._config.secret) + '&';
if (accessTokenSecret)
signingKey += self._encodeString(accessTokenSecret);

Expand All @@ -108,8 +119,14 @@ OAuth1Binding.prototype._getSignature = function(method, url, rawHeaders, access
OAuth1Binding.prototype._call = function(method, url, headers, params, callback) {
var self = this;

// all URLs to be functions to support parameters/customization
if(typeof url === "function") {
url = url(self);
}

// Get the signature
headers.oauth_signature = self._getSignature(method, url, headers, self.accessTokenSecret, params);
headers.oauth_signature =
self._getSignature(method, url, headers, self.accessTokenSecret, params);

// Make a authorization string according to oauth1 spec
var authString = self._getAuthHeaderString(headers);
Expand Down
30 changes: 20 additions & 10 deletions packages/oauth1/oauth1_server.js
Expand Up @@ -12,8 +12,7 @@ Oauth._requestHandlers['1'] = function (service, query, res) {
}

var urls = service.urls;
var oauthBinding = new OAuth1Binding(
config.consumerKey, config.secret, urls);
var oauthBinding = new OAuth1Binding(config, urls);

if (query.requestTokenAndRedirect) {
// step 1 - get and store a request token
Expand All @@ -22,10 +21,20 @@ Oauth._requestHandlers['1'] = function (service, query, res) {
oauthBinding.prepareRequestToken(query.requestTokenAndRedirect);

// Keep track of request token so we can verify it on the next step
requestTokens[query.state] = oauthBinding.requestToken;
requestTokens[query.state] = {
requestToken: oauthBinding.requestToken,
requestTokenSecret: oauthBinding.requestTokenSecret
};

// support for scope/name parameters
var redirectUrl = undefined;
if(typeof urls.authenticate === "function") {
redirectUrl = urls.authenticate(oauthBinding);
} else {
redirectUrl = urls.authenticate + '?oauth_token=' + oauthBinding.requestToken;
}

// redirect to provider login, which will redirect back to "step 2" below
var redirectUrl = urls.authenticate + '?oauth_token=' + oauthBinding.requestToken;
res.writeHead(302, {'Location': redirectUrl});
res.end();
} else {
Expand All @@ -34,7 +43,8 @@ Oauth._requestHandlers['1'] = function (service, query, res) {
// token and access token secret and log in as user

// Get the user's request token so we can verify it and clear it
var requestToken = requestTokens[query.state];
var requestToken = requestTokens[query.state].requestToken;
var requestTokenSecret = requestTokens[query.state].requestTokenSecret;
delete requestTokens[query.state];

// Verify user authorized access and the oauth_token matches
Expand All @@ -45,17 +55,17 @@ Oauth._requestHandlers['1'] = function (service, query, res) {
// subsequent call to the `login` method will be immediate.

// Get the access token for signing requests
oauthBinding.prepareAccessToken(query);
oauthBinding.prepareAccessToken(query, requestTokenSecret);

// Run service-specific handler.
var oauthResult = service.handleOauthRequest(oauthBinding);

// Add the login result to the result map
Oauth._loginResultForCredentialToken[query.state] = {
serviceName: service.serviceName,
serviceData: oauthResult.serviceData,
options: oauthResult.options
};
serviceName: service.serviceName,
serviceData: oauthResult.serviceData,
options: oauthResult.options
};
}

// Either close the window, redirect, or render nothing
Expand Down
4 changes: 3 additions & 1 deletion packages/oauth1/oauth1_tests.js
Expand Up @@ -40,7 +40,9 @@ Tinytest.add("oauth1 - loginResultForCredentialToken is stored", function (test)
});

// simulate logging in using twitterfoo
OAuth1Test.requestTokens[credentialToken] = twitterfooAccessToken;
OAuth1Test.requestTokens[credentialToken] = {
requestToken: twitterfooAccessToken
};

var req = {
method: "POST",
Expand Down

0 comments on commit 1582372

Please sign in to comment.