Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

added allowRuntimeProviderParams to allow runtime query params #129

Merged
merged 1 commit into from
Aug 22, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ Each strategy accepts the following optional settings:
- Facebook supports `display` ('page', 'popup', or 'touch'), `auth_type`, `auth_nonce`.
- Google supports `access_type`, `approval_prompt`, `prompt`, `login_hint`, `user_id`, `hd`.
- Twitter supports `force_login`, `screen_name`.
- `allowRuntimeProviderParams` - allows passing query parameters from a **bell** protected endpoint to the auth request. It will merge the query params you pass along with the providerParams and any other predefined ones. Be aware that this will override predefined query parameters! Default to `false`.
- `scope` - Each built-in vendor comes with the required scope for basic profile information. Use `scope` to specify a different scope
as required by your application. Consult the provider for their specific supported scopes.
- `config` - a configuration object used to customize the provider settings. The built-in `'twitter'` provider accepts the `extendedProfile`
Expand Down
1 change: 1 addition & 0 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ internals.schema = Joi.object({
ttl: Joi.number(),
domain: Joi.string().allow(null),
providerParams: Joi.object(),
allowRuntimeProviderParams: Joi.boolean().default(false),
scope: Joi.array().items(Joi.string()).when('provider.protocol', { is: 'oauth2', otherwise: Joi.forbidden() }),
name: Joi.string().required(),
config: Joi.object(),
Expand Down
12 changes: 9 additions & 3 deletions lib/oauth.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,10 @@ exports.v1 = function (settings) {
var authQuery = settings.providerParams ? Hoek.clone(settings.providerParams) : {};
authQuery.oauth_token = payload.oauth_token;

if (settings.allowRuntimeProviderParams ) {
Hoek.merge(authQuery, request.query);
}

return reply.redirect(settings.provider.auth + '?' + internals.queryString(authQuery));
});
}
Expand Down Expand Up @@ -147,10 +151,12 @@ exports.v2 = function (settings) {
if (!request.query.code) {
var nonce = Cryptiles.randomString(22);
query = Hoek.clone(settings.providerParams) || {};
protocol = request.connection.info.protocol;
if (settings.forceHttps) {
protocol = 'https';

if (settings.allowRuntimeProviderParams ) {
Hoek.merge(query, request.query);
}

protocol = settings.forceHttps ? 'https' : request.connection.info.protocol;
query.client_id = settings.clientId;
query.response_type = 'code';
query.redirect_uri = internals.location(request, protocol, settings.location);
Expand Down
168 changes: 167 additions & 1 deletion test/oauth.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ var Code = require('code');
var Hapi = require('hapi');
var Hoek = require('hoek');
var Lab = require('lab');
var Joi = require('joi');
var Mock = require('./mock');
var OAuth = require('../lib/oauth');

Expand Down Expand Up @@ -223,6 +224,89 @@ describe('Bell', function () {
});
});

it('does not pass on runtime query params by default', 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) {

reply(request.auth.credentials);
}
}
});

server.inject('/login?runtime=true', function (res) {

expect(res.headers.location).to.equal(mock.uri + '/auth?oauth_token=1');

mock.stop(done);
});
});
});
});

it('passes on runtime query params with allowRuntimeProviderParams', 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,
allowRuntimeProviderParams: true
});

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

reply(request.auth.credentials);
}
}
});

server.inject('/login?runtime=true', function (res) {

expect(res.headers.location).to.equal(mock.uri + '/auth?oauth_token=1&runtime=true');

mock.stop(done);
});
});
});
});

it('authenticates an endpoint via oauth with auth provider parameters', function (done) {

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

it('authenticates an endpoint with runtime query parameters', function (done) {

var mock = new Mock.V2();
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,
providerParams: { special: true },
allowRuntimeProviderParams: true
});

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

reply(request.auth.credentials);
}
}
});

server.inject('/login?runtime=5', function (res) {

expect(res.headers.location).to.contain(mock.uri + '/auth?special=true&runtime=5&client_id=test&response_type=code&redirect_uri=http%3A%2F%2Flocalhost%3A80%2Flogin&state=');
mock.stop(done);
});
});
});
});

it('does not include runtime query parameters by default', function (done) {

var mock = new Mock.V2();
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,
providerParams: { special: true }
});

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

reply(request.auth.credentials);
}
}
});

server.inject('/login?notallowed=b', function (res) {

expect(res.headers.location).to.not.contain('notallowed');
mock.stop(done);
});
});
});
});
});

describe('#v2', function () {
Expand Down Expand Up @@ -1361,7 +1528,6 @@ describe('Bell', function () {

expect(res.statusCode).to.equal(500);
done();

});
});
});
Expand Down