import Server from "../../src/lib/Server"; import BluebirdPromise = require("bluebird"); import speakeasy = require("speakeasy"); import request = require("request"); import nedb = require("nedb"); import { GlobalDependencies } from "../../types/Dependencies"; import { UserConfiguration } from "../../src/lib/configuration/Configuration"; import { TOTPSecret } from "../../types/TOTPSecret"; import U2FMock = require("./../mocks/u2f"); import Endpoints = require("../../../shared/api"); import Requests = require("../requests"); import Assert = require("assert"); import Sinon = require("sinon"); import Winston = require("winston"); import MockDate = require("mockdate"); import ExpressSession = require("express-session"); import ldapjs = require("ldapjs"); const requestp = BluebirdPromise.promisifyAll(request) as typeof request; const PORT = 8090; const BASE_URL = "http://localhost:" + PORT; const requests = Requests(PORT); describe("Private pages of the server must not be accessible without session", function () { let server: Server; let transporter: any; let u2f: U2FMock.U2FMock; beforeEach(function () { const config: UserConfiguration = { port: PORT, ldap: { url: "ldap://127.0.0.1:389", base_dn: "ou=users,dc=example,dc=com", user: "cn=admin,dc=example,dc=com", password: "password", }, session: { secret: "session_secret", expiration: 50000, }, regulation: { max_retries: 3, ban_time: 5 * 60, find_time: 5 * 60 }, storage: { local: { in_memory: true } }, notifier: { email: { username: "user@example.com", password: "password", sender: "admin@example.com", service: "gmail" } } }; const ldap_client = { bind: Sinon.stub(), search: Sinon.stub(), modify: Sinon.stub(), on: Sinon.spy() }; const ldap = { Change: Sinon.spy(), createClient: Sinon.spy(function () { return ldap_client; }) }; u2f = U2FMock.U2FMock(); transporter = { sendMail: Sinon.stub().yields() }; const nodemailer = { createTransport: Sinon.spy(function () { return transporter; }) }; const ldap_document = { object: { mail: "test_ok@example.com", } }; const search_res = { on: Sinon.spy(function (event: string, fn: (s: any) => void) { if (event != "error") fn(ldap_document); }) }; ldap_client.bind.withArgs("cn=test_ok,ou=users,dc=example,dc=com", "password").yields(undefined); ldap_client.bind.withArgs("cn=admin,dc=example,dc=com", "password").yields(undefined); ldap_client.bind.withArgs("cn=test_nok,ou=users,dc=example,dc=com", "password").yields("error"); ldap_client.modify.yields(undefined); ldap_client.search.yields(undefined, search_res); const deps: GlobalDependencies = { u2f: u2f as any, nedb: nedb, ldapjs: ldap, session: ExpressSession, winston: Winston, speakeasy: speakeasy, ConnectRedis: Sinon.spy(), dovehash: Sinon.spy() as any }; server = new Server(deps); return server.start(config, deps); }); afterEach(function () { server.stop(); }); describe("Second factor endpoints must be protected if first factor is not validated", function () { function should_post_and_reply_with_401(url: string): BluebirdPromise<void> { return requestp.postAsync(url).then(function (response: request.RequestResponse) { Assert.equal(response.statusCode, 401); return BluebirdPromise.resolve(); }); } function should_get_and_reply_with_401(url: string): BluebirdPromise<void> { return requestp.getAsync(url).then(function (response: request.RequestResponse) { Assert.equal(response.statusCode, 401); return BluebirdPromise.resolve(); }); } it("should block " + Endpoints.SECOND_FACTOR_GET, function () { return should_get_and_reply_with_401(BASE_URL + Endpoints.SECOND_FACTOR_GET); }); it("should block " + Endpoints.SECOND_FACTOR_U2F_IDENTITY_START_GET, function () { return should_get_and_reply_with_401(BASE_URL + Endpoints.SECOND_FACTOR_U2F_IDENTITY_START_GET); }); it("should block " + Endpoints.SECOND_FACTOR_U2F_IDENTITY_FINISH_GET, function () { return should_get_and_reply_with_401(BASE_URL + Endpoints.SECOND_FACTOR_U2F_IDENTITY_FINISH_GET + "?identity_token=dummy"); }); it("should block " + Endpoints.SECOND_FACTOR_U2F_REGISTER_REQUEST_GET, function () { return should_get_and_reply_with_401(BASE_URL + Endpoints.SECOND_FACTOR_U2F_REGISTER_REQUEST_GET); }); it("should block " + Endpoints.SECOND_FACTOR_U2F_REGISTER_POST, function () { return should_post_and_reply_with_401(BASE_URL + Endpoints.SECOND_FACTOR_U2F_REGISTER_POST); }); it("should block " + Endpoints.SECOND_FACTOR_U2F_SIGN_REQUEST_GET, function () { return should_get_and_reply_with_401(BASE_URL + Endpoints.SECOND_FACTOR_U2F_SIGN_REQUEST_GET); }); it("should block " + Endpoints.SECOND_FACTOR_U2F_SIGN_POST, function () { return should_post_and_reply_with_401(BASE_URL + Endpoints.SECOND_FACTOR_U2F_SIGN_POST); }); it("should block " + Endpoints.SECOND_FACTOR_TOTP_POST, function () { return should_post_and_reply_with_401(BASE_URL + Endpoints.SECOND_FACTOR_TOTP_POST); }); it("should block " + Endpoints.LOGGED_IN, function () { return should_get_and_reply_with_401(BASE_URL + Endpoints.LOGGED_IN); }); }); });