Add mock request/response classes for testing

This commit is contained in:
Andrew Stewart 2014-06-04 12:51:35 -07:00
parent cae754672e
commit 5e21c52b95
2 changed files with 186 additions and 0 deletions

57
lib/api/auth/basic.js Normal file
View File

@ -0,0 +1,57 @@
/*
* Cylon API - Basic Auth
* cylonjs.com
*
* Copyright (c) 2013-2014 The Hybrid Group
* Licensed under the Apache 2.0 license.
*/
var http = require('http');
module.exports = function(config) {
var user = config.user,
pass = config.pass;
return function auth(req, res, next) {
var auth = req.headers.authorization;
if (!auth) {
return unauthorized(res);
}
// malformed
var parts = auth.split(' ');
if ('basic' != parts[0].toLowerCase() || !parts[1]) {
return next(error(400));
}
auth = parts[1];
// credentials
auth = new Buffer(auth, 'base64').toString();
auth = auth.match(/^([^:]+):(.+)$/);
if (!auth) {
return unauthorized(res);
}
if (auth[1] === user && auth[2] === pass) {
return next();
}
return unauthorized(res);
};
};
var unauthorized = function unauthorized(res) {
res.statusCode = 401;
res.setHeader('WWW-Authenticate', 'Basic realm="Authorization Required"');
res.end('Unauthorized');
};
var error = function error(code, msg){
var err = new Error(msg || http.STATUS_CODES[code]);
err.status = code;
return err;
};

View File

@ -0,0 +1,129 @@
'use strict'
var basic = source('api/auth/basic');
var MockRequest = require('../../../support/mock_request'),
MockResponse = require('../../../support/mock_response');
describe("Basic Auth", function() {
var opts = { user: 'user', pass: 'pass' },
req,
res,
next;
basic = basic(opts);
beforeEach(function() {
req = new MockRequest();
res = new MockResponse();
next = spy();
var auth = new Buffer("user:pass", "utf8").toString('base64');
req.headers = { authorization: "Basic " + auth };
});
var checkUnauthorized = function() {
var result;
beforeEach(function() {
result = basic(req, res, next);
});
it("returns false", function() {
expect(result).to.be.falsy;
});
it("sends a 401 error", function() {
expect(res.statusCode).to.be.eql(401);
expect(res.end).to.be.calledWith("Unauthorized");
});
};
var checkError = function() {
var result;
beforeEach(function() {
result = basic(req, res, next);
});
it("triggers next with an error", function() {
expect(next).to.be.called;
});
};
context("with a valid request", function() {
var result;
beforeEach(function() {
result = basic(req, res, next);
});
it("returns true", function() {
expect(result).to.be.truthy;
});
it("doesn't modify the response", function() {
expect(res.end).to.not.be.called;
})
});
context("if the user/pass don't match", function() {
beforeEach(function() {
var auth = new Buffer("bad:wrong", "utf8").toString('base64');
req.headers = { authorization: "Basic " + auth };
});
checkUnauthorized();
});
context("if there is already an authorized user", function() {
var result;
beforeEach(function() {
req.user = 'user';
result = basic(req, res, next);
});
it("returns true", function() {
expect(result).to.be.truthy;
});
it("doesn't modify the response", function() {
expect(res.end).to.not.be.called;
})
});
context("if there are no authorization headers", function() {
beforeEach(function() {
delete req.headers.authorization;
});
checkUnauthorized();
});
context("the authorization type isn't Basic", function() {
beforeEach(function() {
var auth = new Buffer("user:pass", "utf8").toString('base64');
req.headers = { authorization: "Digest " + auth };
});
checkError();
});
context("the authorization header is missing content", function() {
beforeEach(function() {
req.headers = { authorization: "Basic" };
});
checkError();
});
context("if the authorization header isn't formatted correctly", function() {
beforeEach(function() {
var auth = new Buffer("user-pass", "utf8").toString('base64');
req.headers = { authorization: "Basic " + auth };
});
checkUnauthorized();
});
});