Move Authentication validator and routes to typescript
parent
c98c07832d
commit
fad23ff3be
|
@ -1,39 +0,0 @@
|
|||
|
||||
var first_factor = require('./routes/FirstFactor');
|
||||
var second_factor = require('./routes/second_factor');
|
||||
var reset_password = require('./routes/reset_password');
|
||||
var verify = require('./routes/verify');
|
||||
var u2f_register_handler = require('./routes/u2f_register_handler');
|
||||
var totp_register = require('./routes/totp_register');
|
||||
var objectPath = require('object-path');
|
||||
|
||||
module.exports = {
|
||||
login: serveLogin,
|
||||
logout: serveLogout,
|
||||
verify: verify,
|
||||
first_factor: first_factor,
|
||||
second_factor: second_factor,
|
||||
reset_password: reset_password,
|
||||
u2f_register: u2f_register_handler,
|
||||
totp_register: totp_register,
|
||||
}
|
||||
|
||||
function serveLogin(req, res) {
|
||||
if(!(objectPath.has(req, 'session.auth_session'))) {
|
||||
req.session.auth_session = {};
|
||||
req.session.auth_session.first_factor = false;
|
||||
req.session.auth_session.second_factor = false;
|
||||
}
|
||||
res.render('login');
|
||||
}
|
||||
|
||||
function serveLogout(req, res) {
|
||||
var redirect_param = req.query.redirect;
|
||||
var redirect_url = redirect_param || '/';
|
||||
req.session.auth_session = {
|
||||
first_factor: false,
|
||||
second_factor: false
|
||||
}
|
||||
res.redirect(redirect_url);
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
|
||||
import FirstFactor = require("./routes/FirstFactor");
|
||||
import second_factor = require("./routes/second_factor");
|
||||
import reset_password = require("./routes/reset_password");
|
||||
import AuthenticationValidator = require("./routes/AuthenticationValidator");
|
||||
import u2f_register_handler = require("./routes/u2f_register_handler");
|
||||
import totp_register = require("./routes/totp_register");
|
||||
import objectPath = require("object-path");
|
||||
|
||||
import express = require("express");
|
||||
|
||||
export = {
|
||||
login: serveLogin,
|
||||
logout: serveLogout,
|
||||
verify: AuthenticationValidator,
|
||||
first_factor: FirstFactor,
|
||||
second_factor: second_factor,
|
||||
reset_password: reset_password,
|
||||
u2f_register: u2f_register_handler,
|
||||
totp_register: totp_register,
|
||||
};
|
||||
|
||||
function serveLogin(req: express.Request, res: express.Response) {
|
||||
if (!(objectPath.has(req, "session.auth_session"))) {
|
||||
req.session.auth_session = {};
|
||||
req.session.auth_session.first_factor = false;
|
||||
req.session.auth_session.second_factor = false;
|
||||
}
|
||||
res.render("login");
|
||||
}
|
||||
|
||||
function serveLogout(req: express.Request, res: express.Response) {
|
||||
const redirect_param = req.query.redirect;
|
||||
const redirect_url = redirect_param || "/";
|
||||
req.session.auth_session = {
|
||||
first_factor: false,
|
||||
second_factor: false
|
||||
};
|
||||
res.redirect(redirect_url);
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
|
||||
import objectPath = require("object-path");
|
||||
import BluebirdPromise = require("bluebird");
|
||||
import express = require("express");
|
||||
|
||||
function verify_filter(req: express.Request, res: express.Response) {
|
||||
const logger = req.app.get("logger");
|
||||
|
||||
if (!objectPath.has(req, "session.auth_session"))
|
||||
return BluebirdPromise.reject("No auth_session variable");
|
||||
|
||||
if (!objectPath.has(req, "session.auth_session.first_factor"))
|
||||
return BluebirdPromise.reject("No first factor variable");
|
||||
|
||||
if (!objectPath.has(req, "session.auth_session.second_factor"))
|
||||
return BluebirdPromise.reject("No second factor variable");
|
||||
|
||||
if (!objectPath.has(req, "session.auth_session.userid"))
|
||||
return BluebirdPromise.reject("No userid variable");
|
||||
|
||||
const host = objectPath.get<express.Request, string>(req, "headers.host");
|
||||
const domain = host.split(":")[0];
|
||||
|
||||
if (!req.session.auth_session.first_factor ||
|
||||
!req.session.auth_session.second_factor)
|
||||
return BluebirdPromise.reject("First or second factor not validated");
|
||||
|
||||
return BluebirdPromise.resolve();
|
||||
}
|
||||
|
||||
export = function(req: express.Request, res: express.Response) {
|
||||
verify_filter(req, res)
|
||||
.then(function () {
|
||||
res.status(204);
|
||||
res.send();
|
||||
})
|
||||
.catch(function (err) {
|
||||
req.app.get("logger").error(err);
|
||||
res.status(401);
|
||||
res.send();
|
||||
});
|
||||
};
|
||||
|
|
@ -1,44 +0,0 @@
|
|||
|
||||
module.exports = verify;
|
||||
|
||||
var objectPath = require('object-path');
|
||||
var BluebirdPromise = require('bluebird');
|
||||
|
||||
function verify_filter(req, res) {
|
||||
var logger = req.app.get('logger');
|
||||
|
||||
if(!objectPath.has(req, 'session.auth_session'))
|
||||
return BluebirdPromise.reject('No auth_session variable');
|
||||
|
||||
if(!objectPath.has(req, 'session.auth_session.first_factor'))
|
||||
return BluebirdPromise.reject('No first factor variable');
|
||||
|
||||
if(!objectPath.has(req, 'session.auth_session.second_factor'))
|
||||
return BluebirdPromise.reject('No second factor variable');
|
||||
|
||||
if(!objectPath.has(req, 'session.auth_session.userid'))
|
||||
return BluebirdPromise.reject('No userid variable');
|
||||
|
||||
var host = objectPath.get(req, 'headers.host');
|
||||
var domain = host.split(':')[0];
|
||||
|
||||
if(!req.session.auth_session.first_factor ||
|
||||
!req.session.auth_session.second_factor)
|
||||
return BluebirdPromise.reject('First or second factor not validated');
|
||||
|
||||
return BluebirdPromise.resolve();
|
||||
}
|
||||
|
||||
function verify(req, res) {
|
||||
verify_filter(req, res)
|
||||
.then(function() {
|
||||
res.status(204);
|
||||
res.send();
|
||||
})
|
||||
.catch(function(err) {
|
||||
req.app.get('logger').error(err);
|
||||
res.status(401);
|
||||
res.send();
|
||||
});
|
||||
}
|
||||
|
|
@ -1,17 +1,51 @@
|
|||
|
||||
import sinon = require("sinon");
|
||||
import express = require("express");
|
||||
|
||||
export interface RequestMock {
|
||||
app?: any;
|
||||
body?: any;
|
||||
session?: any;
|
||||
headers?: any;
|
||||
get?: any;
|
||||
}
|
||||
|
||||
export interface ResponseMock {
|
||||
send: sinon.SinonStub | sinon.SinonSpy;
|
||||
sendStatus: sinon.SinonStub;
|
||||
sendFile: sinon.SinonStub;
|
||||
sendfile: sinon.SinonStub;
|
||||
status: sinon.SinonStub;
|
||||
json: sinon.SinonStub;
|
||||
links: sinon.SinonStub;
|
||||
jsonp: sinon.SinonStub;
|
||||
download: sinon.SinonStub;
|
||||
contentType: sinon.SinonStub;
|
||||
type: sinon.SinonStub;
|
||||
format: sinon.SinonStub;
|
||||
attachment: sinon.SinonStub;
|
||||
set: sinon.SinonStub;
|
||||
header: sinon.SinonStub;
|
||||
headersSent: boolean;
|
||||
get: sinon.SinonStub;
|
||||
clearCookie: sinon.SinonStub;
|
||||
cookie: sinon.SinonStub;
|
||||
location: sinon.SinonStub;
|
||||
redirect: sinon.SinonStub;
|
||||
render: sinon.SinonStub;
|
||||
locals: sinon.SinonStub;
|
||||
charset: string;
|
||||
vary: sinon.SinonStub;
|
||||
app: any;
|
||||
write: sinon.SinonStub;
|
||||
writeContinue: sinon.SinonStub;
|
||||
writeHead: sinon.SinonStub;
|
||||
statusCode: number;
|
||||
statusMessage: string;
|
||||
setHeader: sinon.SinonStub;
|
||||
setTimeout: sinon.SinonStub;
|
||||
sendDate: boolean;
|
||||
getHeader: sinon.SinonStub;
|
||||
}
|
||||
|
||||
export function RequestMock(): RequestMock {
|
||||
|
@ -25,6 +59,38 @@ export function ResponseMock(): ResponseMock {
|
|||
return {
|
||||
send: sinon.stub(),
|
||||
status: sinon.stub(),
|
||||
json: sinon.stub()
|
||||
json: sinon.stub(),
|
||||
sendStatus: sinon.stub(),
|
||||
links: sinon.stub(),
|
||||
jsonp: sinon.stub(),
|
||||
sendFile: sinon.stub(),
|
||||
sendfile: sinon.stub(),
|
||||
download: sinon.stub(),
|
||||
contentType: sinon.stub(),
|
||||
type: sinon.stub(),
|
||||
format: sinon.stub(),
|
||||
attachment: sinon.stub(),
|
||||
set: sinon.stub(),
|
||||
header: sinon.stub(),
|
||||
headersSent: true,
|
||||
get: sinon.stub(),
|
||||
clearCookie: sinon.stub(),
|
||||
cookie: sinon.stub(),
|
||||
location: sinon.stub(),
|
||||
redirect: sinon.stub(),
|
||||
render: sinon.stub(),
|
||||
locals: sinon.stub(),
|
||||
charset: "utf-8",
|
||||
vary: sinon.stub(),
|
||||
app: sinon.stub(),
|
||||
write: sinon.stub(),
|
||||
writeContinue: sinon.stub(),
|
||||
writeHead: sinon.stub(),
|
||||
statusCode: 200,
|
||||
statusMessage: "message",
|
||||
setHeader: sinon.stub(),
|
||||
setTimeout: sinon.stub(),
|
||||
sendDate: true,
|
||||
getHeader: sinon.stub()
|
||||
};
|
||||
}
|
||||
|
|
|
@ -0,0 +1,110 @@
|
|||
|
||||
import assert = require("assert");
|
||||
import AuthenticationValidator = require("../../../src/lib/routes/AuthenticationValidator");
|
||||
import sinon = require("sinon");
|
||||
import winston = require("winston");
|
||||
|
||||
import express = require("express");
|
||||
|
||||
import ExpressMock = require("../mocks/express");
|
||||
import AccessControllerMock = require("../mocks/AccessController");
|
||||
|
||||
describe("test authentication token verification", function () {
|
||||
let req: ExpressMock.RequestMock;
|
||||
let res: ExpressMock.ResponseMock;
|
||||
let accessController: AccessControllerMock.AccessControllerMock;
|
||||
|
||||
beforeEach(function () {
|
||||
accessController = AccessControllerMock.AccessControllerMock();
|
||||
accessController.isDomainAllowedForUser.returns(true);
|
||||
|
||||
req = ExpressMock.RequestMock();
|
||||
res = ExpressMock.ResponseMock();
|
||||
req.headers = {};
|
||||
req.headers.host = "secret.example.com";
|
||||
req.app.get = sinon.stub();
|
||||
req.app.get.withArgs("config").returns({});
|
||||
req.app.get.withArgs("logger").returns(winston);
|
||||
req.app.get.withArgs("access controller").returns(accessController);
|
||||
});
|
||||
|
||||
interface AuthenticationSession {
|
||||
first_factor?: boolean;
|
||||
second_factor?: boolean;
|
||||
userid?: string;
|
||||
groups?: string[];
|
||||
}
|
||||
|
||||
it("should be already authenticated", function (done) {
|
||||
req.session = {};
|
||||
req.session.auth_session = {
|
||||
first_factor: true,
|
||||
second_factor: true,
|
||||
userid: "myuser",
|
||||
} as AuthenticationSession;
|
||||
|
||||
res.send = sinon.spy(function () {
|
||||
assert.equal(204, res.status.getCall(0).args[0]);
|
||||
done();
|
||||
});
|
||||
|
||||
AuthenticationValidator(req as express.Request, res as any);
|
||||
});
|
||||
|
||||
describe("given different cases of session", function () {
|
||||
function test_session(auth_session: AuthenticationSession, status_code: number) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
req.session = {};
|
||||
req.session.auth_session = auth_session;
|
||||
|
||||
res.send = sinon.spy(function () {
|
||||
assert.equal(status_code, res.status.getCall(0).args[0]);
|
||||
resolve();
|
||||
});
|
||||
|
||||
AuthenticationValidator(req as express.Request, res as any);
|
||||
});
|
||||
}
|
||||
|
||||
function test_unauthorized(auth_session: AuthenticationSession) {
|
||||
return test_session(auth_session, 401);
|
||||
}
|
||||
|
||||
function test_authorized(auth_session: AuthenticationSession) {
|
||||
return test_session(auth_session, 204);
|
||||
}
|
||||
|
||||
it("should not be authenticated when second factor is missing", function () {
|
||||
return test_unauthorized({
|
||||
userid: "user",
|
||||
first_factor: true,
|
||||
second_factor: false
|
||||
});
|
||||
});
|
||||
|
||||
it("should not be authenticated when first factor is missing", function () {
|
||||
return test_unauthorized({ first_factor: false, second_factor: true });
|
||||
});
|
||||
|
||||
it("should not be authenticated when userid is missing", function () {
|
||||
return test_unauthorized({
|
||||
first_factor: true,
|
||||
second_factor: true,
|
||||
groups: ["mygroup"],
|
||||
});
|
||||
});
|
||||
|
||||
it("should not be authenticated when first and second factor are missing", function () {
|
||||
return test_unauthorized({ first_factor: false, second_factor: false });
|
||||
});
|
||||
|
||||
it("should not be authenticated when session has not be initiated", function () {
|
||||
return test_unauthorized(undefined);
|
||||
});
|
||||
|
||||
it("should not be authenticated when session is partially initialized", function () {
|
||||
return test_unauthorized({ first_factor: true });
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -1,101 +0,0 @@
|
|||
|
||||
var assert = require('assert');
|
||||
var verify = require('../../../src/lib/routes/verify');
|
||||
var sinon = require('sinon');
|
||||
var winston = require('winston');
|
||||
|
||||
describe('test authentication token verification', function() {
|
||||
var req, res;
|
||||
var config_mock;
|
||||
var acl_matcher;
|
||||
|
||||
beforeEach(function() {
|
||||
acl_matcher = {
|
||||
is_domain_allowed: sinon.stub().returns(true)
|
||||
};
|
||||
var access_control = {
|
||||
matcher: acl_matcher
|
||||
}
|
||||
config_mock = {};
|
||||
req = {};
|
||||
res = {};
|
||||
req.headers = {};
|
||||
req.headers.host = 'secret.example.com';
|
||||
req.app = {};
|
||||
req.app.get = sinon.stub();
|
||||
req.app.get.withArgs('config').returns(config_mock);
|
||||
req.app.get.withArgs('logger').returns(winston);
|
||||
req.app.get.withArgs('access control').returns(access_control);
|
||||
res.status = sinon.spy();
|
||||
});
|
||||
|
||||
it('should be already authenticated', function(done) {
|
||||
req.session = {};
|
||||
req.session.auth_session = {
|
||||
first_factor: true,
|
||||
second_factor: true,
|
||||
userid: 'myuser',
|
||||
allowed_domains: ['*']
|
||||
};
|
||||
|
||||
res.send = sinon.spy(function() {
|
||||
assert.equal(204, res.status.getCall(0).args[0]);
|
||||
done();
|
||||
});
|
||||
|
||||
verify(req, res);
|
||||
});
|
||||
|
||||
describe('given different cases of session', function() {
|
||||
function test_session(auth_session, status_code) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
req.session = {};
|
||||
req.session.auth_session = auth_session;
|
||||
|
||||
res.send = sinon.spy(function() {
|
||||
assert.equal(status_code, res.status.getCall(0).args[0]);
|
||||
resolve();
|
||||
});
|
||||
|
||||
verify(req, res);
|
||||
});
|
||||
}
|
||||
|
||||
function test_unauthorized(auth_session) {
|
||||
return test_session(auth_session, 401);
|
||||
}
|
||||
|
||||
function test_authorized(auth_session) {
|
||||
return test_session(auth_session, 204);
|
||||
}
|
||||
|
||||
it('should not be authenticated when second factor is missing', function() {
|
||||
return test_unauthorized({ first_factor: true, second_factor: false });
|
||||
});
|
||||
|
||||
it('should not be authenticated when first factor is missing', function() {
|
||||
return test_unauthorized({ first_factor: false, second_factor: true });
|
||||
});
|
||||
|
||||
it('should not be authenticated when userid is missing', function() {
|
||||
return test_unauthorized({
|
||||
first_factor: true,
|
||||
second_factor: true,
|
||||
group: 'mygroup',
|
||||
});
|
||||
});
|
||||
|
||||
it('should not be authenticated when first and second factor are missing', function() {
|
||||
return test_unauthorized({ first_factor: false, second_factor: false });
|
||||
});
|
||||
|
||||
it('should not be authenticated when session has not be initiated', function() {
|
||||
return test_unauthorized(undefined);
|
||||
});
|
||||
|
||||
it('should not be authenticated when session is partially initialized', function() {
|
||||
return test_unauthorized({ first_factor: true });
|
||||
});
|
||||
});
|
||||
});
|
||||
|
Loading…
Reference in New Issue