This repository was archived by the owner on Apr 8, 2019. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 192
Assignment 4: add basic auth #121
Closed
FennNaten
wants to merge
7
commits into
outmoded:master
from
FennNaten:assignment-four-add-basic-auth
Closed
Changes from all commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
1179933
added plugin private.js: registers a private route using basic auth
FennNaten b004ca8
bring test coverage to 100%
FennNaten 6f37df2
fix misplaced return next() causing test to fail
FennNaten 18e0635
removes unused describe variable in test/index.js
FennNaten 8f20252
adds a level of indirection in users object to allow test users injec…
FennNaten f202881
refactor code so that users module is injected in index.init and take…
FennNaten 95186f2
removes unnecessary parallel:false statements where monkey patching h…
FennNaten File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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>', | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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' | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
[ | ||
{ | ||
"username": "dummy", | ||
"password": "12345678" | ||
}, | ||
{ | ||
"username": "janedoe", | ||
"password": "azerty" | ||
} | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
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.