Skip to content
This repository was archived by the owner on Apr 8, 2019. It is now read-only.

Assignment 4: add basic auth #121

Closed
Closed
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
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
test:
@node node_modules/lab/bin/lab -a code
test-cov:
@node node_modules/lab/bin/lab -a code -t 100 -L
@node node_modules/lab/bin/lab -a code -t 100 -Lv
test-cov-html:
@node node_modules/lab/bin/lab -a code -r html -o coverage.html

Expand Down
12 changes: 8 additions & 4 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,23 @@

var Hapi = require('hapi');
var Version = require('./version');

var Private = require('./private');

// Declare internals

var internals = {};


exports.init = function (port, next) {
exports.init = function (config, next) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

passing the user file via config wasn't in the assignment.


if (!config || typeof (config) !== 'object'){
return next(new Error('mandatory configuration object not provided'));
}

var server = new Hapi.Server();
server.connection({ port: port });
server.connection({ port: config.port });

server.register(Version, function (err) {
server.register([Version, {register: Private, options: {users: config.users}}], function (err) {

if (err) {
return next(err);
Expand Down
66 changes: 66 additions & 0 deletions lib/private.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// Load modules

var Basic = require('hapi-auth-basic');

// Declare internals

var internals = {
response: {
template: '<html><head><title>private page</title></head><body>Greetings %username%. Welcome to the private section.</body></html>',

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No templates was in the assignment.

generate: function (username){

return this.template.replace('%username%', username);
}
},
authStrategyName: 'private-basic',
authValidate: function(users, username, password, callback) {

var candidateUser = users.filter(function(userObject){

return userObject.username === username && userObject.password === password;
});
var user = candidateUser.length ? candidateUser[0] : null;
if (!user) {
return callback(null, false);
}
return callback(null, true, {username: user.username});
}
};


exports.register = function (server, options, next) {

var users = options.users;
if (users === null || users === undefined){
return next(new Error('private plugin requires users to be provided as option'));
}
if (!users.filter || !typeof (users.filter) === 'function'){
return next(new Error('provided users option must have a filter method'));
}

server.register(Basic, function(err){
if (err) {
return next(err);
}
server.auth.strategy(internals.authStrategyName, 'basic', { validateFunc: internals.authValidate.bind(internals, users) });

server.route({
method: 'GET',
path: '/private',
config: {
auth: internals.authStrategyName,
description: 'Returns a welcome message if user successfully authenticated via basic auth',
handler: function (request, reply) {

return reply(internals.response.generate(request.auth.credentials.username));
}
}
});

return next();
});
};

exports.register.attributes = {
name: 'private'
};
10 changes: 8 additions & 2 deletions lib/start.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,20 @@

var Hoek = require('hoek');
var Server = require('./index');
var Users = require('./users.json');


// Declare internals

var internals = {};
var internals = {
config: {
port: 8000,
users: Users
}
};


Server.init(8000, function (err, server) {
Server.init(internals.config, function (err, server) {

Hoek.assert(!err, err);
console.log('Server started at: ' + server.info.uri);
Expand Down
10 changes: 10 additions & 0 deletions lib/users.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[
{
"username": "dummy",
"password": "12345678"
},
{
"username": "janedoe",
"password": "azerty"
}
]
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "hueniversity",
"version": "0.0.3",
"version": "0.0.4",
"description": "Community learning experiment",
"main": "lib/index.js",
"repository": {
Expand All @@ -19,10 +19,11 @@
"homepage": "https://github.com/hueniverse/hueniversity",
"dependencies": {
"hapi": "8.x.x",
"hapi-auth-basic": "2.x.x",
"hoek": "2.x.x"
},
"scripts": {
"test": "node node_modules/lab/bin/lab -a code -t 100 -L",
"test": "node node_modules/lab/bin/lab -a code -t 100 -Lv",
"start": "node lib/start.js"
},
"devDependencies": {
Expand Down
18 changes: 14 additions & 4 deletions test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,29 @@ var Code = require('code');
var Lab = require('lab');
var Hueniversity = require('../lib');
var Version = require('../lib/version');
var Users = require('../lib/users.json');


// Test shortcuts

var lab = exports.lab = Lab.script();
var describe = lab.experiment;
var expect = Code.expect;
var it = lab.test;

it('throws if configuration is null', function(done){

Hueniversity.init(null, function (err, server) {

expect(err).to.exist();
expect(err.message).to.equal('mandatory configuration object not provided');

done();
});
});

it('starts server and returns hapi server object', function (done) {

Hueniversity.init(0, function (err, server) {
Hueniversity.init({port: 0, users: Users}, function (err, server) {

expect(err).to.not.exist();
expect(server).to.be.instanceof(Hapi.Server);
Expand All @@ -28,7 +38,7 @@ it('starts server and returns hapi server object', function (done) {

it('starts server on provided port', function (done) {

Hueniversity.init(5000, function (err, server) {
Hueniversity.init({port: 5000, users: Users}, function (err, server) {

expect(err).to.not.exist();
expect(server.info.port).to.equal(5000);
Expand All @@ -50,7 +60,7 @@ it('handles register plugin errors', { parallel: false }, function (done) {
name: 'fake version'
};

Hueniversity.init(0, function (err, server) {
Hueniversity.init({port: 0, users: Users}, function (err, server) {

expect(err).to.exist();
expect(err.message).to.equal('register version failed');
Expand Down
140 changes: 140 additions & 0 deletions test/private.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
// Load modules

var Code = require('code');
var Lab = require('lab');
var Hueniversity = require('../lib');
var Basic = require('hapi-auth-basic');
var Hoek = require('hoek');

// Declare internals

var internals = {};

// Test shortcuts

var lab = exports.lab = Lab.script();
var describe = lab.experiment;
var expect = Code.expect;
var it = lab.test;
var beforeEach = lab.beforeEach;
var afterEach = lab.afterEach;


describe('/private', function () {


it('returns unauthorized if user doesn\'t exist', function (done) {

Hueniversity.init({port: 0, users: internals.getTestUsers()}, function (err, server) {

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

var username = 'test';

var password = '12345678';
var request = { method: 'GET', url: '/private', headers: { authorization: internals.header(username, password) } };

server.inject(request, function (res) {

expect(res.statusCode).to.equal(401);

server.stop(done);
});
});
});

it('returns unauthorized if user exist but password is wrong', function (done) {

Hueniversity.init({port: 0, users: internals.getTestUsers()}, function (err, server) {

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

var username = 'jdoe';
var password = '12345678';
var request = { method: 'GET', url: '/private', headers: { authorization: internals.header(username, password) } };

server.inject(request, function (res) {

expect(res.statusCode).to.equal(401);

server.stop(done);
});
});
});

it('returns greetings if user exists and password is ok', function (done) {

Hueniversity.init({port: 0, users: internals.getTestUsers()}, function (err, server) {

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

var username = 'jdoe';
var password = 'qwerty';
var request = { method: 'GET', url: '/private', headers: { authorization: internals.header(username, password) } };

server.inject(request, function (res) {

expect(res.statusCode).to.equal(200);
expect(res.result).to.equal('<html><head><title>private page</title></head><body>Greetings jdoe. Welcome to the private section.</body></html>');

server.stop(done);
});
});
});

it('error bubbles up if basic auth plugin registration throws', { parallel: false }, function (done) {

var orig = Basic.register;
Basic.register = function (server, options, next) {

Basic.register = orig;
return next(new Error('register basic auth failed'));
};

Basic.register.attributes = {
name: 'fake basic auth'
};

Hueniversity.init({port: 0, users: internals.getTestUsers()}, function (err, server) {

expect(err).to.exist();
expect(err.message).to.equal('register basic auth failed');

done();
});
});

it('throws an error if users aren\'t provided', function(done){

Hueniversity.init({port: 0, users: null}, function (err, server) {

expect(err).to.exist();
expect(err.message).to.equal('private plugin requires users to be provided as option');

done();
});
});

it('throws an error if provided users object doesn\'t have filter method', function(done){

Hueniversity.init({port: 0, users: {}}, function (err, server) {

expect(err).to.exist();
expect(err.message).to.equal('provided users option must have a filter method');

done();
});
});
});

internals.header = function (username, password) {

return 'Basic ' + (new Buffer(username + ':' + password, 'utf8')).toString('base64');
};

internals.testUsers = [{username: 'jdoe', password: 'qwerty'}];

internals.getTestUsers = function(){

return Hoek.clone(internals.testUsers);
};
5 changes: 3 additions & 2 deletions test/version.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
var Code = require('code');
var Lab = require('lab');
var Pkg = require('../package.json');
var Server = require('../lib');
var Hueniversity = require('../lib');
var Users = require('../lib/users.json');


// Test shortcuts
Expand All @@ -18,7 +19,7 @@ describe('/version', function () {

it('returns the version from package.json', function (done) {

Server.init(0, function (err, server) {
Hueniversity.init({port: 0, users: Users}, function (err, server) {

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

Expand Down