Skip to content

Commit

Permalink
Merge pull request hapijs#91 from hapijs/client
Browse files Browse the repository at this point in the history
OAuth client resource() endpoint
  • Loading branch information
geek committed May 27, 2015
2 parents c792f52 + 5c21a2f commit 4b5650e
Show file tree
Hide file tree
Showing 4 changed files with 125 additions and 24 deletions.
62 changes: 42 additions & 20 deletions lib/oauth.js
Original file line number Diff line number Diff line change
Expand Up @@ -304,34 +304,45 @@ internals.Client.prototype.temporary = function (oauth_callback, callback) {
};


internals.Client.prototype.token = function (oauth_token, oauth_verifier, tokenSecret, callback) {
internals.Client.prototype.token = function (oauthToken, oauthVerifier, tokenSecret, callback) {

// Token Credentials (2.3)

var oauth = {
oauth_token: oauth_token,
oauth_verifier: oauth_verifier
oauth_token: oauthToken,
oauth_verifier: oauthVerifier
};

this.request('post', this.settings.token, null, oauth, tokenSecret, 'token credentials', callback);
};


internals.Client.prototype.get = function (uri, params, oauth_token, tokenSecret, callback) {
internals.Client.prototype.get = function (uri, params, oauthToken, tokenSecret, callback) {

this.resource('get', uri, params, { token: oauthToken, secret: tokenSecret }, callback);
};


internals.Client.prototype.resource = function (method, uri, params, options, callback) {

// Making Requests (3.1)

var oauth = {
oauth_token: oauth_token
oauth_token: options.token
};

this.request('get', uri, params, oauth, tokenSecret, 'token credentials', callback);
};
if (!options.stream) {
return this.request(method, uri, params, oauth, options.secret, 'resource', callback);
}

this._prepare(method, uri, params, oauth, options, function (method, uri, header) {

Wreck.request(method, uri, { headers: { Authorization: header } }, callback);
});
};

internals.Client.prototype.request = function (method, uri, params, oauth, tokenSecret, type, callback) {

var provider = this.provider;
internals.Client.prototype._prepare = function (method, uri, params, oauth, options, next) {

if (this.settings.version) {
oauth.oauth_version = this.settings.version;
Expand All @@ -341,23 +352,34 @@ internals.Client.prototype.request = function (method, uri, params, oauth, token
oauth.oauth_timestamp = Math.floor(Date.now() / 1000).toString();
oauth.oauth_consumer_key = this.settings.clientId;
oauth.oauth_signature_method = 'HMAC-SHA1';
oauth.oauth_signature = this.signature(method, uri, params, oauth, tokenSecret);
oauth.oauth_signature = this.signature(method, uri, params, oauth, options.secret);

var query = params ? ('?' + Querystring.encode(params)) : '';
Wreck[method](uri + query, { headers: { Authorization: internals.Client.header(oauth) } }, function (err, res, payload) {
return next(method, uri + query, internals.Client.header(oauth));
};

if (err ||
res.statusCode !== 200) {

return callback(Boom.internal('Failed obtaining ' + provider + ' ' + type, err || payload));
}
internals.Client.prototype.request = function (method, uri, params, oauth, tokenSecret, type, callback) {

payload = internals.parse(payload);
if (payload instanceof Error) {
return callback(Boom.internal('Received invalid payload from ' + provider + ' ' + type + ' endpoint', payload));
}
var desc = this.provider + ' ' + type;

this._prepare(method, uri, params, oauth, { secret: tokenSecret }, function (method, uri, header) {

return callback(null, payload);
Wreck[method.toLowerCase()](uri, { headers: { Authorization: header } }, function (err, res, payload) {

if (err ||
res.statusCode !== 200) {

return callback(Boom.internal('Failed obtaining ' + desc, err || payload));
}

payload = internals.parse(payload);
if (payload instanceof Error) {
return callback(Boom.internal('Received invalid payload from ' + desc + ' endpoint', payload));
}

return callback(null, payload);
});
});
};

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "bell",
"description": "Third-party login plugin for hapi",
"version": "2.8.0",
"version": "2.9.0",
"repository": "git://github.com/hapijs/bell",
"main": "lib/index.js",
"keywords": [
Expand Down
20 changes: 17 additions & 3 deletions test/mock.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ exports.V1 = internals.V1 = function (fail) {
oauth_callback_confirmed: true
};

reply(Querystring.encode(payload)).type('application/x-www-form-urlencoded');
return reply(Querystring.encode(payload)).type('application/x-www-form-urlencoded');
}
}
},
Expand All @@ -75,7 +75,7 @@ exports.V1 = internals.V1 = function (fail) {
token.verifier = '123';

var extra = Object.keys(request.query).length > 1 ? '&extra=true' : '';
reply().redirect(unescape(token.callback) + '?oauth_token=' + request.query.oauth_token + '&oauth_verifier=' + token.verifier + extra);
return reply().redirect(unescape(token.callback) + '?oauth_token=' + request.query.oauth_token + '&oauth_verifier=' + token.verifier + extra);
}
}
},
Expand Down Expand Up @@ -106,7 +106,21 @@ exports.V1 = internals.V1 = function (fail) {
payload.screen_name = 'Steve Stevens';
}

reply(Querystring.encode(payload)).type('application/x-www-form-urlencoded');
return reply(Querystring.encode(payload)).type('application/x-www-form-urlencoded');
}
}
},
{
method: '*',
path: '/resource',
config: {
bind: this,
handler: function (request, reply) {

var header = Hawk.utils.parseAuthorizationHeader(request.headers.authorization.replace(/OAuth/i, 'Hawk'), ['realm', 'oauth_consumer_key', 'oauth_token', 'oauth_signature_method', 'oauth_verifier', 'oauth_signature', 'oauth_version', 'oauth_timestamp', 'oauth_nonce']);
expect(header.oauth_token).to.equal('final');

return reply('some text reply');
}
}
}
Expand Down
65 changes: 65 additions & 0 deletions test/oauth.js
Original file line number Diff line number Diff line change
Expand Up @@ -430,6 +430,7 @@ describe('Bell', function () {
});
});
});

it('forces https in callback_url when set in options', function (done) {

var mock = new Mock.V1();
Expand Down Expand Up @@ -479,6 +480,7 @@ describe('Bell', function () {
});
});
});

it('uses location setting in callback_url when set in options', function (done) {

var mock = new Mock.V1();
Expand Down Expand Up @@ -528,6 +530,69 @@ describe('Bell', function () {
});
});
});

it('returns resource response stream', { parallel: false }, function (done) {

var mock = new Mock.V1();
mock.start(function (provider) {

var server = new Hapi.Server();
server.connection({ host: 'localhost', port: 80 });
server.register(Bell, function (err) {

expect(err).to.not.exist();

server.auth.strategy('custom', 'bell', {
password: 'password',
isSecure: false,
clientId: 'test',
clientSecret: 'secret',
provider: provider
});

server.route({
method: '*',
path: '/login',
config: {
auth: 'custom',
handler: function (request, reply) {

var client = new Bell.oauth.Client({
name: 'twitter',
provider: provider,
clientId: 'test',
clientSecret: 'secret'
});

var credentials = request.auth.credentials;
client.resource('GET', mock.uri + '/resource', null, { token: credentials.token, secret: credentials.secret, stream: true }, function (err, res) {

expect(err).to.not.exist();
return reply(res);
});
}
}
});

server.inject('/login?next=%2Fhome', function (res) {

var cookie = res.headers['set-cookie'][0].split(';')[0] + ';';
expect(res.headers.location).to.equal(mock.uri + '/auth?oauth_token=1');

mock.server.inject(res.headers.location, function (res) {

expect(res.headers.location).to.equal('http://localhost:80/login?oauth_token=1&oauth_verifier=123');

server.inject({ url: res.headers.location, headers: { cookie: cookie } }, function (res) {

expect(res.result).to.equal('some text reply');
mock.stop(done);
});
});
});
});
});
});
});

describe('#v2', function () {
Expand Down

0 comments on commit 4b5650e

Please sign in to comment.