mirror of
https://github.com/0rangebananaspy/authelia.git
synced 2024-09-14 22:47:21 +07:00
Move TOTP Validator and Generator to typescript
This commit is contained in:
parent
40e02d23bf
commit
bf74667726
|
@ -8,6 +8,7 @@
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "./node_modules/.bin/mocha --compilers ts:ts-node/register --recursive test/unitary",
|
"test": "./node_modules/.bin/mocha --compilers ts:ts-node/register --recursive test/unitary",
|
||||||
|
"test-dbg": "./node_modules/.bin/mocha --debug-brk --compilers ts:ts-node/register --recursive test/unitary",
|
||||||
"int-test": "./node_modules/.bin/mocha --recursive test/integration",
|
"int-test": "./node_modules/.bin/mocha --recursive test/integration",
|
||||||
"coverage": "./node_modules/.bin/istanbul cover _mocha -- -R spec --recursive test",
|
"coverage": "./node_modules/.bin/istanbul cover _mocha -- -R spec --recursive test",
|
||||||
"build-ts": "tsc",
|
"build-ts": "tsc",
|
||||||
|
|
|
@ -10,7 +10,7 @@ interface DatedDocument {
|
||||||
date: Date;
|
date: Date;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class AuthenticationRegulator {
|
export default class AuthenticationRegulator {
|
||||||
private _user_data_store: any;
|
private _user_data_store: any;
|
||||||
private _lock_time_in_seconds: number;
|
private _lock_time_in_seconds: number;
|
||||||
|
|
||||||
|
|
|
@ -1,22 +0,0 @@
|
||||||
import * as winston from "winston";
|
|
||||||
import nodemailer = require("nodemailer");
|
|
||||||
|
|
||||||
export interface Nodemailer {
|
|
||||||
createTransport: (options?: any, defaults?: Object) => nodemailer.Transporter;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface GlobalDependencies {
|
|
||||||
u2f: object;
|
|
||||||
nodemailer: Nodemailer;
|
|
||||||
ldapjs: object;
|
|
||||||
session: any;
|
|
||||||
winston: winston.Winston;
|
|
||||||
speakeasy: object;
|
|
||||||
nedb: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type NodemailerDependencies = Nodemailer;
|
|
||||||
|
|
||||||
export interface NotifierDependencies {
|
|
||||||
nodemailer: Nodemailer;
|
|
||||||
}
|
|
|
@ -1,10 +1,12 @@
|
||||||
|
|
||||||
import { UserConfiguration } from "./Configuration";
|
import { UserConfiguration } from "./Configuration";
|
||||||
import { GlobalDependencies } from "./Dependencies";
|
import { GlobalDependencies } from "../types/Dependencies";
|
||||||
import { AuthenticationRegulator } from "./AuthenticationRegulator";
|
import AuthenticationRegulator from "./AuthenticationRegulator";
|
||||||
import UserDataStore from "./UserDataStore";
|
import UserDataStore from "./UserDataStore";
|
||||||
import ConfigurationAdapter from "./ConfigurationAdapter";
|
import ConfigurationAdapter from "./ConfigurationAdapter";
|
||||||
import { NotifierFactory } from "./notifiers/NotifierFactory";
|
import { NotifierFactory } from "./notifiers/NotifierFactory";
|
||||||
|
import TOTPValidator from "./TOTPValidator";
|
||||||
|
import TOTPGenerator from "./TOTPGenerator";
|
||||||
|
|
||||||
import * as Express from "express";
|
import * as Express from "express";
|
||||||
import * as BodyParser from "body-parser";
|
import * as BodyParser from "body-parser";
|
||||||
|
@ -58,10 +60,13 @@ export default class Server {
|
||||||
const notifier = NotifierFactory.build(config.notifier, deps);
|
const notifier = NotifierFactory.build(config.notifier, deps);
|
||||||
const ldap = new Ldap(deps, config.ldap);
|
const ldap = new Ldap(deps, config.ldap);
|
||||||
const accessController = new AccessController(config.access_control, deps.winston);
|
const accessController = new AccessController(config.access_control, deps.winston);
|
||||||
|
const totpValidator = new TOTPValidator(deps.speakeasy);
|
||||||
|
const totpGenerator = new TOTPGenerator(deps.speakeasy);
|
||||||
|
|
||||||
app.set("logger", deps.winston);
|
app.set("logger", deps.winston);
|
||||||
app.set("ldap", ldap);
|
app.set("ldap", ldap);
|
||||||
app.set("totp engine", deps.speakeasy);
|
app.set("totp validator", totpValidator);
|
||||||
|
app.set("totp generator", totpGenerator);
|
||||||
app.set("u2f", deps.u2f);
|
app.set("u2f", deps.u2f);
|
||||||
app.set("user data store", data_store);
|
app.set("user data store", data_store);
|
||||||
app.set("notifier", notifier);
|
app.set("notifier", notifier);
|
||||||
|
|
16
src/lib/TOTPGenerator.ts
Normal file
16
src/lib/TOTPGenerator.ts
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
|
||||||
|
import * as speakeasy from "speakeasy";
|
||||||
|
import { Speakeasy } from "../types/Dependencies";
|
||||||
|
import BluebirdPromise = require("bluebird");
|
||||||
|
|
||||||
|
export default class TOTPGenerator {
|
||||||
|
private speakeasy: Speakeasy;
|
||||||
|
|
||||||
|
constructor(speakeasy: Speakeasy) {
|
||||||
|
this.speakeasy = speakeasy;
|
||||||
|
}
|
||||||
|
|
||||||
|
generate(options: speakeasy.GenerateOptions): speakeasy.Key {
|
||||||
|
return this.speakeasy.generateSecret(options);
|
||||||
|
}
|
||||||
|
}
|
23
src/lib/TOTPValidator.ts
Normal file
23
src/lib/TOTPValidator.ts
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
|
||||||
|
import { Speakeasy } from "../types/Dependencies";
|
||||||
|
import BluebirdPromise = require("bluebird");
|
||||||
|
|
||||||
|
const TOTP_ENCODING = "base32";
|
||||||
|
|
||||||
|
export default class TOTPValidator {
|
||||||
|
private speakeasy: Speakeasy;
|
||||||
|
|
||||||
|
constructor(speakeasy: Speakeasy) {
|
||||||
|
this.speakeasy = speakeasy;
|
||||||
|
}
|
||||||
|
|
||||||
|
validate(token: string, secret: string): BluebirdPromise<void> {
|
||||||
|
const real_token = this.speakeasy.totp({
|
||||||
|
secret: secret,
|
||||||
|
encoding: TOTP_ENCODING
|
||||||
|
});
|
||||||
|
|
||||||
|
if (token == real_token) return BluebirdPromise.resolve();
|
||||||
|
return BluebirdPromise.reject("Wrong challenge");
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,7 +2,7 @@ import * as Promise from "bluebird";
|
||||||
import * as path from "path";
|
import * as path from "path";
|
||||||
import Nedb = require("nedb");
|
import Nedb = require("nedb");
|
||||||
import { NedbAsync } from "nedb";
|
import { NedbAsync } from "nedb";
|
||||||
import { TOTPSecret } from "./TOTPSecret";
|
import { TOTPSecret } from "../types/TOTPSecret";
|
||||||
|
|
||||||
// Constants
|
// Constants
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ import * as fs from "fs";
|
||||||
import * as ejs from "ejs";
|
import * as ejs from "ejs";
|
||||||
import nodemailer = require("nodemailer");
|
import nodemailer = require("nodemailer");
|
||||||
|
|
||||||
import { NodemailerDependencies } from "../Dependencies";
|
import { NodemailerDependencies } from "../../types/Dependencies";
|
||||||
import { Identity } from "../Identity";
|
import { Identity } from "../Identity";
|
||||||
import { INotifier } from "../notifiers/INotifier";
|
import { INotifier } from "../notifiers/INotifier";
|
||||||
import { GmailNotifierConfiguration } from "../Configuration";
|
import { GmailNotifierConfiguration } from "../Configuration";
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
|
|
||||||
import { NotifierConfiguration } from "..//Configuration";
|
import { NotifierConfiguration } from "..//Configuration";
|
||||||
import { NotifierDependencies } from "../Dependencies";
|
import { NotifierDependencies } from "../../types/Dependencies";
|
||||||
import { INotifier } from "./INotifier";
|
import { INotifier } from "./INotifier";
|
||||||
|
|
||||||
import { GMailNotifier } from "./GMailNotifier";
|
import { GMailNotifier } from "./GMailNotifier";
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
|
|
||||||
module.exports = totp_fn;
|
module.exports = totp_fn;
|
||||||
|
|
||||||
var totp = require('../totp');
|
|
||||||
var objectPath = require('object-path');
|
var objectPath = require('object-path');
|
||||||
var exceptions = require('../../../src/lib/exceptions');
|
var exceptions = require('../../../src/lib/exceptions');
|
||||||
|
|
||||||
|
@ -20,14 +19,14 @@ function totp_fn(req, res) {
|
||||||
}
|
}
|
||||||
|
|
||||||
var token = req.body.token;
|
var token = req.body.token;
|
||||||
var totp_engine = req.app.get('totp engine');
|
var totpValidator = req.app.get('totp validator');
|
||||||
var data_store = req.app.get('user data store');
|
var data_store = req.app.get('user data store');
|
||||||
|
|
||||||
logger.debug('POST 2ndfactor totp: Fetching secret for user %s', userid);
|
logger.debug('POST 2ndfactor totp: Fetching secret for user %s', userid);
|
||||||
data_store.get_totp_secret(userid)
|
data_store.get_totp_secret(userid)
|
||||||
.then(function(doc) {
|
.then(function(doc) {
|
||||||
logger.debug('POST 2ndfactor totp: TOTP secret is %s', JSON.stringify(doc));
|
logger.debug('POST 2ndfactor totp: TOTP secret is %s', JSON.stringify(doc));
|
||||||
return totp.validate(totp_engine, token, doc.secret.base32)
|
return totpValidator.validate(token, doc.secret.base32);
|
||||||
})
|
})
|
||||||
.then(function() {
|
.then(function() {
|
||||||
logger.debug('POST 2ndfactor totp: TOTP validation succeeded');
|
logger.debug('POST 2ndfactor totp: TOTP validation succeeded');
|
||||||
|
|
|
@ -47,8 +47,8 @@ function post(req, res) {
|
||||||
}
|
}
|
||||||
|
|
||||||
var user_data_store = req.app.get('user data store');
|
var user_data_store = req.app.get('user data store');
|
||||||
var totp = req.app.get('totp engine');
|
var totpGenerator = req.app.get('totp generator');
|
||||||
var secret = totp.generateSecret();
|
var secret = totpGenerator.generate();
|
||||||
|
|
||||||
logger.debug('POST new-totp-secret: save the TOTP secret in DB');
|
logger.debug('POST new-totp-secret: save the TOTP secret in DB');
|
||||||
user_data_store.set_totp_secret(userid, secret)
|
user_data_store.set_totp_secret(userid, secret)
|
||||||
|
|
|
@ -1,22 +0,0 @@
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
'validate': validate
|
|
||||||
}
|
|
||||||
|
|
||||||
var Promise = require('bluebird');
|
|
||||||
|
|
||||||
function validate(totp_engine, token, totp_secret) {
|
|
||||||
return new Promise(function(resolve, reject) {
|
|
||||||
var real_token = totp_engine.totp({
|
|
||||||
secret: totp_secret,
|
|
||||||
encoding: 'base32'
|
|
||||||
});
|
|
||||||
|
|
||||||
if(token == real_token) {
|
|
||||||
resolve();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
reject('Wrong challenge');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
27
src/types/Dependencies.ts
Normal file
27
src/types/Dependencies.ts
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
import * as winston from "winston";
|
||||||
|
import * as speakeasy from "speakeasy";
|
||||||
|
import nodemailer = require("nodemailer");
|
||||||
|
import session = require("express-session");
|
||||||
|
import nedb = require("nedb");
|
||||||
|
|
||||||
|
export type Nodemailer = typeof nodemailer;
|
||||||
|
export type Speakeasy = typeof speakeasy;
|
||||||
|
export type Winston = typeof winston;
|
||||||
|
export type Session = typeof session;
|
||||||
|
export type Nedb = typeof nedb;
|
||||||
|
|
||||||
|
export interface GlobalDependencies {
|
||||||
|
u2f: object;
|
||||||
|
nodemailer: Nodemailer;
|
||||||
|
ldapjs: object;
|
||||||
|
session: Session;
|
||||||
|
winston: Winston;
|
||||||
|
speakeasy: Speakeasy;
|
||||||
|
nedb: Nedb;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type NodemailerDependencies = Nodemailer;
|
||||||
|
|
||||||
|
export interface NotifierDependencies {
|
||||||
|
nodemailer: Nodemailer;
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
|
|
||||||
import { AuthenticationRegulator } from "../../src/lib/AuthenticationRegulator";
|
import AuthenticationRegulator from "../../src/lib/AuthenticationRegulator";
|
||||||
import UserDataStore from "../../src/lib/UserDataStore";
|
import UserDataStore from "../../src/lib/UserDataStore";
|
||||||
import * as MockDate from "mockdate";
|
import * as MockDate from "mockdate";
|
||||||
|
|
||||||
|
|
|
@ -2,11 +2,11 @@
|
||||||
import Server from "../../src/lib/Server";
|
import Server from "../../src/lib/Server";
|
||||||
import Ldap = require("../../src/lib/ldap");
|
import Ldap = require("../../src/lib/ldap");
|
||||||
|
|
||||||
import * as Promise from "bluebird";
|
import Promise = require("bluebird");
|
||||||
import * as speakeasy from "speakeasy";
|
import speakeasy = require("speakeasy");
|
||||||
import * as request from "request";
|
import request = require("request");
|
||||||
import * as nedb from "nedb";
|
import nedb = require("nedb");
|
||||||
import { TOTPSecret } from "../../src/lib/TOTPSecret";
|
import { TOTPSecret } from "../../src/types/TOTPSecret";
|
||||||
|
|
||||||
|
|
||||||
const requestp = Promise.promisifyAll(request) as request.RequestAsync;
|
const requestp = Promise.promisifyAll(request) as request.RequestAsync;
|
||||||
|
@ -29,7 +29,6 @@ describe("test the server", function () {
|
||||||
beforeEach(function () {
|
beforeEach(function () {
|
||||||
const config = {
|
const config = {
|
||||||
port: PORT,
|
port: PORT,
|
||||||
totp_secret: "totp_secret",
|
|
||||||
ldap: {
|
ldap: {
|
||||||
url: "ldap://127.0.0.1:389",
|
url: "ldap://127.0.0.1:389",
|
||||||
base_dn: "ou=users,dc=example,dc=com",
|
base_dn: "ou=users,dc=example,dc=com",
|
||||||
|
|
30
test/unitary/TOTPValidator.ts
Normal file
30
test/unitary/TOTPValidator.ts
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
|
||||||
|
import TOTPValidator from "../../src/lib/TOTPValidator";
|
||||||
|
import sinon = require("sinon");
|
||||||
|
import Promise = require("bluebird");
|
||||||
|
import SpeakeasyMock = require("./mocks/speakeasy");
|
||||||
|
|
||||||
|
describe("test TOTP validation", function() {
|
||||||
|
let totpValidator: TOTPValidator;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
SpeakeasyMock.totp.returns("token");
|
||||||
|
totpValidator = new TOTPValidator(SpeakeasyMock as any);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should validate the TOTP token", function() {
|
||||||
|
const totp_secret = "NBD2ZV64R9UV1O7K";
|
||||||
|
const token = "token";
|
||||||
|
return totpValidator.validate(token, totp_secret);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should not validate a wrong TOTP token", function() {
|
||||||
|
const totp_secret = "NBD2ZV64R9UV1O7K";
|
||||||
|
const token = "wrong token";
|
||||||
|
return totpValidator.validate(token, totp_secret)
|
||||||
|
.catch(function() {
|
||||||
|
return Promise.resolve();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
|
@ -4,7 +4,7 @@ import * as request from "request";
|
||||||
|
|
||||||
import Server from "../../src/lib/Server";
|
import Server from "../../src/lib/Server";
|
||||||
import { UserConfiguration } from "../../src/lib/Configuration";
|
import { UserConfiguration } from "../../src/lib/Configuration";
|
||||||
import { GlobalDependencies } from "../../src/lib/Dependencies";
|
import { GlobalDependencies } from "../../src/types/Dependencies";
|
||||||
import * as tmp from "tmp";
|
import * as tmp from "tmp";
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
|
|
||||||
import sinon = require("sinon");
|
import sinon = require("sinon");
|
||||||
import { Nodemailer } from "../../../src/lib/Dependencies";
|
|
||||||
|
|
||||||
export = {
|
export = {
|
||||||
createTransport: sinon.stub()
|
createTransport: sinon.stub()
|
||||||
|
|
7
test/unitary/mocks/speakeasy.ts
Normal file
7
test/unitary/mocks/speakeasy.ts
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
|
||||||
|
import sinon = require("sinon");
|
||||||
|
|
||||||
|
export = {
|
||||||
|
totp: sinon.stub(),
|
||||||
|
generateSecret: sinon.stub()
|
||||||
|
};
|
|
@ -9,7 +9,7 @@ import { NotifierFactory } from "../../../src/lib/notifiers/NotifierFactory";
|
||||||
import { GMailNotifier } from "../../../src/lib/notifiers/GMailNotifier";
|
import { GMailNotifier } from "../../../src/lib/notifiers/GMailNotifier";
|
||||||
import { FileSystemNotifier } from "../../../src/lib/notifiers/FileSystemNotifier";
|
import { FileSystemNotifier } from "../../../src/lib/notifiers/FileSystemNotifier";
|
||||||
|
|
||||||
import { NotifierDependencies } from "../../../src/lib/Dependencies";
|
import { NotifierDependencies } from "../../../src/types/Dependencies";
|
||||||
|
|
||||||
|
|
||||||
describe("test notifier", function() {
|
describe("test notifier", function() {
|
||||||
|
|
|
@ -7,7 +7,7 @@ var winston = require('winston');
|
||||||
|
|
||||||
describe('test totp route', function() {
|
describe('test totp route', function() {
|
||||||
var req, res;
|
var req, res;
|
||||||
var totp_engine;
|
var totpValidator;
|
||||||
var user_data_store;
|
var user_data_store;
|
||||||
|
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
|
@ -33,8 +33,8 @@ describe('test totp route', function() {
|
||||||
};
|
};
|
||||||
|
|
||||||
var config = { totp_secret: 'secret' };
|
var config = { totp_secret: 'secret' };
|
||||||
totp_engine = {
|
totpValidator = {
|
||||||
totp: sinon.stub()
|
validate: sinon.stub()
|
||||||
}
|
}
|
||||||
|
|
||||||
user_data_store = {};
|
user_data_store = {};
|
||||||
|
@ -47,14 +47,14 @@ describe('test totp route', function() {
|
||||||
user_data_store.get_totp_secret.returns(Promise.resolve(doc));
|
user_data_store.get_totp_secret.returns(Promise.resolve(doc));
|
||||||
|
|
||||||
app_get.withArgs('logger').returns(winston);
|
app_get.withArgs('logger').returns(winston);
|
||||||
app_get.withArgs('totp engine').returns(totp_engine);
|
app_get.withArgs('totp validator').returns(totpValidator);
|
||||||
app_get.withArgs('config').returns(config);
|
app_get.withArgs('config').returns(config);
|
||||||
app_get.withArgs('user data store').returns(user_data_store);
|
app_get.withArgs('user data store').returns(user_data_store);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
it('should send status code 204 when totp is valid', function(done) {
|
it('should send status code 204 when totp is valid', function(done) {
|
||||||
totp_engine.totp.returns('abc');
|
totpValidator.validate.returns(Promise.resolve("ok"));
|
||||||
res.send = sinon.spy(function() {
|
res.send = sinon.spy(function() {
|
||||||
// Second factor passed
|
// Second factor passed
|
||||||
assert.equal(true, req.session.auth_session.second_factor)
|
assert.equal(true, req.session.auth_session.second_factor)
|
||||||
|
@ -65,7 +65,7 @@ describe('test totp route', function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should send status code 401 when totp is not valid', function(done) {
|
it('should send status code 401 when totp is not valid', function(done) {
|
||||||
totp_engine.totp.returns('bad_token');
|
totpValidator.validate.returns(Promise.reject('bad_token'));
|
||||||
res.send = sinon.spy(function() {
|
res.send = sinon.spy(function() {
|
||||||
assert.equal(false, req.session.auth_session.second_factor)
|
assert.equal(false, req.session.auth_session.second_factor)
|
||||||
assert.equal(401, res.status.getCall(0).args[0]);
|
assert.equal(401, res.status.getCall(0).args[0]);
|
||||||
|
@ -75,7 +75,7 @@ describe('test totp route', function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should send status code 401 when session has not been initiated', function(done) {
|
it('should send status code 401 when session has not been initiated', function(done) {
|
||||||
totp_engine.totp.returns('abc');
|
totpValidator.validate.returns(Promise.resolve('abc'));
|
||||||
res.send = sinon.spy(function() {
|
res.send = sinon.spy(function() {
|
||||||
assert.equal(403, res.status.getCall(0).args[0]);
|
assert.equal(403, res.status.getCall(0).args[0]);
|
||||||
done();
|
done();
|
||||||
|
|
|
@ -81,7 +81,9 @@ describe('test totp register', function() {
|
||||||
|
|
||||||
function test_post_secret() {
|
function test_post_secret() {
|
||||||
it('should send the secret in json format', function(done) {
|
it('should send the secret in json format', function(done) {
|
||||||
req.app.get.withArgs('totp engine').returns(require('speakeasy'));
|
req.app.get.withArgs('totp generator').returns({
|
||||||
|
generate: sinon.stub().returns({ otpauth_url: "abc"})
|
||||||
|
});
|
||||||
req.session.auth_session.identity_check = {};
|
req.session.auth_session.identity_check = {};
|
||||||
req.session.auth_session.identity_check.userid = 'user';
|
req.session.auth_session.identity_check.userid = 'user';
|
||||||
req.session.auth_session.identity_check.challenge = 'totp-register';
|
req.session.auth_session.identity_check.challenge = 'totp-register';
|
||||||
|
@ -92,7 +94,9 @@ describe('test totp register', function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should clear the session for reauthentication', function(done) {
|
it('should clear the session for reauthentication', function(done) {
|
||||||
req.app.get.withArgs('totp engine').returns(require('speakeasy'));
|
req.app.get.withArgs('totp generator').returns({
|
||||||
|
generate: sinon.stub().returns({ otpauth_url: "abc"})
|
||||||
|
});
|
||||||
req.session.auth_session.identity_check = {};
|
req.session.auth_session.identity_check = {};
|
||||||
req.session.auth_session.identity_check.userid = 'user';
|
req.session.auth_session.identity_check.userid = 'user';
|
||||||
req.session.auth_session.identity_check.challenge = 'totp-register';
|
req.session.auth_session.identity_check.challenge = 'totp-register';
|
||||||
|
@ -114,7 +118,9 @@ describe('test totp register', function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return 500 if db throws', function(done) {
|
it('should return 500 if db throws', function(done) {
|
||||||
req.app.get.withArgs('totp engine').returns(require('speakeasy'));
|
req.app.get.withArgs('totp generator').returns({
|
||||||
|
generate: sinon.stub().returns({ otpauth_url: "abc" })
|
||||||
|
});
|
||||||
req.session.auth_session.identity_check = {};
|
req.session.auth_session.identity_check = {};
|
||||||
req.session.auth_session.identity_check.userid = 'user';
|
req.session.auth_session.identity_check.userid = 'user';
|
||||||
req.session.auth_session.identity_check.challenge = 'totp-register';
|
req.session.auth_session.identity_check.challenge = 'totp-register';
|
||||||
|
|
|
@ -1,30 +1,32 @@
|
||||||
|
|
||||||
import * as assert from "assert";
|
import assert = require("assert");
|
||||||
import * as sinon from "sinon";
|
import sinon = require ("sinon");
|
||||||
import nedb = require("nedb");
|
import nedb = require("nedb");
|
||||||
import * as express from "express";
|
import express = require("express");
|
||||||
import * as winston from "winston";
|
import winston = require("winston");
|
||||||
import * as speakeasy from "speakeasy";
|
import speakeasy = require("speakeasy");
|
||||||
import * as u2f from "authdog";
|
import u2f = require("authdog");
|
||||||
|
import nodemailer = require("nodemailer");
|
||||||
|
import session = require("express-session");
|
||||||
|
|
||||||
import { AppConfiguration, UserConfiguration } from "../../src/lib/Configuration";
|
import { AppConfiguration, UserConfiguration } from "../../src/lib/Configuration";
|
||||||
import { GlobalDependencies, Nodemailer } from "../../src/lib/Dependencies";
|
import { GlobalDependencies, Nodemailer } from "../../src/types/Dependencies";
|
||||||
import Server from "../../src/lib/Server";
|
import Server from "../../src/lib/Server";
|
||||||
|
|
||||||
|
|
||||||
describe("test server configuration", function () {
|
describe("test server configuration", function () {
|
||||||
let deps: GlobalDependencies;
|
let deps: GlobalDependencies;
|
||||||
|
let sessionMock: sinon.SinonSpy;
|
||||||
|
|
||||||
before(function () {
|
before(function () {
|
||||||
const transporter = {
|
const transporter = {
|
||||||
sendMail: sinon.stub().yields()
|
sendMail: sinon.stub().yields()
|
||||||
};
|
};
|
||||||
|
|
||||||
const nodemailer: Nodemailer = {
|
const createTransport = sinon.stub(nodemailer, "createTransport");
|
||||||
createTransport: sinon.spy(function () {
|
createTransport.returns(transporter);
|
||||||
return transporter;
|
|
||||||
})
|
sessionMock = sinon.spy(session);
|
||||||
};
|
|
||||||
|
|
||||||
deps = {
|
deps = {
|
||||||
nodemailer: nodemailer,
|
nodemailer: nodemailer,
|
||||||
|
@ -37,9 +39,7 @@ describe("test server configuration", function () {
|
||||||
return { on: sinon.spy() };
|
return { on: sinon.spy() };
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
session: sinon.spy(function () {
|
session: sessionMock as any
|
||||||
return function (req: express.Request, res: express.Response, next: express.NextFunction) { next(); };
|
|
||||||
})
|
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -66,7 +66,7 @@ describe("test server configuration", function () {
|
||||||
const server = new Server();
|
const server = new Server();
|
||||||
server.start(config, deps);
|
server.start(config, deps);
|
||||||
|
|
||||||
assert(deps.session.calledOnce);
|
assert(sessionMock.calledOnce);
|
||||||
assert.equal(deps.session.getCall(0).args[0].cookie.domain, "example.com");
|
assert.equal(sessionMock.getCall(0).args[0].cookie.domain, "example.com");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,69 +0,0 @@
|
||||||
|
|
||||||
import Server from "../../src/lib/Server";
|
|
||||||
|
|
||||||
import { UserConfiguration } from "../../src/lib/Configuration";
|
|
||||||
import { GlobalDependencies } from "../../src/lib/Dependencies";
|
|
||||||
import * as express from "express";
|
|
||||||
|
|
||||||
const sinon = require("sinon");
|
|
||||||
const assert = require("assert");
|
|
||||||
|
|
||||||
describe("test server configuration", function () {
|
|
||||||
let deps: GlobalDependencies;
|
|
||||||
|
|
||||||
before(function () {
|
|
||||||
const transporter = {
|
|
||||||
sendMail: sinon.stub().yields()
|
|
||||||
};
|
|
||||||
|
|
||||||
const nodemailer = {
|
|
||||||
createTransport: sinon.spy(function () {
|
|
||||||
return transporter;
|
|
||||||
})
|
|
||||||
};
|
|
||||||
|
|
||||||
deps = {
|
|
||||||
nodemailer: nodemailer,
|
|
||||||
speakeasy: sinon.spy(),
|
|
||||||
u2f: sinon.spy(),
|
|
||||||
nedb: require("nedb"),
|
|
||||||
winston: sinon.spy(),
|
|
||||||
ldapjs: {
|
|
||||||
createClient: sinon.spy(function () {
|
|
||||||
return { on: sinon.spy() };
|
|
||||||
})
|
|
||||||
},
|
|
||||||
session: sinon.spy(function () {
|
|
||||||
return function (req: express.Request, res: express.Response, next: express.NextFunction) { next(); };
|
|
||||||
})
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
it("should set cookie scope to domain set in the config", function () {
|
|
||||||
const config = {
|
|
||||||
notifier: {
|
|
||||||
gmail: {
|
|
||||||
username: "user@example.com",
|
|
||||||
password: "password"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
session: {
|
|
||||||
domain: "example.com",
|
|
||||||
secret: "secret"
|
|
||||||
},
|
|
||||||
ldap: {
|
|
||||||
url: "http://ldap",
|
|
||||||
base_dn: "cn=test,dc=example,dc=com",
|
|
||||||
user: "user",
|
|
||||||
password: "password"
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const server = new Server();
|
|
||||||
server.start(config, deps);
|
|
||||||
|
|
||||||
assert(deps.session.calledOnce);
|
|
||||||
assert.equal(deps.session.getCall(0).args[0].cookie.domain, "example.com");
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -1,32 +0,0 @@
|
||||||
|
|
||||||
const totp = require("../../src/lib/totp");
|
|
||||||
const sinon = require("sinon");
|
|
||||||
import Promise = require("bluebird");
|
|
||||||
|
|
||||||
describe("test TOTP validation", function() {
|
|
||||||
it("should validate the TOTP token", function() {
|
|
||||||
const totp_secret = "NBD2ZV64R9UV1O7K";
|
|
||||||
const token = "token";
|
|
||||||
const totp_mock = sinon.mock();
|
|
||||||
totp_mock.returns("token");
|
|
||||||
const speakeasy_mock = {
|
|
||||||
totp: totp_mock
|
|
||||||
};
|
|
||||||
return totp.validate(speakeasy_mock, token, totp_secret);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should not validate a wrong TOTP token", function() {
|
|
||||||
const totp_secret = "NBD2ZV64R9UV1O7K";
|
|
||||||
const token = "wrong token";
|
|
||||||
const totp_mock = sinon.mock();
|
|
||||||
totp_mock.returns("token");
|
|
||||||
const speakeasy_mock = {
|
|
||||||
totp: totp_mock
|
|
||||||
};
|
|
||||||
return totp.validate(speakeasy_mock, token, totp_secret)
|
|
||||||
.catch(function() {
|
|
||||||
return Promise.resolve();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user