Refactor configuration to remove optional sections from minimal template
Also move tests from dedicated directory to source dir with .spec.ts extensionpull/242/head
parent
97e0ee8ff6
commit
c82f910da3
|
@ -1,6 +1,4 @@
|
||||||
dist: trusty
|
|
||||||
language: node_js
|
language: node_js
|
||||||
sudo: required
|
|
||||||
node_js:
|
node_js:
|
||||||
- "8"
|
- "8"
|
||||||
services:
|
services:
|
||||||
|
|
|
@ -19,7 +19,7 @@ module.exports = function (grunt) {
|
||||||
"generate-config-schema": {
|
"generate-config-schema": {
|
||||||
cmd: "./node_modules/.bin/typescript-json-schema",
|
cmd: "./node_modules/.bin/typescript-json-schema",
|
||||||
args: ["-o", schemaDir, "--strictNullChecks",
|
args: ["-o", schemaDir, "--strictNullChecks",
|
||||||
"--required", "server/tsconfig.json", "UserConfiguration"]
|
"--required", "server/tsconfig.json", "Configuration"]
|
||||||
},
|
},
|
||||||
"compile-client": {
|
"compile-client": {
|
||||||
cmd: "./node_modules/.bin/tsc",
|
cmd: "./node_modules/.bin/tsc",
|
||||||
|
@ -35,11 +35,11 @@ module.exports = function (grunt) {
|
||||||
},
|
},
|
||||||
"test-server-unit": {
|
"test-server-unit": {
|
||||||
cmd: "./node_modules/.bin/mocha",
|
cmd: "./node_modules/.bin/mocha",
|
||||||
args: ['--colors', '--compilers', 'ts:ts-node/register', '--recursive', 'server/test']
|
args: ['--colors', '--require', 'ts-node/register', 'server/src/**/*.spec.ts']
|
||||||
},
|
},
|
||||||
"test-client-unit": {
|
"test-client-unit": {
|
||||||
cmd: "./node_modules/.bin/mocha",
|
cmd: "./node_modules/.bin/mocha",
|
||||||
args: ['--colors', '--compilers', 'ts:ts-node/register', '--recursive', 'client/test']
|
args: ['--colors', '--require', 'ts-node/register', 'client/test/**/*.test.ts']
|
||||||
},
|
},
|
||||||
"test-int": {
|
"test-int": {
|
||||||
cmd: "./scripts/run-cucumber.sh",
|
cmd: "./scripts/run-cucumber.sh",
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
###############################################################
|
||||||
|
# Authelia minimal configuration #
|
||||||
|
###############################################################
|
||||||
|
|
||||||
|
ldap:
|
||||||
|
url: ldap://openldap
|
||||||
|
base_dn: dc=example,dc=com
|
||||||
|
|
||||||
|
additional_users_dn: ou=users
|
||||||
|
additional_groups_dn: ou=groups
|
||||||
|
|
||||||
|
groups_filter: (&(member={dn})(objectclass=groupOfNames))
|
||||||
|
|
||||||
|
user: cn=admin,dc=example,dc=com
|
||||||
|
password: password
|
||||||
|
|
||||||
|
session:
|
||||||
|
# The secret to encrypt the session cookies.
|
||||||
|
secret: unsecure_session_secret
|
||||||
|
|
||||||
|
# The domain to protect.
|
||||||
|
# Note: the authenticator must also be in that domain. If empty, the cookie
|
||||||
|
# is restricted to the subdomain of the issuer.
|
||||||
|
domain: example.com
|
|
@ -191,10 +191,11 @@ session:
|
||||||
# time.
|
# time.
|
||||||
regulation:
|
regulation:
|
||||||
# The number of failed login attempts before user is banned.
|
# The number of failed login attempts before user is banned.
|
||||||
# Set it to 0 for disabling regulation.
|
# Set it to 0 to disable regulation.
|
||||||
max_retries: 3
|
max_retries: 3
|
||||||
|
|
||||||
# The length of time between login attempts before user is banned.
|
# The time range during which the user can attempt login before being banned.
|
||||||
|
# The user is banned if the authenticaction failed `max_retries` times in a `find_time` seconds window.
|
||||||
find_time: 120
|
find_time: 120
|
||||||
|
|
||||||
# The length of time before a banned user can login again.
|
# The length of time before a banned user can login again.
|
||||||
|
|
|
@ -29,7 +29,7 @@ export class AuthenticationSessionHandler {
|
||||||
|
|
||||||
static get(req: express.Request, logger: IRequestLogger): AuthenticationSession {
|
static get(req: express.Request, logger: IRequestLogger): AuthenticationSession {
|
||||||
if (!req.session) {
|
if (!req.session) {
|
||||||
const errorMsg = "Something is wrong with session cookies. Please check Redis is running and Authelia can contact it.";
|
const errorMsg = "Something is wrong with session cookies. Please check Redis is running and Authelia can connect to it.";
|
||||||
logger.error(req, errorMsg);
|
logger.error(req, errorMsg);
|
||||||
throw new Error(errorMsg);
|
throw new Error(errorMsg);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,32 +1,32 @@
|
||||||
|
|
||||||
import sinon = require("sinon");
|
import sinon = require("sinon");
|
||||||
import IdentityValidator = require("../src/lib/IdentityCheckMiddleware");
|
import IdentityValidator = require("./IdentityCheckMiddleware");
|
||||||
import { AuthenticationSessionHandler }
|
import { AuthenticationSessionHandler }
|
||||||
from "../src/lib/AuthenticationSessionHandler";
|
from "./AuthenticationSessionHandler";
|
||||||
import { AuthenticationSession } from "../types/AuthenticationSession";
|
import { AuthenticationSession } from "../../types/AuthenticationSession";
|
||||||
import { UserDataStore } from "../src/lib/storage/UserDataStore";
|
import { UserDataStore } from "./storage/UserDataStore";
|
||||||
import exceptions = require("../src/lib/Exceptions");
|
import exceptions = require("./Exceptions");
|
||||||
import { ServerVariables } from "../src/lib/ServerVariables";
|
import { ServerVariables } from "./ServerVariables";
|
||||||
import Assert = require("assert");
|
import Assert = require("assert");
|
||||||
import express = require("express");
|
import express = require("express");
|
||||||
import BluebirdPromise = require("bluebird");
|
import BluebirdPromise = require("bluebird");
|
||||||
import ExpressMock = require("./mocks/express");
|
import ExpressMock = require("./stubs/express.spec");
|
||||||
import NotifierMock = require("./mocks/Notifier");
|
import NotifierMock = require("./notifiers/NotifierStub.spec");
|
||||||
import IdentityValidatorMock = require("./mocks/IdentityValidator");
|
import { IdentityValidableStub } from "./IdentityValidableStub.spec";
|
||||||
import { RequestLoggerStub } from "./mocks/RequestLoggerStub";
|
import { RequestLoggerStub } from "./logging/RequestLoggerStub.spec";
|
||||||
import { ServerVariablesMock, ServerVariablesMockBuilder }
|
import { ServerVariablesMock, ServerVariablesMockBuilder }
|
||||||
from "./mocks/ServerVariablesMockBuilder";
|
from "./ServerVariablesMockBuilder.spec";
|
||||||
import { PRE_VALIDATION_TEMPLATE }
|
import { PRE_VALIDATION_TEMPLATE }
|
||||||
from "../src/lib/IdentityCheckPreValidationTemplate";
|
from "./IdentityCheckPreValidationTemplate";
|
||||||
|
|
||||||
|
|
||||||
describe("test identity check process", function () {
|
describe("IdentityCheckMiddleware", function () {
|
||||||
let req: ExpressMock.RequestMock;
|
let req: ExpressMock.RequestMock;
|
||||||
let res: ExpressMock.ResponseMock;
|
let res: ExpressMock.ResponseMock;
|
||||||
let app: express.Application;
|
let app: express.Application;
|
||||||
let app_get: sinon.SinonStub;
|
let app_get: sinon.SinonStub;
|
||||||
let app_post: sinon.SinonStub;
|
let app_post: sinon.SinonStub;
|
||||||
let identityValidable: IdentityValidatorMock.IdentityValidableMock;
|
let identityValidable: IdentityValidableStub;
|
||||||
let mocks: ServerVariablesMock;
|
let mocks: ServerVariablesMock;
|
||||||
let vars: ServerVariables;
|
let vars: ServerVariables;
|
||||||
|
|
||||||
|
@ -38,8 +38,6 @@ describe("test identity check process", function () {
|
||||||
req = ExpressMock.RequestMock();
|
req = ExpressMock.RequestMock();
|
||||||
res = ExpressMock.ResponseMock();
|
res = ExpressMock.ResponseMock();
|
||||||
|
|
||||||
identityValidable = IdentityValidatorMock.IdentityValidableMock();
|
|
||||||
|
|
||||||
req.headers = {};
|
req.headers = {};
|
||||||
req.originalUrl = "/non-api/xxx";
|
req.originalUrl = "/non-api/xxx";
|
||||||
req.session = {};
|
req.session = {};
|
||||||
|
@ -47,6 +45,8 @@ describe("test identity check process", function () {
|
||||||
req.query = {};
|
req.query = {};
|
||||||
req.app = {};
|
req.app = {};
|
||||||
|
|
||||||
|
identityValidable = new IdentityValidableStub();
|
||||||
|
|
||||||
mocks.notifier.notifyStub.returns(BluebirdPromise.resolve());
|
mocks.notifier.notifyStub.returns(BluebirdPromise.resolve());
|
||||||
mocks.userDataStore.produceIdentityValidationTokenStub
|
mocks.userDataStore.produceIdentityValidationTokenStub
|
||||||
.returns(BluebirdPromise.resolve());
|
.returns(BluebirdPromise.resolve());
|
||||||
|
@ -66,7 +66,7 @@ describe("test identity check process", function () {
|
||||||
describe("test start GET", function () {
|
describe("test start GET", function () {
|
||||||
it("should redirect to error 401 if pre validation initialization \
|
it("should redirect to error 401 if pre validation initialization \
|
||||||
throws a first factor error", function () {
|
throws a first factor error", function () {
|
||||||
identityValidable.preValidationInit.returns(BluebirdPromise.reject(
|
identityValidable.preValidationInitStub.returns(BluebirdPromise.reject(
|
||||||
new exceptions.FirstFactorValidationError(
|
new exceptions.FirstFactorValidationError(
|
||||||
"Error during prevalidation")));
|
"Error during prevalidation")));
|
||||||
const callback = IdentityValidator.get_start_validation(
|
const callback = IdentityValidator.get_start_validation(
|
||||||
|
@ -83,14 +83,14 @@ throws a first factor error", function () {
|
||||||
it("should send 200 if email is missing in provided identity", function () {
|
it("should send 200 if email is missing in provided identity", function () {
|
||||||
const identity = { userid: "abc" };
|
const identity = { userid: "abc" };
|
||||||
|
|
||||||
identityValidable.preValidationInit
|
identityValidable.preValidationInitStub
|
||||||
.returns(BluebirdPromise.resolve(identity));
|
.returns(BluebirdPromise.resolve(identity));
|
||||||
const callback = IdentityValidator
|
const callback = IdentityValidator
|
||||||
.get_start_validation(identityValidable, "/endpoint", vars);
|
.get_start_validation(identityValidable, "/endpoint", vars);
|
||||||
|
|
||||||
return callback(req as any, res as any, undefined)
|
return callback(req as any, res as any, undefined)
|
||||||
.then(function () {
|
.then(function () {
|
||||||
Assert(identityValidable.preValidationResponse.called);
|
Assert(identityValidable.preValidationResponseStub.called);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -100,14 +100,14 @@ throws a first factor error", function () {
|
||||||
const endpoint = "/protected";
|
const endpoint = "/protected";
|
||||||
const identity = { email: "abc@example.com" };
|
const identity = { email: "abc@example.com" };
|
||||||
|
|
||||||
identityValidable.preValidationInit
|
identityValidable.preValidationInitStub
|
||||||
.returns(BluebirdPromise.resolve(identity));
|
.returns(BluebirdPromise.resolve(identity));
|
||||||
const callback = IdentityValidator
|
const callback = IdentityValidator
|
||||||
.get_start_validation(identityValidable, "/endpoint", vars);
|
.get_start_validation(identityValidable, "/endpoint", vars);
|
||||||
|
|
||||||
return callback(req as any, res as any, undefined)
|
return callback(req as any, res as any, undefined)
|
||||||
.then(function () {
|
.then(function () {
|
||||||
Assert(identityValidable.preValidationResponse.called);
|
Assert(identityValidable.preValidationResponseStub.called);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -116,7 +116,7 @@ throws a first factor error", function () {
|
||||||
const identity = { userid: "user", email: "abc@example.com" };
|
const identity = { userid: "user", email: "abc@example.com" };
|
||||||
req.get = sinon.stub().withArgs("Host").returns("localhost");
|
req.get = sinon.stub().withArgs("Host").returns("localhost");
|
||||||
|
|
||||||
identityValidable.preValidationInit
|
identityValidable.preValidationInitStub
|
||||||
.returns(BluebirdPromise.resolve(identity));
|
.returns(BluebirdPromise.resolve(identity));
|
||||||
const callback = IdentityValidator
|
const callback = IdentityValidator
|
||||||
.get_start_validation(identityValidable, "/finish_endpoint", vars);
|
.get_start_validation(identityValidable, "/finish_endpoint", vars);
|
||||||
|
@ -177,24 +177,5 @@ valid", function () {
|
||||||
Assert(res.redirect.calledWith("/error/401"));
|
Assert(res.redirect.calledWith("/error/401"));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should set the identity_check session object even if session does \
|
|
||||||
not exist yet", function () {
|
|
||||||
req.query.identity_token = "token";
|
|
||||||
|
|
||||||
req.session = {};
|
|
||||||
const authSession =
|
|
||||||
AuthenticationSessionHandler.get(req as any, vars.logger);
|
|
||||||
const callback = IdentityValidator
|
|
||||||
.get_finish_validation(identityValidable, vars);
|
|
||||||
|
|
||||||
return callback(req as any, res as any, undefined)
|
|
||||||
.then(function () {
|
|
||||||
return BluebirdPromise.reject("Should fail");
|
|
||||||
})
|
|
||||||
.catch(function () {
|
|
||||||
Assert.equal(authSession.identity_check.userid, "user");
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
import objectPath = require("object-path");
|
import objectPath = require("object-path");
|
||||||
import randomstring = require("randomstring");
|
import randomstring = require("randomstring");
|
||||||
import BluebirdPromise = require("bluebird");
|
import BluebirdPromise = require("bluebird");
|
||||||
|
@ -12,6 +11,7 @@ import ErrorReplies = require("./ErrorReplies");
|
||||||
import { AuthenticationSessionHandler } from "./AuthenticationSessionHandler";
|
import { AuthenticationSessionHandler } from "./AuthenticationSessionHandler";
|
||||||
import { AuthenticationSession } from "../../types/AuthenticationSession";
|
import { AuthenticationSession } from "../../types/AuthenticationSession";
|
||||||
import { ServerVariables } from "./ServerVariables";
|
import { ServerVariables } from "./ServerVariables";
|
||||||
|
import { IdentityValidable } from "./IdentityValidable";
|
||||||
|
|
||||||
import Identity = require("../../types/Identity");
|
import Identity = require("../../types/Identity");
|
||||||
import { IdentityValidationDocument }
|
import { IdentityValidationDocument }
|
||||||
|
@ -20,26 +20,9 @@ import { IdentityValidationDocument }
|
||||||
const filePath = __dirname + "/../resources/email-template.ejs";
|
const filePath = __dirname + "/../resources/email-template.ejs";
|
||||||
const email_template = fs.readFileSync(filePath, "utf8");
|
const email_template = fs.readFileSync(filePath, "utf8");
|
||||||
|
|
||||||
// IdentityValidator allows user to go through a identity validation process
|
|
||||||
// in two steps:
|
|
||||||
// - Request an operation to be performed (password reset, registration).
|
|
||||||
// - Confirm operation with email.
|
|
||||||
|
|
||||||
export interface IdentityValidable {
|
|
||||||
challenge(): string;
|
|
||||||
preValidationInit(req: Express.Request): BluebirdPromise<Identity.Identity>;
|
|
||||||
postValidationInit(req: Express.Request): BluebirdPromise<void>;
|
|
||||||
|
|
||||||
// Serves a page after identity check request
|
|
||||||
preValidationResponse(req: Express.Request, res: Express.Response): void;
|
|
||||||
// Serves the page if identity validated
|
|
||||||
postValidationResponse(req: Express.Request, res: Express.Response): void;
|
|
||||||
mailSubject(): string;
|
|
||||||
}
|
|
||||||
|
|
||||||
function createAndSaveToken(userid: string, challenge: string,
|
function createAndSaveToken(userid: string, challenge: string,
|
||||||
userDataStore: IUserDataStore)
|
userDataStore: IUserDataStore): BluebirdPromise<string> {
|
||||||
: BluebirdPromise<string> {
|
|
||||||
const five_minutes = 4 * 60 * 1000;
|
const five_minutes = 4 * 60 * 1000;
|
||||||
const token = randomstring.generate({ length: 64 });
|
const token = randomstring.generate({ length: 64 });
|
||||||
const that = this;
|
const that = this;
|
||||||
|
@ -80,8 +63,10 @@ function checkIdentityToken(req: Express.Request, identityToken: string)
|
||||||
export function get_finish_validation(handler: IdentityValidable,
|
export function get_finish_validation(handler: IdentityValidable,
|
||||||
vars: ServerVariables)
|
vars: ServerVariables)
|
||||||
: Express.RequestHandler {
|
: Express.RequestHandler {
|
||||||
|
|
||||||
return function (req: Express.Request, res: Express.Response)
|
return function (req: Express.Request, res: Express.Response)
|
||||||
: BluebirdPromise<void> {
|
: BluebirdPromise<void> {
|
||||||
|
|
||||||
let authSession: AuthenticationSession;
|
let authSession: AuthenticationSession;
|
||||||
const identityToken = objectPath.get<Express.Request, string>(
|
const identityToken = objectPath.get<Express.Request, string>(
|
||||||
req, "query.identity_token");
|
req, "query.identity_token");
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
import Bluebird = require("bluebird");
|
||||||
|
import Identity = require("../../types/Identity");
|
||||||
|
|
||||||
|
// IdentityValidator allows user to go through a identity validation process
|
||||||
|
// in two steps:
|
||||||
|
// - Request an operation to be performed (password reset, registration).
|
||||||
|
// - Confirm operation with email.
|
||||||
|
|
||||||
|
export interface IdentityValidable {
|
||||||
|
challenge(): string;
|
||||||
|
preValidationInit(req: Express.Request): Bluebird<Identity.Identity>;
|
||||||
|
postValidationInit(req: Express.Request): Bluebird<void>;
|
||||||
|
|
||||||
|
// Serves a page after identity check request
|
||||||
|
preValidationResponse(req: Express.Request, res: Express.Response): void;
|
||||||
|
// Serves the page if identity validated
|
||||||
|
postValidationResponse(req: Express.Request, res: Express.Response): void;
|
||||||
|
mailSubject(): string;
|
||||||
|
}
|
|
@ -0,0 +1,52 @@
|
||||||
|
|
||||||
|
import Sinon = require("sinon");
|
||||||
|
import { IdentityValidable } from "./IdentityValidable";
|
||||||
|
import express = require("express");
|
||||||
|
import Bluebird = require("bluebird");
|
||||||
|
import { Identity } from "../../types/Identity";
|
||||||
|
|
||||||
|
|
||||||
|
export class IdentityValidableStub implements IdentityValidable {
|
||||||
|
challengeStub: Sinon.SinonStub;
|
||||||
|
preValidationInitStub: Sinon.SinonStub;
|
||||||
|
postValidationInitStub: Sinon.SinonStub;
|
||||||
|
preValidationResponseStub: Sinon.SinonStub;
|
||||||
|
postValidationResponseStub: Sinon.SinonStub;
|
||||||
|
mailSubjectStub: Sinon.SinonStub;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.challengeStub = Sinon.stub();
|
||||||
|
|
||||||
|
this.preValidationInitStub = Sinon.stub();
|
||||||
|
this.postValidationResponseStub = Sinon.stub();
|
||||||
|
|
||||||
|
this.preValidationResponseStub = Sinon.stub();
|
||||||
|
this.postValidationResponseStub = Sinon.stub();
|
||||||
|
|
||||||
|
this.mailSubjectStub = Sinon.stub();
|
||||||
|
}
|
||||||
|
|
||||||
|
challenge(): string {
|
||||||
|
return this.challengeStub();
|
||||||
|
}
|
||||||
|
|
||||||
|
preValidationInit(req: Express.Request): Bluebird<Identity> {
|
||||||
|
return this.preValidationInitStub(req);
|
||||||
|
}
|
||||||
|
|
||||||
|
postValidationInit(req: Express.Request): Bluebird<void> {
|
||||||
|
return this.postValidationInitStub(req);
|
||||||
|
}
|
||||||
|
|
||||||
|
preValidationResponse(req: Express.Request, res: Express.Response): void {
|
||||||
|
return this.preValidationResponseStub(req, res);
|
||||||
|
}
|
||||||
|
|
||||||
|
postValidationResponse(req: Express.Request, res: Express.Response): void {
|
||||||
|
return this.postValidationResponseStub(req, res);
|
||||||
|
}
|
||||||
|
|
||||||
|
mailSubject(): string {
|
||||||
|
return this.mailSubjectStub();
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,13 +7,13 @@ import winston = require("winston");
|
||||||
import speakeasy = require("speakeasy");
|
import speakeasy = require("speakeasy");
|
||||||
import u2f = require("u2f");
|
import u2f = require("u2f");
|
||||||
import session = require("express-session");
|
import session = require("express-session");
|
||||||
import { AppConfiguration, UserConfiguration } from "../src/lib/configuration/Configuration";
|
import { Configuration } from "./configuration/schema/Configuration";
|
||||||
import { GlobalDependencies } from "../types/Dependencies";
|
import { GlobalDependencies } from "../../types/Dependencies";
|
||||||
import Server from "../src/lib/Server";
|
import Server from "./Server";
|
||||||
import { LdapjsMock, LdapjsClientMock } from "./mocks/ldapjs";
|
import { LdapjsMock, LdapjsClientMock } from "./stubs/ldapjs.spec";
|
||||||
|
|
||||||
|
|
||||||
describe("test server configuration", function () {
|
describe("Server", function () {
|
||||||
let deps: GlobalDependencies;
|
let deps: GlobalDependencies;
|
||||||
let sessionMock: Sinon.SinonSpy;
|
let sessionMock: Sinon.SinonSpy;
|
||||||
let ldapjsMock: LdapjsMock;
|
let ldapjsMock: LdapjsMock;
|
||||||
|
@ -36,7 +36,7 @@ describe("test server configuration", function () {
|
||||||
|
|
||||||
|
|
||||||
it("should set cookie scope to domain set in the config", function () {
|
it("should set cookie scope to domain set in the config", function () {
|
||||||
const config: UserConfiguration = {
|
const config: Configuration = {
|
||||||
port: 8081,
|
port: 8081,
|
||||||
session: {
|
session: {
|
||||||
domain: "example.com",
|
domain: "example.com",
|
|
@ -2,7 +2,7 @@ import BluebirdPromise = require("bluebird");
|
||||||
import ObjectPath = require("object-path");
|
import ObjectPath = require("object-path");
|
||||||
|
|
||||||
import { AccessController } from "./access_control/AccessController";
|
import { AccessController } from "./access_control/AccessController";
|
||||||
import { AppConfiguration, UserConfiguration } from "./configuration/Configuration";
|
import { Configuration } from "./configuration/schema/Configuration";
|
||||||
import { GlobalDependencies } from "../../types/Dependencies";
|
import { GlobalDependencies } from "../../types/Dependencies";
|
||||||
import { UserDataStore } from "./storage/UserDataStore";
|
import { UserDataStore } from "./storage/UserDataStore";
|
||||||
import { ConfigurationParser } from "./configuration/ConfigurationParser";
|
import { ConfigurationParser } from "./configuration/ConfigurationParser";
|
||||||
|
@ -31,33 +31,22 @@ export default class Server {
|
||||||
this.requestLogger = new RequestLogger(deps.winston);
|
this.requestLogger = new RequestLogger(deps.winston);
|
||||||
}
|
}
|
||||||
|
|
||||||
private displayConfigurations(userConfiguration: UserConfiguration,
|
private displayConfigurations(configuration: Configuration) {
|
||||||
appConfiguration: AppConfiguration) {
|
const displayableConfiguration: Configuration = clone(configuration);
|
||||||
const displayableUserConfiguration = clone(userConfiguration);
|
|
||||||
const displayableAppConfiguration = clone(appConfiguration);
|
|
||||||
const STARS = "*****";
|
const STARS = "*****";
|
||||||
|
|
||||||
displayableUserConfiguration.ldap.password = STARS;
|
displayableConfiguration.ldap.password = STARS;
|
||||||
displayableUserConfiguration.session.secret = STARS;
|
displayableConfiguration.session.secret = STARS;
|
||||||
if (displayableUserConfiguration.notifier && displayableUserConfiguration.notifier.email)
|
if (displayableConfiguration.notifier && displayableConfiguration.notifier.email)
|
||||||
displayableUserConfiguration.notifier.email.password = STARS;
|
displayableConfiguration.notifier.email.password = STARS;
|
||||||
if (displayableUserConfiguration.notifier && displayableUserConfiguration.notifier.smtp)
|
if (displayableConfiguration.notifier && displayableConfiguration.notifier.smtp)
|
||||||
displayableUserConfiguration.notifier.smtp.password = STARS;
|
displayableConfiguration.notifier.smtp.password = STARS;
|
||||||
|
|
||||||
displayableAppConfiguration.ldap.password = STARS;
|
|
||||||
displayableAppConfiguration.session.secret = STARS;
|
|
||||||
if (displayableAppConfiguration.notifier && displayableAppConfiguration.notifier.email)
|
|
||||||
displayableAppConfiguration.notifier.email.password = STARS;
|
|
||||||
if (displayableAppConfiguration.notifier && displayableAppConfiguration.notifier.smtp)
|
|
||||||
displayableAppConfiguration.notifier.smtp.password = STARS;
|
|
||||||
|
|
||||||
this.globalLogger.debug("User configuration is %s",
|
this.globalLogger.debug("User configuration is %s",
|
||||||
JSON.stringify(displayableUserConfiguration, undefined, 2));
|
JSON.stringify(displayableConfiguration, undefined, 2));
|
||||||
this.globalLogger.debug("Adapted configuration is %s",
|
|
||||||
JSON.stringify(displayableAppConfiguration, undefined, 2));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private setup(config: AppConfiguration, app: Express.Application, deps: GlobalDependencies): BluebirdPromise<void> {
|
private setup(config: Configuration, app: Express.Application, deps: GlobalDependencies): BluebirdPromise<void> {
|
||||||
const that = this;
|
const that = this;
|
||||||
return ServerVariablesInitializer.initialize(config, this.requestLogger, deps)
|
return ServerVariablesInitializer.initialize(config, this.requestLogger, deps)
|
||||||
.then(function (vars: ServerVariables) {
|
.then(function (vars: ServerVariables) {
|
||||||
|
@ -76,16 +65,16 @@ export default class Server {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
start(userConfiguration: UserConfiguration, deps: GlobalDependencies)
|
start(configuration: Configuration, deps: GlobalDependencies)
|
||||||
: BluebirdPromise<void> {
|
: BluebirdPromise<void> {
|
||||||
const that = this;
|
const that = this;
|
||||||
const app = Express();
|
const app = Express();
|
||||||
|
|
||||||
const appConfiguration = ConfigurationParser.parse(userConfiguration);
|
const appConfiguration = ConfigurationParser.parse(configuration);
|
||||||
|
|
||||||
// by default the level of logs is info
|
// by default the level of logs is info
|
||||||
deps.winston.level = userConfiguration.logs_level;
|
deps.winston.level = configuration.logs_level;
|
||||||
this.displayConfigurations(userConfiguration, appConfiguration);
|
this.displayConfigurations(configuration);
|
||||||
|
|
||||||
return this.setup(appConfiguration, app, deps)
|
return this.setup(appConfiguration, app, deps)
|
||||||
.then(function () {
|
.then(function () {
|
||||||
|
|
|
@ -7,7 +7,7 @@ import { IU2fHandler } from "./authentication/u2f/IU2fHandler";
|
||||||
import { IUserDataStore } from "./storage/IUserDataStore";
|
import { IUserDataStore } from "./storage/IUserDataStore";
|
||||||
import { INotifier } from "./notifiers/INotifier";
|
import { INotifier } from "./notifiers/INotifier";
|
||||||
import { IRegulator } from "./regulation/IRegulator";
|
import { IRegulator } from "./regulation/IRegulator";
|
||||||
import { AppConfiguration } from "./configuration/Configuration";
|
import { Configuration } from "./configuration/schema/Configuration";
|
||||||
import { IAccessController } from "./access_control/IAccessController";
|
import { IAccessController } from "./access_control/IAccessController";
|
||||||
|
|
||||||
export interface ServerVariables {
|
export interface ServerVariables {
|
||||||
|
@ -20,6 +20,6 @@ export interface ServerVariables {
|
||||||
userDataStore: IUserDataStore;
|
userDataStore: IUserDataStore;
|
||||||
notifier: INotifier;
|
notifier: INotifier;
|
||||||
regulator: IRegulator;
|
regulator: IRegulator;
|
||||||
config: AppConfiguration;
|
config: Configuration;
|
||||||
accessController: IAccessController;
|
accessController: IAccessController;
|
||||||
}
|
}
|
|
@ -26,7 +26,7 @@ import { UserDataStore } from "./storage/UserDataStore";
|
||||||
import { INotifier } from "./notifiers/INotifier";
|
import { INotifier } from "./notifiers/INotifier";
|
||||||
import { Regulator } from "./regulation/Regulator";
|
import { Regulator } from "./regulation/Regulator";
|
||||||
import { IRegulator } from "./regulation/IRegulator";
|
import { IRegulator } from "./regulation/IRegulator";
|
||||||
import Configuration = require("./configuration/Configuration");
|
import Configuration = require("./configuration/schema/Configuration");
|
||||||
import { AccessController } from "./access_control/AccessController";
|
import { AccessController } from "./access_control/AccessController";
|
||||||
import { IAccessController } from "./access_control/IAccessController";
|
import { IAccessController } from "./access_control/IAccessController";
|
||||||
import { CollectionFactoryFactory } from "./storage/CollectionFactoryFactory";
|
import { CollectionFactoryFactory } from "./storage/CollectionFactoryFactory";
|
||||||
|
@ -40,7 +40,7 @@ import { ServerVariables } from "./ServerVariables";
|
||||||
import { MethodCalculator } from "./authentication/MethodCalculator";
|
import { MethodCalculator } from "./authentication/MethodCalculator";
|
||||||
|
|
||||||
class UserDataStoreFactory {
|
class UserDataStoreFactory {
|
||||||
static create(config: Configuration.AppConfiguration): BluebirdPromise<UserDataStore> {
|
static create(config: Configuration.Configuration): BluebirdPromise<UserDataStore> {
|
||||||
if (config.storage.local) {
|
if (config.storage.local) {
|
||||||
const nedbOptions: Nedb.DataStoreOptions = {
|
const nedbOptions: Nedb.DataStoreOptions = {
|
||||||
filename: config.storage.local.path,
|
filename: config.storage.local.path,
|
||||||
|
@ -64,7 +64,7 @@ class UserDataStoreFactory {
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ServerVariablesInitializer {
|
export class ServerVariablesInitializer {
|
||||||
static initialize(config: Configuration.AppConfiguration, requestLogger: IRequestLogger,
|
static initialize(config: Configuration.Configuration, requestLogger: IRequestLogger,
|
||||||
deps: GlobalDependencies): BluebirdPromise<ServerVariables> {
|
deps: GlobalDependencies): BluebirdPromise<ServerVariables> {
|
||||||
const mailSenderBuilder = new MailSenderBuilder(Nodemailer);
|
const mailSenderBuilder = new MailSenderBuilder(Nodemailer);
|
||||||
const notifier = NotifierFactory.build(config.notifier, mailSenderBuilder);
|
const notifier = NotifierFactory.build(config.notifier, mailSenderBuilder);
|
||||||
|
|
|
@ -1,20 +1,20 @@
|
||||||
import { ServerVariables } from "../../src/lib/ServerVariables";
|
import { ServerVariables } from "./ServerVariables";
|
||||||
|
|
||||||
import { AppConfiguration } from "../../src/lib/configuration/Configuration";
|
import { Configuration } from "./configuration/schema/Configuration";
|
||||||
import { AuthenticatorStub } from "./ldap/AuthenticatorStub";
|
import { AuthenticatorStub } from "./ldap/AuthenticatorStub.spec";
|
||||||
import { EmailsRetrieverStub } from "./ldap/EmailsRetrieverStub";
|
import { EmailsRetrieverStub } from "./ldap/EmailsRetrieverStub.spec";
|
||||||
import { PasswordUpdaterStub } from "./ldap/PasswordUpdaterStub";
|
import { PasswordUpdaterStub } from "./ldap/PasswordUpdaterStub.spec";
|
||||||
import { AccessControllerStub } from "./AccessControllerStub";
|
import { AccessControllerStub } from "./access_control/AccessControllerStub.spec";
|
||||||
import { RequestLoggerStub } from "./RequestLoggerStub";
|
import { RequestLoggerStub } from "./logging/RequestLoggerStub.spec";
|
||||||
import { NotifierStub } from "./NotifierStub";
|
import { NotifierStub } from "./notifiers/NotifierStub.spec";
|
||||||
import { RegulatorStub } from "./RegulatorStub";
|
import { RegulatorStub } from "./regulation/RegulatorStub.spec";
|
||||||
import { TotpHandlerStub } from "./TotpHandlerStub";
|
import { TotpHandlerStub } from "./authentication/totp/TotpHandlerStub.spec";
|
||||||
import { UserDataStoreStub } from "./storage/UserDataStoreStub";
|
import { UserDataStoreStub } from "./storage/UserDataStoreStub.spec";
|
||||||
import { U2fHandlerStub } from "./U2fHandlerStub";
|
import { U2fHandlerStub } from "./authentication/u2f/U2fHandlerStub.spec";
|
||||||
|
|
||||||
export interface ServerVariablesMock {
|
export interface ServerVariablesMock {
|
||||||
accessController: AccessControllerStub;
|
accessController: AccessControllerStub;
|
||||||
config: AppConfiguration;
|
config: Configuration;
|
||||||
ldapAuthenticator: AuthenticatorStub;
|
ldapAuthenticator: AuthenticatorStub;
|
||||||
ldapEmailsRetriever: EmailsRetrieverStub;
|
ldapEmailsRetriever: EmailsRetrieverStub;
|
||||||
ldapPasswordUpdater: PasswordUpdaterStub;
|
ldapPasswordUpdater: PasswordUpdaterStub;
|
||||||
|
@ -40,11 +40,12 @@ export class ServerVariablesMockBuilder {
|
||||||
},
|
},
|
||||||
ldap: {
|
ldap: {
|
||||||
url: "ldap://ldap",
|
url: "ldap://ldap",
|
||||||
|
base_dn: "dc=example,dc=com",
|
||||||
user: "user",
|
user: "user",
|
||||||
password: "password",
|
password: "password",
|
||||||
mail_attribute: "mail",
|
mail_attribute: "mail",
|
||||||
users_dn: "ou=users,dc=example,dc=com",
|
additional_users_dn: "ou=users",
|
||||||
groups_dn: "ou=groups,dc=example,dc=com",
|
additional_groups_dn: "ou=groups",
|
||||||
users_filter: "cn={0}",
|
users_filter: "cn={0}",
|
||||||
groups_filter: "member={dn}",
|
groups_filter: "member={dn}",
|
||||||
group_name_attribute: "cn"
|
group_name_attribute: "cn"
|
|
@ -1,10 +1,10 @@
|
||||||
|
|
||||||
import Assert = require("assert");
|
import Assert = require("assert");
|
||||||
import winston = require("winston");
|
import winston = require("winston");
|
||||||
import { AccessController } from "../../src/lib/access_control/AccessController";
|
import { AccessController } from "./AccessController";
|
||||||
import { ACLConfiguration, ACLRule } from "../../src/lib/configuration/Configuration";
|
import { ACLConfiguration, ACLRule } from "../configuration/schema/AclConfiguration";
|
||||||
|
|
||||||
describe("test access control manager", function () {
|
describe("access_control/AccessController", function () {
|
||||||
let accessController: AccessController;
|
let accessController: AccessController;
|
||||||
let configuration: ACLConfiguration;
|
let configuration: ACLConfiguration;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
|
|
||||||
import { ACLConfiguration, ACLPolicy, ACLRule } from "../configuration/Configuration";
|
import { ACLConfiguration, ACLPolicy, ACLRule } from "../configuration/schema/AclConfiguration";
|
||||||
import { IAccessController } from "./IAccessController";
|
import { IAccessController } from "./IAccessController";
|
||||||
import { Winston } from "../../../types/Dependencies";
|
import { Winston } from "../../../types/Dependencies";
|
||||||
import { MultipleDomainMatcher } from "./MultipleDomainMatcher";
|
import { MultipleDomainMatcher } from "./MultipleDomainMatcher";
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
|
|
||||||
import Sinon = require("sinon");
|
import Sinon = require("sinon");
|
||||||
import { IAccessController } from "../../src/lib/access_control/IAccessController";
|
import { IAccessController } from "./IAccessController";
|
||||||
|
|
||||||
export class AccessControllerStub implements IAccessController {
|
export class AccessControllerStub implements IAccessController {
|
||||||
isAccessAllowedMock: Sinon.SinonStub;
|
isAccessAllowedMock: Sinon.SinonStub;
|
|
@ -1,10 +1,9 @@
|
||||||
import { MethodCalculator }
|
import { MethodCalculator } from "./MethodCalculator";
|
||||||
from "../../src/lib/authentication/MethodCalculator";
|
|
||||||
import { AuthenticationMethodsConfiguration }
|
import { AuthenticationMethodsConfiguration }
|
||||||
from "../../src/lib/configuration/Configuration";
|
from "../configuration/schema/AuthenticationMethodsConfiguration";
|
||||||
import Assert = require("assert");
|
import Assert = require("assert");
|
||||||
|
|
||||||
describe("test MethodCalculator", function () {
|
describe("authentication/MethodCalculator", function () {
|
||||||
describe("test compute method", function () {
|
describe("test compute method", function () {
|
||||||
it("should return default method when sub domain not overriden",
|
it("should return default method when sub domain not overriden",
|
||||||
function () {
|
function () {
|
|
@ -1,7 +1,7 @@
|
||||||
import {
|
import {
|
||||||
AuthenticationMethod,
|
AuthenticationMethod,
|
||||||
AuthenticationMethodsConfiguration
|
AuthenticationMethodsConfiguration
|
||||||
} from "../configuration/Configuration";
|
} from "../configuration/schema/AuthenticationMethodsConfiguration";
|
||||||
|
|
||||||
function computeIsSingleFactorOnlyMode(
|
function computeIsSingleFactorOnlyMode(
|
||||||
configuration: AuthenticationMethodsConfiguration): boolean {
|
configuration: AuthenticationMethodsConfiguration): boolean {
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
|
|
||||||
import { TotpHandler } from "../../../src/lib/authentication/totp/TotpHandler";
|
import { TotpHandler } from "./TotpHandler";
|
||||||
import Sinon = require("sinon");
|
import Sinon = require("sinon");
|
||||||
import Speakeasy = require("speakeasy");
|
import Speakeasy = require("speakeasy");
|
||||||
import Assert = require("assert");
|
import Assert = require("assert");
|
||||||
|
|
||||||
describe("test TOTP validation", function() {
|
describe("authentication/totp/TotpHandler", function() {
|
||||||
let totpValidator: TotpHandler;
|
let totpValidator: TotpHandler;
|
||||||
let validateStub: Sinon.SinonStub;
|
let validateStub: Sinon.SinonStub;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import Sinon = require("sinon");
|
import Sinon = require("sinon");
|
||||||
import BluebirdPromise = require("bluebird");
|
import BluebirdPromise = require("bluebird");
|
||||||
import { ITotpHandler } from "../../src/lib/authentication/totp/ITotpHandler";
|
import { ITotpHandler } from "./ITotpHandler";
|
||||||
import { TOTPSecret } from "../../types/TOTPSecret";
|
import { TOTPSecret } from "../../../../types/TOTPSecret";
|
||||||
|
|
||||||
export class TotpHandlerStub implements ITotpHandler {
|
export class TotpHandlerStub implements ITotpHandler {
|
||||||
generateStub: Sinon.SinonStub;
|
generateStub: Sinon.SinonStub;
|
|
@ -1,7 +1,7 @@
|
||||||
import Sinon = require("sinon");
|
import Sinon = require("sinon");
|
||||||
import BluebirdPromise = require("bluebird");
|
import BluebirdPromise = require("bluebird");
|
||||||
import U2f = require("u2f");
|
import U2f = require("u2f");
|
||||||
import { IU2fHandler } from "../../src/lib/authentication/u2f/IU2fHandler";
|
import { IU2fHandler } from "./IU2fHandler";
|
||||||
|
|
||||||
|
|
||||||
export class U2fHandlerStub implements IU2fHandler {
|
export class U2fHandlerStub implements IU2fHandler {
|
|
@ -1,155 +0,0 @@
|
||||||
export interface UserLdapConfiguration {
|
|
||||||
url: string;
|
|
||||||
base_dn: string;
|
|
||||||
|
|
||||||
additional_users_dn?: string;
|
|
||||||
users_filter?: string;
|
|
||||||
|
|
||||||
additional_groups_dn?: string;
|
|
||||||
groups_filter?: string;
|
|
||||||
|
|
||||||
group_name_attribute?: string;
|
|
||||||
mail_attribute?: string;
|
|
||||||
|
|
||||||
user: string; // admin username
|
|
||||||
password: string; // admin password
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface LdapConfiguration {
|
|
||||||
url: string;
|
|
||||||
|
|
||||||
users_dn: string;
|
|
||||||
users_filter: string;
|
|
||||||
|
|
||||||
groups_dn: string;
|
|
||||||
groups_filter: string;
|
|
||||||
|
|
||||||
group_name_attribute: string;
|
|
||||||
mail_attribute: string;
|
|
||||||
|
|
||||||
user: string; // admin username
|
|
||||||
password: string; // admin password
|
|
||||||
}
|
|
||||||
|
|
||||||
type UserName = string;
|
|
||||||
type GroupName = string;
|
|
||||||
type DomainPattern = string;
|
|
||||||
|
|
||||||
export type ACLPolicy = 'deny' | 'allow';
|
|
||||||
|
|
||||||
export type ACLRule = {
|
|
||||||
domain: string;
|
|
||||||
policy: ACLPolicy;
|
|
||||||
resources?: string[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export type ACLDefaultRules = ACLRule[];
|
|
||||||
export type ACLGroupsRules = { [group: string]: ACLRule[]; };
|
|
||||||
export type ACLUsersRules = { [user: string]: ACLRule[]; };
|
|
||||||
|
|
||||||
export interface ACLConfiguration {
|
|
||||||
default_policy?: ACLPolicy;
|
|
||||||
any?: ACLDefaultRules;
|
|
||||||
groups?: ACLGroupsRules;
|
|
||||||
users?: ACLUsersRules;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface SessionRedisOptions {
|
|
||||||
host: string;
|
|
||||||
port: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface SessionCookieConfiguration {
|
|
||||||
secret: string;
|
|
||||||
expiration?: number;
|
|
||||||
inactivity?: number;
|
|
||||||
domain: string;
|
|
||||||
redis?: SessionRedisOptions;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface EmailNotifierConfiguration {
|
|
||||||
username: string;
|
|
||||||
password: string;
|
|
||||||
sender: string;
|
|
||||||
service: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface SmtpNotifierConfiguration {
|
|
||||||
username?: string;
|
|
||||||
password?: string;
|
|
||||||
host: string;
|
|
||||||
port: number;
|
|
||||||
secure: boolean;
|
|
||||||
sender: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface FileSystemNotifierConfiguration {
|
|
||||||
filename: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface NotifierConfiguration {
|
|
||||||
email?: EmailNotifierConfiguration;
|
|
||||||
smtp?: SmtpNotifierConfiguration;
|
|
||||||
filesystem?: FileSystemNotifierConfiguration;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface MongoStorageConfiguration {
|
|
||||||
url: string;
|
|
||||||
database: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface LocalStorageConfiguration {
|
|
||||||
path?: string;
|
|
||||||
in_memory?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface StorageConfiguration {
|
|
||||||
local?: LocalStorageConfiguration;
|
|
||||||
mongo?: MongoStorageConfiguration;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface RegulationConfiguration {
|
|
||||||
max_retries: number;
|
|
||||||
find_time: number;
|
|
||||||
ban_time: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare type AuthenticationMethod = 'two_factor' | 'single_factor';
|
|
||||||
declare type AuthenticationMethodPerSubdomain = { [subdomain: string]: AuthenticationMethod }
|
|
||||||
|
|
||||||
export interface AuthenticationMethodsConfiguration {
|
|
||||||
default_method: AuthenticationMethod;
|
|
||||||
per_subdomain_methods?: AuthenticationMethodPerSubdomain;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface TOTPConfiguration {
|
|
||||||
issuer: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface UserConfiguration {
|
|
||||||
port?: number;
|
|
||||||
logs_level?: string;
|
|
||||||
ldap: UserLdapConfiguration;
|
|
||||||
session: SessionCookieConfiguration;
|
|
||||||
storage: StorageConfiguration;
|
|
||||||
notifier: NotifierConfiguration;
|
|
||||||
authentication_methods?: AuthenticationMethodsConfiguration;
|
|
||||||
access_control?: ACLConfiguration;
|
|
||||||
regulation: RegulationConfiguration;
|
|
||||||
default_redirection_url?: string;
|
|
||||||
totp?: TOTPConfiguration;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface AppConfiguration {
|
|
||||||
port: number;
|
|
||||||
logs_level: string;
|
|
||||||
ldap: LdapConfiguration;
|
|
||||||
session: SessionCookieConfiguration;
|
|
||||||
storage: StorageConfiguration;
|
|
||||||
notifier: NotifierConfiguration;
|
|
||||||
authentication_methods: AuthenticationMethodsConfiguration;
|
|
||||||
access_control?: ACLConfiguration;
|
|
||||||
regulation: RegulationConfiguration;
|
|
||||||
default_redirection_url?: string;
|
|
||||||
totp: TOTPConfiguration;
|
|
||||||
}
|
|
|
@ -1,13 +1,11 @@
|
||||||
import * as Assert from "assert";
|
import * as Assert from "assert";
|
||||||
import {
|
import { Configuration } from "./schema/Configuration";
|
||||||
UserConfiguration,
|
import { ACLConfiguration } from "./schema/AclConfiguration";
|
||||||
LdapConfiguration, ACLConfiguration
|
import { ConfigurationParser } from "./ConfigurationParser";
|
||||||
} from "../../src/lib/configuration/Configuration";
|
|
||||||
import { ConfigurationParser } from "../../src/lib/configuration/ConfigurationParser";
|
|
||||||
|
|
||||||
describe("test config parser", function () {
|
describe("configuration/ConfigurationParser", function () {
|
||||||
function buildYamlConfig(): UserConfiguration {
|
function buildYamlConfig(): Configuration {
|
||||||
const yaml_config: UserConfiguration = {
|
const yaml_config: Configuration = {
|
||||||
port: 8080,
|
port: 8080,
|
||||||
ldap: {
|
ldap: {
|
||||||
url: "http://ldap",
|
url: "http://ldap",
|
||||||
|
@ -160,11 +158,11 @@ describe("test config parser", function () {
|
||||||
userConfig.access_control = {} as any;
|
userConfig.access_control = {} as any;
|
||||||
const config = ConfigurationParser.parse(userConfig);
|
const config = ConfigurationParser.parse(userConfig);
|
||||||
Assert.deepEqual(config.access_control, {
|
Assert.deepEqual(config.access_control, {
|
||||||
default_policy: "deny",
|
default_policy: "allow",
|
||||||
any: [],
|
any: [],
|
||||||
users: {},
|
users: {},
|
||||||
groups: {}
|
groups: {}
|
||||||
} as ACLConfiguration);
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,109 +1,39 @@
|
||||||
|
|
||||||
import * as ObjectPath from "object-path";
|
import * as ObjectPath from "object-path";
|
||||||
import {
|
import { Configuration, complete } from "./schema/Configuration";
|
||||||
AppConfiguration, UserConfiguration, NotifierConfiguration,
|
import Ajv = require("ajv");
|
||||||
ACLConfiguration, LdapConfiguration, SessionRedisOptions,
|
import Path = require("path");
|
||||||
MongoStorageConfiguration, LocalStorageConfiguration,
|
|
||||||
UserLdapConfiguration
|
|
||||||
} from "./Configuration";
|
|
||||||
import Util = require("util");
|
import Util = require("util");
|
||||||
import { ACLAdapter } from "./adapters/ACLAdapter";
|
|
||||||
import { TOTPAdapter } from "./adapters/TOTPAdapter";
|
|
||||||
import { AuthenticationMethodsAdapter } from "./adapters/AuthenticationMethodsAdapter";
|
|
||||||
import { Validator } from "./Validator";
|
|
||||||
|
|
||||||
const LDAP_URL_ENV_VARIABLE = "LDAP_URL";
|
|
||||||
|
|
||||||
function get_optional<T>(config: object, path: string, default_value: T): T {
|
|
||||||
let entry = default_value;
|
|
||||||
if (ObjectPath.has(config, path)) {
|
|
||||||
entry = ObjectPath.get<object, T>(config, path);
|
|
||||||
}
|
|
||||||
return entry;
|
|
||||||
}
|
|
||||||
|
|
||||||
function ensure_key_existence(config: object, path: string): void {
|
|
||||||
if (!ObjectPath.has(config, path)) {
|
|
||||||
throw new Error(`Configuration error: key '${path}' is missing in configuration file`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function adaptLdapConfiguration(userConfig: UserLdapConfiguration): LdapConfiguration {
|
|
||||||
const DEFAULT_USERS_FILTER = "cn={0}";
|
|
||||||
const DEFAULT_GROUPS_FILTER = "member={dn}";
|
|
||||||
const DEFAULT_GROUP_NAME_ATTRIBUTE = "cn";
|
|
||||||
const DEFAULT_MAIL_ATTRIBUTE = "mail";
|
|
||||||
|
|
||||||
let usersDN = userConfig.base_dn;
|
|
||||||
if (userConfig.additional_users_dn)
|
|
||||||
usersDN = userConfig.additional_users_dn + "," + usersDN;
|
|
||||||
|
|
||||||
let groupsDN = userConfig.base_dn;
|
|
||||||
if (userConfig.additional_groups_dn)
|
|
||||||
groupsDN = userConfig.additional_groups_dn + "," + groupsDN;
|
|
||||||
|
|
||||||
return {
|
|
||||||
url: userConfig.url,
|
|
||||||
users_dn: usersDN,
|
|
||||||
users_filter: userConfig.users_filter || DEFAULT_USERS_FILTER,
|
|
||||||
groups_dn: groupsDN,
|
|
||||||
groups_filter: userConfig.groups_filter || DEFAULT_GROUPS_FILTER,
|
|
||||||
group_name_attribute: userConfig.group_name_attribute || DEFAULT_GROUP_NAME_ATTRIBUTE,
|
|
||||||
mail_attribute: userConfig.mail_attribute || DEFAULT_MAIL_ATTRIBUTE,
|
|
||||||
password: userConfig.password,
|
|
||||||
user: userConfig.user
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function adaptFromUserConfiguration(userConfiguration: UserConfiguration)
|
|
||||||
: AppConfiguration {
|
|
||||||
if (!Validator.isValid(userConfiguration))
|
|
||||||
throw new Error("Configuration is malformed. Please double check your configuration file.");
|
|
||||||
|
|
||||||
const port = userConfiguration.port || 8080;
|
|
||||||
const ldapConfiguration = adaptLdapConfiguration(userConfiguration.ldap);
|
|
||||||
const authenticationMethods = AuthenticationMethodsAdapter
|
|
||||||
.adapt(userConfiguration.authentication_methods);
|
|
||||||
const totpConfiguration = TOTPAdapter.adapt(userConfiguration.totp);
|
|
||||||
|
|
||||||
return {
|
|
||||||
port: port,
|
|
||||||
ldap: ldapConfiguration,
|
|
||||||
session: {
|
|
||||||
domain: ObjectPath.get<object, string>(userConfiguration, "session.domain"),
|
|
||||||
secret: ObjectPath.get<object, string>(userConfiguration, "session.secret"),
|
|
||||||
expiration: get_optional<number>(userConfiguration, "session.expiration", 3600000), // in ms
|
|
||||||
inactivity: get_optional<number>(userConfiguration, "session.inactivity", undefined),
|
|
||||||
redis: ObjectPath.get<object, SessionRedisOptions>(userConfiguration, "session.redis")
|
|
||||||
},
|
|
||||||
storage: {
|
|
||||||
local: get_optional<LocalStorageConfiguration>(userConfiguration, "storage.local", undefined),
|
|
||||||
mongo: get_optional<MongoStorageConfiguration>(userConfiguration, "storage.mongo", undefined)
|
|
||||||
},
|
|
||||||
logs_level: get_optional<string>(userConfiguration, "logs_level", "info"),
|
|
||||||
notifier: ObjectPath.get<object, NotifierConfiguration>(userConfiguration, "notifier"),
|
|
||||||
access_control: ACLAdapter.adapt(userConfiguration.access_control),
|
|
||||||
regulation: userConfiguration.regulation,
|
|
||||||
authentication_methods: authenticationMethods,
|
|
||||||
default_redirection_url: userConfiguration.default_redirection_url,
|
|
||||||
totp: totpConfiguration
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export class ConfigurationParser {
|
export class ConfigurationParser {
|
||||||
static parse(userConfiguration: UserConfiguration): AppConfiguration {
|
private static parseTypes(configuration: Configuration): string[] {
|
||||||
const errors = Validator.isValid(userConfiguration);
|
const schema = require(Path.resolve(__dirname, "./Configuration.schema.json"));
|
||||||
if (errors.length > 0) {
|
const ajv = new Ajv({
|
||||||
errors.forEach((e: string) => { console.log(e); });
|
allErrors: true,
|
||||||
|
missingRefs: "fail"
|
||||||
|
});
|
||||||
|
ajv.addMetaSchema(require("ajv/lib/refs/json-schema-draft-06.json"));
|
||||||
|
const valid = ajv.validate(schema, configuration);
|
||||||
|
if (!valid)
|
||||||
|
return ajv.errors.map(
|
||||||
|
(e: Ajv.ErrorObject) => { return ajv.errorsText([e]); });
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
static parse(configuration: Configuration): Configuration {
|
||||||
|
const validationErrors = this.parseTypes(configuration);
|
||||||
|
if (validationErrors.length > 0) {
|
||||||
|
validationErrors.forEach((e: string) => { console.log(e); });
|
||||||
throw new Error("Malformed configuration. Please double-check your configuration file.");
|
throw new Error("Malformed configuration. Please double-check your configuration file.");
|
||||||
}
|
}
|
||||||
const appConfiguration = adaptFromUserConfiguration(userConfiguration);
|
|
||||||
|
|
||||||
const ldapUrl = process.env[LDAP_URL_ENV_VARIABLE];
|
const [newConfiguration, completionErrors] = complete(configuration);
|
||||||
if (ldapUrl)
|
|
||||||
appConfiguration.ldap.url = ldapUrl;
|
|
||||||
|
|
||||||
return appConfiguration;
|
if (completionErrors.length > 0) {
|
||||||
|
completionErrors.forEach((e: string) => { console.log(e); });
|
||||||
|
throw new Error("Malformed configuration. Please double-check your configuration file.");
|
||||||
|
}
|
||||||
|
return newConfiguration;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,15 +1,15 @@
|
||||||
import { SessionConfigurationBuilder } from "../src/lib/configuration/SessionConfigurationBuilder";
|
import { SessionConfigurationBuilder } from "./SessionConfigurationBuilder";
|
||||||
import { AppConfiguration } from "../src/lib/configuration/Configuration";
|
import { Configuration } from "./schema/Configuration";
|
||||||
import { GlobalDependencies } from "../types/Dependencies";
|
import { GlobalDependencies } from "../../../types/Dependencies";
|
||||||
|
|
||||||
import ExpressSession = require("express-session");
|
import ExpressSession = require("express-session");
|
||||||
import ConnectRedis = require("connect-redis");
|
import ConnectRedis = require("connect-redis");
|
||||||
import Sinon = require("sinon");
|
import Sinon = require("sinon");
|
||||||
import Assert = require("assert");
|
import Assert = require("assert");
|
||||||
|
|
||||||
describe("test session configuration builder", function () {
|
describe("configuration/SessionConfigurationBuilder", function () {
|
||||||
it("should return session options without redis options", function () {
|
it("should return session options without redis options", function () {
|
||||||
const configuration: AppConfiguration = {
|
const configuration: Configuration = {
|
||||||
access_control: {
|
access_control: {
|
||||||
default_policy: "deny",
|
default_policy: "deny",
|
||||||
any: [],
|
any: [],
|
||||||
|
@ -22,9 +22,10 @@ describe("test session configuration builder", function () {
|
||||||
ldap: {
|
ldap: {
|
||||||
url: "ldap://ldap",
|
url: "ldap://ldap",
|
||||||
user: "user",
|
user: "user",
|
||||||
|
base_dn: "dc=example,dc=com",
|
||||||
password: "password",
|
password: "password",
|
||||||
groups_dn: "ou=groups,dc=example,dc=com",
|
additional_groups_dn: "ou=groups",
|
||||||
users_dn: "ou=users,dc=example,dc=com",
|
additional_users_dn: "ou=users",
|
||||||
group_name_attribute: "",
|
group_name_attribute: "",
|
||||||
groups_filter: "",
|
groups_filter: "",
|
||||||
mail_attribute: "",
|
mail_attribute: "",
|
||||||
|
@ -87,7 +88,7 @@ describe("test session configuration builder", function () {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should return session options with redis options", function () {
|
it("should return session options with redis options", function () {
|
||||||
const configuration: AppConfiguration = {
|
const configuration: Configuration = {
|
||||||
access_control: {
|
access_control: {
|
||||||
default_policy: "deny",
|
default_policy: "deny",
|
||||||
any: [],
|
any: [],
|
||||||
|
@ -101,8 +102,9 @@ describe("test session configuration builder", function () {
|
||||||
url: "ldap://ldap",
|
url: "ldap://ldap",
|
||||||
user: "user",
|
user: "user",
|
||||||
password: "password",
|
password: "password",
|
||||||
groups_dn: "ou=groups,dc=example,dc=com",
|
base_dn: "dc=example,dc=com",
|
||||||
users_dn: "ou=users,dc=example,dc=com",
|
additional_groups_dn: "ou=groups",
|
||||||
|
additional_users_dn: "ou=users",
|
||||||
group_name_attribute: "",
|
group_name_attribute: "",
|
||||||
groups_filter: "",
|
groups_filter: "",
|
||||||
mail_attribute: "",
|
mail_attribute: "",
|
|
@ -1,11 +1,11 @@
|
||||||
|
|
||||||
import ExpressSession = require("express-session");
|
import ExpressSession = require("express-session");
|
||||||
import { AppConfiguration } from "./Configuration";
|
import { Configuration } from "./schema/Configuration";
|
||||||
import { GlobalDependencies } from "../../../types/Dependencies";
|
import { GlobalDependencies } from "../../../types/Dependencies";
|
||||||
|
|
||||||
export class SessionConfigurationBuilder {
|
export class SessionConfigurationBuilder {
|
||||||
|
|
||||||
static build(configuration: AppConfiguration, deps: GlobalDependencies): ExpressSession.SessionOptions {
|
static build(configuration: Configuration, deps: GlobalDependencies): ExpressSession.SessionOptions {
|
||||||
const sessionOptions: ExpressSession.SessionOptions = {
|
const sessionOptions: ExpressSession.SessionOptions = {
|
||||||
secret: configuration.session.secret,
|
secret: configuration.session.secret,
|
||||||
resave: false,
|
resave: false,
|
||||||
|
|
|
@ -1,94 +0,0 @@
|
||||||
import Ajv = require("ajv");
|
|
||||||
import Path = require("path");
|
|
||||||
import Util = require("util");
|
|
||||||
import {
|
|
||||||
UserConfiguration, StorageConfiguration,
|
|
||||||
NotifierConfiguration, AuthenticationMethodsConfiguration
|
|
||||||
} from "./Configuration";
|
|
||||||
import { MethodCalculator } from "../authentication/MethodCalculator";
|
|
||||||
|
|
||||||
function validateSchema(configuration: UserConfiguration): string[] {
|
|
||||||
const schema = require(Path.resolve(__dirname, "./Configuration.schema.json"));
|
|
||||||
const ajv = new Ajv({
|
|
||||||
allErrors: true,
|
|
||||||
missingRefs: "fail"
|
|
||||||
});
|
|
||||||
ajv.addMetaSchema(require("ajv/lib/refs/json-schema-draft-06.json"));
|
|
||||||
const valid = ajv.validate(schema, configuration);
|
|
||||||
if (!valid)
|
|
||||||
return ajv.errors.map(
|
|
||||||
(e: Ajv.ErrorObject) => { return ajv.errorsText([e]); });
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
function diff(a: string[], b: string[]) {
|
|
||||||
return a.filter(function(i) {return b.indexOf(i) < 0; });
|
|
||||||
}
|
|
||||||
|
|
||||||
function validateUnknownKeys(path: string, obj: any, knownKeys: string[]) {
|
|
||||||
const keysSet = Object.keys(obj);
|
|
||||||
|
|
||||||
const unknownKeysSet = diff(keysSet, knownKeys);
|
|
||||||
if (unknownKeysSet.length > 0) {
|
|
||||||
const unknownKeys = Array.from(unknownKeysSet);
|
|
||||||
return unknownKeys.map((k: string) => { return Util.format("data.%s has unknown key '%s'", path, k); });
|
|
||||||
}
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
function validateStorage(storage: any): string[] {
|
|
||||||
const ERROR = "Storage must be either 'local' or 'mongo'";
|
|
||||||
|
|
||||||
if (!storage)
|
|
||||||
return [];
|
|
||||||
|
|
||||||
const errors = validateUnknownKeys("storage", storage, ["local", "mongo"]);
|
|
||||||
if (errors.length > 0)
|
|
||||||
return errors;
|
|
||||||
|
|
||||||
if (storage.local && storage.mongo)
|
|
||||||
return [ERROR];
|
|
||||||
|
|
||||||
if (!storage.local && !storage.mongo)
|
|
||||||
return [ERROR];
|
|
||||||
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
function validateNotifier(notifier: NotifierConfiguration,
|
|
||||||
authenticationMethods: AuthenticationMethodsConfiguration): string[] {
|
|
||||||
const ERROR = "Notifier must be either 'filesystem', 'email' or 'smtp'";
|
|
||||||
|
|
||||||
if (!notifier)
|
|
||||||
return [];
|
|
||||||
|
|
||||||
if (!MethodCalculator.isSingleFactorOnlyMode(authenticationMethods)) {
|
|
||||||
if (Object.keys(notifier).length != 1)
|
|
||||||
return ["A notifier needs to be declared when server is used with two-factor"];
|
|
||||||
|
|
||||||
if (notifier && notifier.filesystem && notifier.email && notifier.smtp)
|
|
||||||
return [ERROR];
|
|
||||||
|
|
||||||
if (notifier && !notifier.filesystem && !notifier.email && !notifier.smtp)
|
|
||||||
return [ERROR];
|
|
||||||
}
|
|
||||||
|
|
||||||
const errors = validateUnknownKeys("notifier", notifier, ["filesystem", "email", "smtp"]);
|
|
||||||
if (errors.length > 0)
|
|
||||||
return errors;
|
|
||||||
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
export class Validator {
|
|
||||||
static isValid(configuration: any): string[] {
|
|
||||||
const schemaErrors = validateSchema(configuration);
|
|
||||||
const storageErrors = validateStorage(configuration.storage);
|
|
||||||
const notifierErrors = validateNotifier(configuration.notifier,
|
|
||||||
configuration.authentication_methods);
|
|
||||||
|
|
||||||
return schemaErrors
|
|
||||||
.concat(storageErrors)
|
|
||||||
.concat(notifierErrors);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,39 +0,0 @@
|
||||||
import { ACLConfiguration } from "../Configuration";
|
|
||||||
import { ObjectCloner } from "../../utils/ObjectCloner";
|
|
||||||
|
|
||||||
const DEFAULT_POLICY = "deny";
|
|
||||||
|
|
||||||
function adaptDefaultPolicy(configuration: ACLConfiguration) {
|
|
||||||
if (!configuration.default_policy)
|
|
||||||
configuration.default_policy = DEFAULT_POLICY;
|
|
||||||
if (configuration.default_policy != "deny" && configuration.default_policy != "allow")
|
|
||||||
configuration.default_policy = DEFAULT_POLICY;
|
|
||||||
}
|
|
||||||
|
|
||||||
function adaptAny(configuration: ACLConfiguration) {
|
|
||||||
if (!configuration.any || !(configuration.any.constructor === Array))
|
|
||||||
configuration.any = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
function adaptGroups(configuration: ACLConfiguration) {
|
|
||||||
if (!configuration.groups || !(configuration.groups.constructor === Object))
|
|
||||||
configuration.groups = {};
|
|
||||||
}
|
|
||||||
|
|
||||||
function adaptUsers(configuration: ACLConfiguration) {
|
|
||||||
if (!configuration.users || !(configuration.users.constructor === Object))
|
|
||||||
configuration.users = {};
|
|
||||||
}
|
|
||||||
|
|
||||||
export class ACLAdapter {
|
|
||||||
static adapt(configuration: ACLConfiguration): ACLConfiguration {
|
|
||||||
if (!configuration) return;
|
|
||||||
|
|
||||||
const newConfiguration: ACLConfiguration = ObjectCloner.clone(configuration);
|
|
||||||
adaptDefaultPolicy(newConfiguration);
|
|
||||||
adaptAny(newConfiguration);
|
|
||||||
adaptGroups(newConfiguration);
|
|
||||||
adaptUsers(newConfiguration);
|
|
||||||
return newConfiguration;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,30 +0,0 @@
|
||||||
import { AuthenticationMethodsConfiguration } from "../Configuration";
|
|
||||||
import { ObjectCloner } from "../../utils/ObjectCloner";
|
|
||||||
|
|
||||||
function clone(obj: any): any {
|
|
||||||
return JSON.parse(JSON.stringify(obj));
|
|
||||||
}
|
|
||||||
|
|
||||||
export class AuthenticationMethodsAdapter {
|
|
||||||
static adapt(authentication_methods: AuthenticationMethodsConfiguration)
|
|
||||||
: AuthenticationMethodsConfiguration {
|
|
||||||
if (!authentication_methods) {
|
|
||||||
return {
|
|
||||||
default_method: "two_factor",
|
|
||||||
per_subdomain_methods: {}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const newAuthMethods: AuthenticationMethodsConfiguration
|
|
||||||
= ObjectCloner.clone(authentication_methods);
|
|
||||||
|
|
||||||
if (!newAuthMethods.default_method)
|
|
||||||
newAuthMethods.default_method = "two_factor";
|
|
||||||
|
|
||||||
if (!newAuthMethods.per_subdomain_methods ||
|
|
||||||
newAuthMethods.per_subdomain_methods.constructor !== Object)
|
|
||||||
newAuthMethods.per_subdomain_methods = {};
|
|
||||||
|
|
||||||
return newAuthMethods;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,20 +0,0 @@
|
||||||
import { TOTPConfiguration } from "../Configuration";
|
|
||||||
import { ObjectCloner } from "../../utils/ObjectCloner";
|
|
||||||
|
|
||||||
const DEFAULT_ISSUER = "authelia.com";
|
|
||||||
|
|
||||||
export class TOTPAdapter {
|
|
||||||
static adapt(configuration: TOTPConfiguration): TOTPConfiguration {
|
|
||||||
const newConfiguration = {
|
|
||||||
issuer: DEFAULT_ISSUER
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!configuration)
|
|
||||||
return newConfiguration;
|
|
||||||
|
|
||||||
if (configuration && configuration.issuer)
|
|
||||||
newConfiguration.issuer = configuration.issuer;
|
|
||||||
|
|
||||||
return newConfiguration;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
import { ACLConfiguration, complete } from "./AclConfiguration";
|
||||||
|
import Assert = require("assert");
|
||||||
|
|
||||||
|
describe("configuration/schema/AclConfiguration", function() {
|
||||||
|
it("should complete ACLConfiguration", function() {
|
||||||
|
const configuration: ACLConfiguration = {};
|
||||||
|
const newConfiguration = complete(configuration);
|
||||||
|
|
||||||
|
Assert.deepEqual(newConfiguration.default_policy, "allow");
|
||||||
|
Assert.deepEqual(newConfiguration.any, []);
|
||||||
|
Assert.deepEqual(newConfiguration.groups, {});
|
||||||
|
Assert.deepEqual(newConfiguration.users, {});
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,42 @@
|
||||||
|
|
||||||
|
export type ACLPolicy = "deny" | "allow";
|
||||||
|
|
||||||
|
export type ACLRule = {
|
||||||
|
domain: string;
|
||||||
|
policy: ACLPolicy;
|
||||||
|
resources?: string[];
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ACLDefaultRules = ACLRule[];
|
||||||
|
export type ACLGroupsRules = { [group: string]: ACLRule[]; };
|
||||||
|
export type ACLUsersRules = { [user: string]: ACLRule[]; };
|
||||||
|
|
||||||
|
export interface ACLConfiguration {
|
||||||
|
default_policy?: ACLPolicy;
|
||||||
|
any?: ACLDefaultRules;
|
||||||
|
groups?: ACLGroupsRules;
|
||||||
|
users?: ACLUsersRules;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function complete(configuration: ACLConfiguration): ACLConfiguration {
|
||||||
|
const newConfiguration: ACLConfiguration = (configuration)
|
||||||
|
? JSON.parse(JSON.stringify(configuration)) : {};
|
||||||
|
|
||||||
|
if (!newConfiguration.default_policy) {
|
||||||
|
newConfiguration.default_policy = "allow";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!newConfiguration.any) {
|
||||||
|
newConfiguration.any = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!newConfiguration.groups) {
|
||||||
|
newConfiguration.groups = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!newConfiguration.users) {
|
||||||
|
newConfiguration.users = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
return newConfiguration;
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
import Assert = require("assert");
|
||||||
|
import { AuthenticationMethodsConfiguration, complete } from "./AuthenticationMethodsConfiguration";
|
||||||
|
|
||||||
|
describe("configuration/schema/AuthenticationMethodsConfiguration", function() {
|
||||||
|
it("should ensure at least one key is provided", function() {
|
||||||
|
const configuration: AuthenticationMethodsConfiguration = {};
|
||||||
|
const newConfiguration = complete(configuration);
|
||||||
|
|
||||||
|
Assert.deepEqual(newConfiguration.default_method, "two_factor");
|
||||||
|
Assert.deepEqual(newConfiguration.per_subdomain_methods, []);
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,21 @@
|
||||||
|
export type AuthenticationMethod = "two_factor" | "single_factor";
|
||||||
|
export type AuthenticationMethodPerSubdomain = { [subdomain: string]: AuthenticationMethod };
|
||||||
|
|
||||||
|
export interface AuthenticationMethodsConfiguration {
|
||||||
|
default_method?: AuthenticationMethod;
|
||||||
|
per_subdomain_methods?: AuthenticationMethodPerSubdomain;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function complete(configuration: AuthenticationMethodsConfiguration): AuthenticationMethodsConfiguration {
|
||||||
|
const newConfiguration: AuthenticationMethodsConfiguration = (configuration) ? JSON.parse(JSON.stringify(configuration)) : {};
|
||||||
|
|
||||||
|
if (!newConfiguration.default_method) {
|
||||||
|
newConfiguration.default_method = "two_factor";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!newConfiguration.per_subdomain_methods) {
|
||||||
|
newConfiguration.per_subdomain_methods = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
return newConfiguration;
|
||||||
|
}
|
|
@ -0,0 +1,55 @@
|
||||||
|
import { ACLConfiguration, complete as AclConfigurationComplete } from "./AclConfiguration";
|
||||||
|
import { AuthenticationMethodsConfiguration, complete as AuthenticationMethodsConfigurationComplete } from "./AuthenticationMethodsConfiguration";
|
||||||
|
import { LdapConfiguration, complete as LdapConfigurationComplete } from "./LdapConfiguration";
|
||||||
|
import { NotifierConfiguration, complete as NotifierConfigurationComplete } from "./NotifierConfiguration";
|
||||||
|
import { RegulationConfiguration, complete as RegulationConfigurationComplete } from "./RegulationConfiguration";
|
||||||
|
import { SessionConfiguration, complete as SessionConfigurationComplete } from "./SessionConfiguration";
|
||||||
|
import { StorageConfiguration, complete as StorageConfigurationComplete } from "./StorageConfiguration";
|
||||||
|
import { TotpConfiguration, complete as TotpConfigurationComplete } from "./TotpConfiguration";
|
||||||
|
import { MethodCalculator } from "../../authentication/MethodCalculator";
|
||||||
|
|
||||||
|
export interface Configuration {
|
||||||
|
access_control?: ACLConfiguration;
|
||||||
|
ldap: LdapConfiguration;
|
||||||
|
authentication_methods?: AuthenticationMethodsConfiguration;
|
||||||
|
default_redirection_url?: string;
|
||||||
|
logs_level?: string;
|
||||||
|
notifier?: NotifierConfiguration;
|
||||||
|
port?: number;
|
||||||
|
regulation?: RegulationConfiguration;
|
||||||
|
session?: SessionConfiguration;
|
||||||
|
storage?: StorageConfiguration;
|
||||||
|
totp?: TotpConfiguration;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function complete(configuration: Configuration): [Configuration, string[]] {
|
||||||
|
const newConfiguration: Configuration = JSON.parse(JSON.stringify(configuration));
|
||||||
|
const errors: string[] = [];
|
||||||
|
|
||||||
|
newConfiguration.access_control = AclConfigurationComplete(newConfiguration.access_control);
|
||||||
|
newConfiguration.ldap = LdapConfigurationComplete(newConfiguration.ldap);
|
||||||
|
|
||||||
|
newConfiguration.authentication_methods = AuthenticationMethodsConfigurationComplete(newConfiguration.authentication_methods);
|
||||||
|
|
||||||
|
if (!newConfiguration.logs_level) {
|
||||||
|
newConfiguration.logs_level = "info";
|
||||||
|
}
|
||||||
|
|
||||||
|
// In single factor mode, notifier section is optional.
|
||||||
|
if (!MethodCalculator.isSingleFactorOnlyMode(newConfiguration.authentication_methods)) {
|
||||||
|
const [notifier, error] = NotifierConfigurationComplete(newConfiguration.notifier);
|
||||||
|
newConfiguration.notifier = notifier;
|
||||||
|
if (error) errors.push(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!newConfiguration.port) {
|
||||||
|
newConfiguration.port = 8080;
|
||||||
|
}
|
||||||
|
|
||||||
|
newConfiguration.regulation = RegulationConfigurationComplete(newConfiguration.regulation);
|
||||||
|
newConfiguration.session = SessionConfigurationComplete(newConfiguration.session);
|
||||||
|
newConfiguration.storage = StorageConfigurationComplete(newConfiguration.storage);
|
||||||
|
newConfiguration.totp = TotpConfigurationComplete(newConfiguration.totp);
|
||||||
|
|
||||||
|
return [newConfiguration, errors];
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
import Assert = require("assert");
|
||||||
|
import { LdapConfiguration, complete } from "./LdapConfiguration";
|
||||||
|
|
||||||
|
describe("configuration/schema/AuthenticationMethodsConfiguration", function() {
|
||||||
|
it("should ensure at least one key is provided", function() {
|
||||||
|
const configuration: LdapConfiguration = {
|
||||||
|
url: "ldap.example.com",
|
||||||
|
base_dn: "dc=example,dc=com",
|
||||||
|
user: "admin",
|
||||||
|
password: "password"
|
||||||
|
};
|
||||||
|
const newConfiguration = complete(configuration);
|
||||||
|
|
||||||
|
Assert.deepEqual(newConfiguration, {
|
||||||
|
url: "ldap.example.com",
|
||||||
|
base_dn: "dc=example,dc=com",
|
||||||
|
user: "admin",
|
||||||
|
password: "password",
|
||||||
|
users_filter: "cn={0}",
|
||||||
|
group_name_attribute: "cn",
|
||||||
|
groups_filter: "member={dn}",
|
||||||
|
mail_attribute: "mail"
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,40 @@
|
||||||
|
import Util = require("util");
|
||||||
|
|
||||||
|
export interface LdapConfiguration {
|
||||||
|
url: string;
|
||||||
|
base_dn: string;
|
||||||
|
|
||||||
|
additional_users_dn?: string;
|
||||||
|
users_filter?: string;
|
||||||
|
|
||||||
|
additional_groups_dn?: string;
|
||||||
|
groups_filter?: string;
|
||||||
|
|
||||||
|
group_name_attribute?: string;
|
||||||
|
mail_attribute?: string;
|
||||||
|
|
||||||
|
user: string; // admin username
|
||||||
|
password: string; // admin password
|
||||||
|
}
|
||||||
|
|
||||||
|
export function complete(configuration: LdapConfiguration): LdapConfiguration {
|
||||||
|
const newConfiguration: LdapConfiguration = (configuration) ? JSON.parse(JSON.stringify(configuration)) : {};
|
||||||
|
|
||||||
|
if (!newConfiguration.users_filter) {
|
||||||
|
newConfiguration.users_filter = "cn={0}";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!newConfiguration.groups_filter) {
|
||||||
|
newConfiguration.groups_filter = "member={dn}";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!newConfiguration.group_name_attribute) {
|
||||||
|
newConfiguration.group_name_attribute = "cn";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!newConfiguration.mail_attribute) {
|
||||||
|
newConfiguration.mail_attribute = "mail";
|
||||||
|
}
|
||||||
|
|
||||||
|
return newConfiguration;
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
import Assert = require("assert");
|
||||||
|
import { NotifierConfiguration, complete } from "./NotifierConfiguration";
|
||||||
|
|
||||||
|
describe("configuration/schema/NotifierConfiguration", function() {
|
||||||
|
it("should ensure at least one key is provided", function() {
|
||||||
|
const configuration: NotifierConfiguration = {};
|
||||||
|
const [newConfiguration, error] = complete(configuration);
|
||||||
|
|
||||||
|
Assert.equal(error, "Notifier must have one of the following keys: 'filesystem', 'email' or 'smtp'");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should ensure there is no more than one key", function() {
|
||||||
|
const configuration: NotifierConfiguration = {
|
||||||
|
smtp: {
|
||||||
|
host: "smtp.example.com",
|
||||||
|
port: 25,
|
||||||
|
secure: false,
|
||||||
|
sender: "test@example.com"
|
||||||
|
},
|
||||||
|
email: {
|
||||||
|
username: "test",
|
||||||
|
password: "test",
|
||||||
|
sender: "test@example.com",
|
||||||
|
service: "gmail"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const [newConfiguration, error] = complete(configuration);
|
||||||
|
|
||||||
|
Assert.equal(error, "Notifier must have one of the following keys: 'filesystem', 'email' or 'smtp'");
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,42 @@
|
||||||
|
|
||||||
|
export interface EmailNotifierConfiguration {
|
||||||
|
username: string;
|
||||||
|
password: string;
|
||||||
|
sender: string;
|
||||||
|
service: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SmtpNotifierConfiguration {
|
||||||
|
username?: string;
|
||||||
|
password?: string;
|
||||||
|
host: string;
|
||||||
|
port: number;
|
||||||
|
secure: boolean;
|
||||||
|
sender: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface FileSystemNotifierConfiguration {
|
||||||
|
filename: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface NotifierConfiguration {
|
||||||
|
email?: EmailNotifierConfiguration;
|
||||||
|
smtp?: SmtpNotifierConfiguration;
|
||||||
|
filesystem?: FileSystemNotifierConfiguration;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function complete(configuration: NotifierConfiguration): [NotifierConfiguration, string] {
|
||||||
|
const newConfiguration: NotifierConfiguration = (configuration) ? JSON.parse(JSON.stringify(configuration)) : {};
|
||||||
|
|
||||||
|
const ERROR = "Notifier must have one of the following keys: 'filesystem', 'email' or 'smtp'";
|
||||||
|
|
||||||
|
if (Object.keys(newConfiguration).length != 1)
|
||||||
|
return [newConfiguration, ERROR];
|
||||||
|
|
||||||
|
const key = Object.keys(newConfiguration)[0];
|
||||||
|
|
||||||
|
if (key != "filesystem" && key != "smtp" && key != "email")
|
||||||
|
return [newConfiguration, ERROR];
|
||||||
|
|
||||||
|
return [newConfiguration, undefined];
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
import Assert = require("assert");
|
||||||
|
import { RegulationConfiguration, complete } from "./RegulationConfiguration";
|
||||||
|
|
||||||
|
describe("configuration/schema/RegulationConfiguration", function() {
|
||||||
|
it("should return default regulation configuration", function() {
|
||||||
|
const configuration: RegulationConfiguration = {};
|
||||||
|
const newConfiguration = complete(configuration);
|
||||||
|
|
||||||
|
Assert.equal(newConfiguration.ban_time, 300);
|
||||||
|
Assert.equal(newConfiguration.find_time, 120);
|
||||||
|
Assert.equal(newConfiguration.max_retries, 3);
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,23 @@
|
||||||
|
export interface RegulationConfiguration {
|
||||||
|
max_retries?: number;
|
||||||
|
find_time?: number;
|
||||||
|
ban_time?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function complete(configuration: RegulationConfiguration): RegulationConfiguration {
|
||||||
|
const newConfiguration: RegulationConfiguration = (configuration) ? JSON.parse(JSON.stringify(configuration)) : {};
|
||||||
|
|
||||||
|
if (!newConfiguration.max_retries) {
|
||||||
|
newConfiguration.max_retries = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!newConfiguration.find_time) {
|
||||||
|
newConfiguration.find_time = 120; // seconds
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!newConfiguration.ban_time) {
|
||||||
|
newConfiguration.ban_time = 300; // seconds
|
||||||
|
}
|
||||||
|
|
||||||
|
return newConfiguration;
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
import Assert = require("assert");
|
||||||
|
import { SessionConfiguration, complete } from "./SessionConfiguration";
|
||||||
|
|
||||||
|
describe("configuration/schema/SessionConfiguration", function() {
|
||||||
|
it("should return default regulation configuration", function() {
|
||||||
|
const configuration: SessionConfiguration = {
|
||||||
|
domain: "example.com",
|
||||||
|
secret: "unsecure_secret"
|
||||||
|
};
|
||||||
|
const newConfiguration = complete(configuration);
|
||||||
|
|
||||||
|
Assert.equal(newConfiguration.expiration, 3600000);
|
||||||
|
Assert.equal(newConfiguration.inactivity, undefined);
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,26 @@
|
||||||
|
export interface SessionRedisOptions {
|
||||||
|
host: string;
|
||||||
|
port: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SessionConfiguration {
|
||||||
|
domain: string;
|
||||||
|
secret: string;
|
||||||
|
expiration?: number;
|
||||||
|
inactivity?: number;
|
||||||
|
redis?: SessionRedisOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function complete(configuration: SessionConfiguration): SessionConfiguration {
|
||||||
|
const newConfiguration: SessionConfiguration = (configuration) ? JSON.parse(JSON.stringify(configuration)) : {};
|
||||||
|
|
||||||
|
if (!newConfiguration.expiration) {
|
||||||
|
newConfiguration.expiration = 3600000; // 1 hour
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!newConfiguration.inactivity) {
|
||||||
|
newConfiguration.inactivity = undefined; // disabled
|
||||||
|
}
|
||||||
|
|
||||||
|
return newConfiguration;
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
import Assert = require("assert");
|
||||||
|
import { StorageConfiguration, complete } from "./StorageConfiguration";
|
||||||
|
|
||||||
|
describe("configuration/schema/StorageConfiguration", function() {
|
||||||
|
it("should return default regulation configuration", function() {
|
||||||
|
const configuration: StorageConfiguration = {};
|
||||||
|
const newConfiguration = complete(configuration);
|
||||||
|
|
||||||
|
Assert.deepEqual(newConfiguration, {
|
||||||
|
local: {
|
||||||
|
in_memory: true
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,25 @@
|
||||||
|
export interface MongoStorageConfiguration {
|
||||||
|
url: string;
|
||||||
|
database: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface LocalStorageConfiguration {
|
||||||
|
path?: string;
|
||||||
|
in_memory?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface StorageConfiguration {
|
||||||
|
local?: LocalStorageConfiguration;
|
||||||
|
mongo?: MongoStorageConfiguration;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function complete(configuration: StorageConfiguration): StorageConfiguration {
|
||||||
|
const newConfiguration: StorageConfiguration = (configuration) ? JSON.parse(JSON.stringify(configuration)) : {};
|
||||||
|
|
||||||
|
if (!newConfiguration.local && !newConfiguration.mongo) {
|
||||||
|
newConfiguration.local = {
|
||||||
|
in_memory: true
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return newConfiguration;
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
export interface TotpConfiguration {
|
||||||
|
issuer: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function complete(configuration: TotpConfiguration): TotpConfiguration {
|
||||||
|
const newConfiguration: TotpConfiguration = (configuration) ? JSON.parse(JSON.stringify(configuration)) : {};
|
||||||
|
|
||||||
|
if (!newConfiguration.issuer) {
|
||||||
|
newConfiguration.issuer = "authelia.com";
|
||||||
|
}
|
||||||
|
|
||||||
|
return newConfiguration;
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
|
||||||
|
export interface UserInfo {
|
||||||
|
username: string;
|
||||||
|
password_hash: string;
|
||||||
|
email: string;
|
||||||
|
groups?: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export type UserDatabaseConfiguration = UserInfo[];
|
|
@ -1,9 +1,9 @@
|
||||||
import Assert = require("assert");
|
import Assert = require("assert");
|
||||||
import Sinon = require("sinon");
|
import Sinon = require("sinon");
|
||||||
import MongoDB = require("mongodb");
|
import MongoDB = require("mongodb");
|
||||||
import { MongoClient } from "../../../src/lib/connectors/mongo/MongoClient";
|
import { MongoClient } from "./MongoClient";
|
||||||
|
|
||||||
describe("MongoClient", function () {
|
describe("connectors/mongo/MongoClient", function () {
|
||||||
let mongoClientConnectStub: Sinon.SinonStub;
|
let mongoClientConnectStub: Sinon.SinonStub;
|
||||||
let mongoDatabase: any;
|
let mongoDatabase: any;
|
||||||
let mongoDatabaseCollectionStub: Sinon.SinonStub;
|
let mongoDatabaseCollectionStub: Sinon.SinonStub;
|
|
@ -2,10 +2,10 @@ import Assert = require("assert");
|
||||||
import Sinon = require("sinon");
|
import Sinon = require("sinon");
|
||||||
import MongoDB = require("mongodb");
|
import MongoDB = require("mongodb");
|
||||||
import BluebirdPromise = require("bluebird");
|
import BluebirdPromise = require("bluebird");
|
||||||
import { IMongoClient } from "../../../src/lib/connectors/mongo/IMongoClient";
|
import { IMongoClient } from "./IMongoClient";
|
||||||
import { MongoConnector } from "../../../src/lib/connectors/mongo/MongoConnector";
|
import { MongoConnector } from "./MongoConnector";
|
||||||
|
|
||||||
describe("MongoConnector", function () {
|
describe("connectors/mongo/MongoConnector", function () {
|
||||||
let mongoClientConnectStub: Sinon.SinonStub;
|
let mongoClientConnectStub: Sinon.SinonStub;
|
||||||
|
|
||||||
describe("create", function () {
|
describe("create", function () {
|
|
@ -1,7 +1,7 @@
|
||||||
import Assert = require("assert");
|
import Assert = require("assert");
|
||||||
import { MongoConnectorFactory } from "../../../src/lib/connectors/mongo/MongoConnectorFactory";
|
import { MongoConnectorFactory } from "./MongoConnectorFactory";
|
||||||
|
|
||||||
describe("MongoConnectorFactory", function () {
|
describe("connectors/mongo/MongoConnectorFactory", function () {
|
||||||
describe("create", function () {
|
describe("create", function () {
|
||||||
it("should create a connector", function () {
|
it("should create a connector", function () {
|
||||||
const factory = new MongoConnectorFactory();
|
const factory = new MongoConnectorFactory();
|
|
@ -1,16 +1,16 @@
|
||||||
|
|
||||||
import { Authenticator } from "../../src/lib/ldap/Authenticator";
|
import { Authenticator } from "./Authenticator";
|
||||||
import { LdapConfiguration } from "../../src/lib/configuration/Configuration";
|
import { LdapConfiguration } from "../configuration/schema/LdapConfiguration";
|
||||||
|
|
||||||
import Sinon = require("sinon");
|
import Sinon = require("sinon");
|
||||||
import BluebirdPromise = require("bluebird");
|
import BluebirdPromise = require("bluebird");
|
||||||
import Assert = require("assert");
|
import Assert = require("assert");
|
||||||
|
|
||||||
import { ClientFactoryStub } from "../mocks/ldap/ClientFactoryStub";
|
import { ClientFactoryStub } from "./ClientFactoryStub.spec";
|
||||||
import { ClientStub } from "../mocks/ldap/ClientStub";
|
import { ClientStub } from "./ClientStub.spec";
|
||||||
|
|
||||||
|
|
||||||
describe("test ldap authentication", function () {
|
describe("ldap/Authenticator", function () {
|
||||||
const USERNAME = "username";
|
const USERNAME = "username";
|
||||||
const PASSWORD = "password";
|
const PASSWORD = "password";
|
||||||
|
|
||||||
|
@ -31,9 +31,10 @@ describe("test ldap authentication", function () {
|
||||||
|
|
||||||
ldapConfig = {
|
ldapConfig = {
|
||||||
url: "http://localhost:324",
|
url: "http://localhost:324",
|
||||||
users_dn: "ou=users,dc=example,dc=com",
|
additional_users_dn: "ou=users",
|
||||||
|
additional_groups_dn: "ou=groups",
|
||||||
|
base_dn: "dc=example,dc=com",
|
||||||
users_filter: "cn={0}",
|
users_filter: "cn={0}",
|
||||||
groups_dn: "ou=groups,dc=example,dc=com",
|
|
||||||
groups_filter: "member={0}",
|
groups_filter: "member={0}",
|
||||||
mail_attribute: "mail",
|
mail_attribute: "mail",
|
||||||
group_name_attribute: "cn",
|
group_name_attribute: "cn",
|
|
@ -6,7 +6,7 @@ import { IClientFactory } from "./IClientFactory";
|
||||||
import { GroupsAndEmails } from "./IClient";
|
import { GroupsAndEmails } from "./IClient";
|
||||||
|
|
||||||
import { IAuthenticator } from "./IAuthenticator";
|
import { IAuthenticator } from "./IAuthenticator";
|
||||||
import { LdapConfiguration } from "../configuration/Configuration";
|
import { LdapConfiguration } from "../configuration/schema/LdapConfiguration";
|
||||||
import { EmailsAndGroupsRetriever } from "./EmailsAndGroupsRetriever";
|
import { EmailsAndGroupsRetriever } from "./EmailsAndGroupsRetriever";
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import BluebirdPromise = require("bluebird");
|
import BluebirdPromise = require("bluebird");
|
||||||
import { IAuthenticator } from "../../../src/lib/ldap/IAuthenticator";
|
import { IAuthenticator } from "../../../src/lib/ldap/IAuthenticator";
|
||||||
import { GroupsAndEmails } from "../../../src/lib/ldap/IClient";
|
import { GroupsAndEmails } from "./IClient";
|
||||||
import Sinon = require("sinon");
|
import Sinon = require("sinon");
|
||||||
|
|
||||||
export class AuthenticatorStub implements IAuthenticator {
|
export class AuthenticatorStub implements IAuthenticator {
|
|
@ -1,15 +1,15 @@
|
||||||
|
|
||||||
import { LdapConfiguration } from "../../src/lib/configuration/Configuration";
|
import { LdapConfiguration } from "../configuration/schema/LdapConfiguration";
|
||||||
import { Client } from "../../src/lib/ldap/Client";
|
import { Client } from "./Client";
|
||||||
import { LdapClientFactoryStub } from "../mocks/ldap/LdapClientFactoryStub";
|
import { LdapClientFactoryStub } from "./LdapClientFactoryStub.spec";
|
||||||
import { LdapClientStub } from "../mocks/ldap/LdapClientStub";
|
import { LdapClientStub } from "./LdapClientStub.spec";
|
||||||
|
|
||||||
import Sinon = require("sinon");
|
import Sinon = require("sinon");
|
||||||
import BluebirdPromise = require("bluebird");
|
import BluebirdPromise = require("bluebird");
|
||||||
import Assert = require("assert");
|
import Assert = require("assert");
|
||||||
import Winston = require("winston");
|
import Winston = require("winston");
|
||||||
|
|
||||||
describe("test authelia ldap client", function () {
|
describe("ldap/Client", function () {
|
||||||
const USERNAME = "username";
|
const USERNAME = "username";
|
||||||
const ADMIN_USER_DN = "cn=admin,dc=example,dc=com";
|
const ADMIN_USER_DN = "cn=admin,dc=example,dc=com";
|
||||||
const ADMIN_PASSWORD = "password";
|
const ADMIN_PASSWORD = "password";
|
||||||
|
@ -17,9 +17,10 @@ describe("test authelia ldap client", function () {
|
||||||
it("should replace {0} by username when searching for groups in LDAP", function () {
|
it("should replace {0} by username when searching for groups in LDAP", function () {
|
||||||
const options: LdapConfiguration = {
|
const options: LdapConfiguration = {
|
||||||
url: "ldap://ldap",
|
url: "ldap://ldap",
|
||||||
users_dn: "ou=users,dc=example,dc=com",
|
additional_users_dn: "ou=users",
|
||||||
|
additional_groups_dn: "ou=groups",
|
||||||
|
base_dn: "dc=example,dc=com",
|
||||||
users_filter: "cn={0}",
|
users_filter: "cn={0}",
|
||||||
groups_dn: "ou=groups,dc=example,dc=com",
|
|
||||||
groups_filter: "member=cn={0},ou=users,dc=example,dc=com",
|
groups_filter: "member=cn={0},ou=users,dc=example,dc=com",
|
||||||
group_name_attribute: "cn",
|
group_name_attribute: "cn",
|
||||||
mail_attribute: "mail",
|
mail_attribute: "mail",
|
||||||
|
@ -46,9 +47,10 @@ describe("test authelia ldap client", function () {
|
||||||
const USER_DN = "cn=user1,ou=users,dc=example,dc=com";
|
const USER_DN = "cn=user1,ou=users,dc=example,dc=com";
|
||||||
const options: LdapConfiguration = {
|
const options: LdapConfiguration = {
|
||||||
url: "ldap://ldap",
|
url: "ldap://ldap",
|
||||||
users_dn: "ou=users,dc=example,dc=com",
|
additional_users_dn: "ou=users",
|
||||||
|
additional_groups_dn: "ou=groups",
|
||||||
|
base_dn: "dc=example,dc=com",
|
||||||
users_filter: "cn={0}",
|
users_filter: "cn={0}",
|
||||||
groups_dn: "ou=groups,dc=example,dc=com",
|
|
||||||
groups_filter: "member={dn}",
|
groups_filter: "member={dn}",
|
||||||
group_name_attribute: "cn",
|
group_name_attribute: "cn",
|
||||||
mail_attribute: "mail",
|
mail_attribute: "mail",
|
||||||
|
@ -91,9 +93,10 @@ describe("test authelia ldap client", function () {
|
||||||
const USER_DN = "cn=user1,ou=users,dc=example,dc=com";
|
const USER_DN = "cn=user1,ou=users,dc=example,dc=com";
|
||||||
const options: LdapConfiguration = {
|
const options: LdapConfiguration = {
|
||||||
url: "ldap://ldap",
|
url: "ldap://ldap",
|
||||||
users_dn: "ou=users,dc=example,dc=com",
|
additional_users_dn: "ou=users",
|
||||||
|
additional_groups_dn: "ou=groups",
|
||||||
|
base_dn: "dc=example,dc=com",
|
||||||
users_filter: "cn={0}",
|
users_filter: "cn={0}",
|
||||||
groups_dn: "ou=groups,dc=example,dc=com",
|
|
||||||
groups_filter: "member={dn}",
|
groups_filter: "member={dn}",
|
||||||
group_name_attribute: "cn",
|
group_name_attribute: "cn",
|
||||||
mail_attribute: "custom_mail",
|
mail_attribute: "custom_mail",
|
|
@ -4,7 +4,7 @@ import { EventEmitter } from "events";
|
||||||
import { IClient, GroupsAndEmails } from "./IClient";
|
import { IClient, GroupsAndEmails } from "./IClient";
|
||||||
import { ILdapClient } from "./ILdapClient";
|
import { ILdapClient } from "./ILdapClient";
|
||||||
import { ILdapClientFactory } from "./ILdapClientFactory";
|
import { ILdapClientFactory } from "./ILdapClientFactory";
|
||||||
import { LdapConfiguration } from "../configuration/Configuration";
|
import { LdapConfiguration } from "../configuration/schema/LdapConfiguration";
|
||||||
import { Winston } from "../../../types/Dependencies";
|
import { Winston } from "../../../types/Dependencies";
|
||||||
import Util = require("util");
|
import Util = require("util");
|
||||||
import { HashGenerator } from "../utils/HashGenerator";
|
import { HashGenerator } from "../utils/HashGenerator";
|
||||||
|
@ -16,6 +16,9 @@ export class Client implements IClient {
|
||||||
private logger: Winston;
|
private logger: Winston;
|
||||||
private options: LdapConfiguration;
|
private options: LdapConfiguration;
|
||||||
|
|
||||||
|
private groupsSearchBase: string;
|
||||||
|
private usersSearchBase: string;
|
||||||
|
|
||||||
constructor(userDN: string, password: string, options: LdapConfiguration,
|
constructor(userDN: string, password: string, options: LdapConfiguration,
|
||||||
ldapClientFactory: ILdapClientFactory, logger: Winston) {
|
ldapClientFactory: ILdapClientFactory, logger: Winston) {
|
||||||
this.options = options;
|
this.options = options;
|
||||||
|
@ -23,6 +26,14 @@ export class Client implements IClient {
|
||||||
this.userDN = userDN;
|
this.userDN = userDN;
|
||||||
this.password = password;
|
this.password = password;
|
||||||
this.ldapClient = ldapClientFactory.create();
|
this.ldapClient = ldapClientFactory.create();
|
||||||
|
|
||||||
|
this.groupsSearchBase = (this.options.additional_groups_dn)
|
||||||
|
? Util.format("%s,%s", this.options.additional_groups_dn, this.options.base_dn)
|
||||||
|
: this.options.base_dn;
|
||||||
|
|
||||||
|
this.usersSearchBase = (this.options.additional_users_dn)
|
||||||
|
? Util.format("%s,%s", this.options.additional_users_dn, this.options.base_dn)
|
||||||
|
: this.options.base_dn;
|
||||||
}
|
}
|
||||||
|
|
||||||
open(): BluebirdPromise<void> {
|
open(): BluebirdPromise<void> {
|
||||||
|
@ -64,7 +75,7 @@ export class Client implements IClient {
|
||||||
attributes: [that.options.group_name_attribute],
|
attributes: [that.options.group_name_attribute],
|
||||||
filter: groupsFilter
|
filter: groupsFilter
|
||||||
};
|
};
|
||||||
return that.ldapClient.searchAsync(that.options.groups_dn, query);
|
return that.ldapClient.searchAsync(that.groupsSearchBase, query);
|
||||||
})
|
})
|
||||||
.then(function (docs: { cn: string }[]) {
|
.then(function (docs: { cn: string }[]) {
|
||||||
const groups = docs.map((doc: any) => { return doc.cn; });
|
const groups = docs.map((doc: any) => { return doc.cn; });
|
||||||
|
@ -85,7 +96,7 @@ export class Client implements IClient {
|
||||||
};
|
};
|
||||||
|
|
||||||
that.logger.debug("LDAP: searching for user dn of %s", username);
|
that.logger.debug("LDAP: searching for user dn of %s", username);
|
||||||
return that.ldapClient.searchAsync(this.options.users_dn, query)
|
return that.ldapClient.searchAsync(this.usersSearchBase, query)
|
||||||
.then(function (users: { dn: string }[]) {
|
.then(function (users: { dn: string }[]) {
|
||||||
if (users.length > 0) {
|
if (users.length > 0) {
|
||||||
that.logger.debug("LDAP: retrieved user dn is %s", users[0].dn);
|
that.logger.debug("LDAP: retrieved user dn is %s", users[0].dn);
|
||||||
|
|
|
@ -3,7 +3,7 @@ import { IClient } from "./IClient";
|
||||||
import { Client } from "./Client";
|
import { Client } from "./Client";
|
||||||
import { SanitizedClient } from "./SanitizedClient";
|
import { SanitizedClient } from "./SanitizedClient";
|
||||||
import { ILdapClientFactory } from "./ILdapClientFactory";
|
import { ILdapClientFactory } from "./ILdapClientFactory";
|
||||||
import { LdapConfiguration } from "../configuration/Configuration";
|
import { LdapConfiguration } from "../configuration/schema/LdapConfiguration";
|
||||||
import Ldapjs = require("ldapjs");
|
import Ldapjs = require("ldapjs");
|
||||||
import Winston = require("winston");
|
import Winston = require("winston");
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
|
|
||||||
import BluebirdPromise = require("bluebird");
|
import BluebirdPromise = require("bluebird");
|
||||||
import { IClient, GroupsAndEmails } from "../../../src/lib/ldap/IClient";
|
import { IClient, GroupsAndEmails } from "./IClient";
|
||||||
import Sinon = require("sinon");
|
import Sinon = require("sinon");
|
||||||
|
|
||||||
export class ClientStub implements IClient {
|
export class ClientStub implements IClient {
|
|
@ -3,7 +3,7 @@ import exceptions = require("../Exceptions");
|
||||||
import ldapjs = require("ldapjs");
|
import ldapjs = require("ldapjs");
|
||||||
import { Client } from "./Client";
|
import { Client } from "./Client";
|
||||||
import { IClientFactory } from "./IClientFactory";
|
import { IClientFactory } from "./IClientFactory";
|
||||||
import { LdapConfiguration } from "../configuration/Configuration";
|
import { LdapConfiguration } from "../configuration/schema/LdapConfiguration";
|
||||||
import { GroupsAndEmails } from "./IClient";
|
import { GroupsAndEmails } from "./IClient";
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,15 +1,15 @@
|
||||||
|
|
||||||
import { EmailsRetriever } from "../../src/lib/ldap/EmailsRetriever";
|
import { EmailsRetriever } from "./EmailsRetriever";
|
||||||
import { LdapConfiguration } from "../../src/lib/configuration/Configuration";
|
import { LdapConfiguration } from "../configuration/schema/LdapConfiguration";
|
||||||
|
|
||||||
import Sinon = require("sinon");
|
import Sinon = require("sinon");
|
||||||
import BluebirdPromise = require("bluebird");
|
import BluebirdPromise = require("bluebird");
|
||||||
import Assert = require("assert");
|
import Assert = require("assert");
|
||||||
|
|
||||||
import { ClientFactoryStub } from "../mocks/ldap/ClientFactoryStub";
|
import { ClientFactoryStub } from "./ClientFactoryStub.spec";
|
||||||
import { ClientStub } from "../mocks/ldap/ClientStub";
|
import { ClientStub } from "./ClientStub.spec";
|
||||||
|
|
||||||
describe("test emails retriever", function () {
|
describe("ldap/EmailsRetriever", function () {
|
||||||
const USERNAME = "username";
|
const USERNAME = "username";
|
||||||
const ADMIN_USER_DN = "cn=admin,dc=example,dc=com";
|
const ADMIN_USER_DN = "cn=admin,dc=example,dc=com";
|
||||||
const ADMIN_PASSWORD = "password";
|
const ADMIN_PASSWORD = "password";
|
||||||
|
@ -28,8 +28,9 @@ describe("test emails retriever", function () {
|
||||||
url: "http://ldap",
|
url: "http://ldap",
|
||||||
user: ADMIN_USER_DN,
|
user: ADMIN_USER_DN,
|
||||||
password: ADMIN_PASSWORD,
|
password: ADMIN_PASSWORD,
|
||||||
users_dn: "ou=users,dc=example,dc=com",
|
additional_users_dn: "ou=users",
|
||||||
groups_dn: "ou=groups,dc=example,dc=com",
|
additional_groups_dn: "ou=groups",
|
||||||
|
base_dn: "dc=example,dc=com",
|
||||||
group_name_attribute: "cn",
|
group_name_attribute: "cn",
|
||||||
groups_filter: "cn={0}",
|
groups_filter: "cn={0}",
|
||||||
mail_attribute: "mail",
|
mail_attribute: "mail",
|
|
@ -5,7 +5,7 @@ import { Client } from "./Client";
|
||||||
|
|
||||||
import { IClientFactory } from "./IClientFactory";
|
import { IClientFactory } from "./IClientFactory";
|
||||||
import { IEmailsRetriever } from "./IEmailsRetriever";
|
import { IEmailsRetriever } from "./IEmailsRetriever";
|
||||||
import { LdapConfiguration } from "../configuration/Configuration";
|
import { LdapConfiguration } from "../configuration/schema/LdapConfiguration";
|
||||||
|
|
||||||
|
|
||||||
export class EmailsRetriever implements IEmailsRetriever {
|
export class EmailsRetriever implements IEmailsRetriever {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import BluebirdPromise = require("bluebird");
|
import BluebirdPromise = require("bluebird");
|
||||||
import { IClient } from "../../../src/lib/ldap/IClient";
|
import { IClient } from "./IClient";
|
||||||
import { IEmailsRetriever } from "../../../src/lib/ldap/IEmailsRetriever";
|
import { IEmailsRetriever } from "./IEmailsRetriever";
|
||||||
import Sinon = require("sinon");
|
import Sinon = require("sinon");
|
||||||
|
|
||||||
export class EmailsRetrieverStub implements IEmailsRetriever {
|
export class EmailsRetrieverStub implements IEmailsRetriever {
|
|
@ -1,7 +1,7 @@
|
||||||
import Assert = require("assert");
|
import Assert = require("assert");
|
||||||
import { InputsSanitizer } from "../../src/lib/ldap/InputsSanitizer";
|
import { InputsSanitizer } from "./InputsSanitizer";
|
||||||
|
|
||||||
describe("test InputsSanitizer", function () {
|
describe("ldap/InputsSanitizer", function () {
|
||||||
it("should fail when special characters are used", function () {
|
it("should fail when special characters are used", function () {
|
||||||
Assert.throws(() => { InputsSanitizer.sanitize("ab,c"); }, Error);
|
Assert.throws(() => { InputsSanitizer.sanitize("ab,c"); }, Error);
|
||||||
Assert.throws(() => { InputsSanitizer.sanitize("a\\bc"); }, Error);
|
Assert.throws(() => { InputsSanitizer.sanitize("a\\bc"); }, Error);
|
|
@ -1,7 +1,7 @@
|
||||||
import { ILdapClientFactory } from "./ILdapClientFactory";
|
import { ILdapClientFactory } from "./ILdapClientFactory";
|
||||||
import { ILdapClient } from "./ILdapClient";
|
import { ILdapClient } from "./ILdapClient";
|
||||||
import { LdapClient } from "./LdapClient";
|
import { LdapClient } from "./LdapClient";
|
||||||
import { LdapConfiguration } from "../configuration/Configuration";
|
import { LdapConfiguration } from "../configuration/schema/LdapConfiguration";
|
||||||
|
|
||||||
import Ldapjs = require("ldapjs");
|
import Ldapjs = require("ldapjs");
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import Sinon = require("sinon");
|
import Sinon = require("sinon");
|
||||||
import BluebirdPromise = require("bluebird");
|
import BluebirdPromise = require("bluebird");
|
||||||
import { ILdapClientFactory } from "../../../src/lib/ldap/ILdapClientFactory";
|
import { ILdapClientFactory } from "./ILdapClientFactory";
|
||||||
import { ILdapClient } from "../../../src/lib/ldap/ILdapClient";
|
import { ILdapClient } from "./ILdapClient";
|
||||||
|
|
||||||
export class LdapClientFactoryStub implements ILdapClientFactory {
|
export class LdapClientFactoryStub implements ILdapClientFactory {
|
||||||
createStub: Sinon.SinonStub;
|
createStub: Sinon.SinonStub;
|
|
@ -1,6 +1,6 @@
|
||||||
import Sinon = require("sinon");
|
import Sinon = require("sinon");
|
||||||
import BluebirdPromise = require("bluebird");
|
import BluebirdPromise = require("bluebird");
|
||||||
import { ILdapClient } from "../../../src/lib/ldap/ILdapClient";
|
import { ILdapClient } from "./ILdapClient";
|
||||||
|
|
||||||
export class LdapClientStub implements ILdapClient {
|
export class LdapClientStub implements ILdapClient {
|
||||||
bindAsyncStub: Sinon.SinonStub;
|
bindAsyncStub: Sinon.SinonStub;
|
|
@ -1,13 +1,13 @@
|
||||||
import Sinon = require("sinon");
|
import Sinon = require("sinon");
|
||||||
import BluebirdPromise = require("bluebird");
|
import BluebirdPromise = require("bluebird");
|
||||||
import Assert = require("assert");
|
import Assert = require("assert");
|
||||||
import { PasswordUpdater } from "../../src/lib/ldap/PasswordUpdater";
|
import { PasswordUpdater } from "./PasswordUpdater";
|
||||||
import { LdapConfiguration } from "../../src/lib/configuration/Configuration";
|
import { LdapConfiguration } from "../configuration/schema/LdapConfiguration";
|
||||||
import { ClientFactoryStub } from "../mocks/ldap/ClientFactoryStub";
|
import { ClientFactoryStub } from "./ClientFactoryStub.spec";
|
||||||
import { ClientStub } from "../mocks/ldap/ClientStub";
|
import { ClientStub } from "./ClientStub.spec";
|
||||||
import { HashGenerator } from "../../src/lib/utils/HashGenerator";
|
import { HashGenerator } from "../utils/HashGenerator";
|
||||||
|
|
||||||
describe("test password update", function () {
|
describe("ldap/PasswordUpdater", function () {
|
||||||
const USERNAME = "username";
|
const USERNAME = "username";
|
||||||
const NEW_PASSWORD = "new-password";
|
const NEW_PASSWORD = "new-password";
|
||||||
|
|
||||||
|
@ -28,8 +28,9 @@ describe("test password update", function () {
|
||||||
url: "http://ldap",
|
url: "http://ldap",
|
||||||
user: ADMIN_USER_DN,
|
user: ADMIN_USER_DN,
|
||||||
password: ADMIN_PASSWORD,
|
password: ADMIN_PASSWORD,
|
||||||
users_dn: "ou=users,dc=example,dc=com",
|
additional_users_dn: "ou=users",
|
||||||
groups_dn: "ou=groups,dc=example,dc=com",
|
additional_groups_dn: "ou=groups",
|
||||||
|
base_dn: "dc=example,dc=com",
|
||||||
group_name_attribute: "cn",
|
group_name_attribute: "cn",
|
||||||
groups_filter: "cn={0}",
|
groups_filter: "cn={0}",
|
||||||
mail_attribute: "mail",
|
mail_attribute: "mail",
|
|
@ -4,7 +4,7 @@ import ldapjs = require("ldapjs");
|
||||||
import { Client } from "./Client";
|
import { Client } from "./Client";
|
||||||
|
|
||||||
import { IPasswordUpdater } from "./IPasswordUpdater";
|
import { IPasswordUpdater } from "./IPasswordUpdater";
|
||||||
import { LdapConfiguration } from "../configuration/Configuration";
|
import { LdapConfiguration } from "../configuration/schema/LdapConfiguration";
|
||||||
import { IClientFactory } from "./IClientFactory";
|
import { IClientFactory } from "./IClientFactory";
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import BluebirdPromise = require("bluebird");
|
import BluebirdPromise = require("bluebird");
|
||||||
import { IClient } from "../../../src/lib/ldap/IClient";
|
import { IClient } from "./IClient";
|
||||||
import { IPasswordUpdater } from "../../../src/lib/ldap/IPasswordUpdater";
|
import { IPasswordUpdater } from "./IPasswordUpdater";
|
||||||
import Sinon = require("sinon");
|
import Sinon = require("sinon");
|
||||||
|
|
||||||
export class PasswordUpdaterStub implements IPasswordUpdater {
|
export class PasswordUpdaterStub implements IPasswordUpdater {
|
|
@ -1,8 +1,8 @@
|
||||||
import BluebirdPromise = require("bluebird");
|
import BluebirdPromise = require("bluebird");
|
||||||
import { ClientStub } from "../mocks/ldap/ClientStub";
|
import { ClientStub } from "./ClientStub.spec";
|
||||||
import { SanitizedClient } from "../../src/lib/ldap/SanitizedClient";
|
import { SanitizedClient } from "./SanitizedClient";
|
||||||
|
|
||||||
describe("test SanitizedClient", function () {
|
describe("ldap/SanitizedClient", function () {
|
||||||
let client: SanitizedClient;
|
let client: SanitizedClient;
|
||||||
|
|
||||||
beforeEach(function () {
|
beforeEach(function () {
|
|
@ -1,6 +1,6 @@
|
||||||
import { IRequestLogger } from "../../src/lib/logging/IRequestLogger";
|
import { IRequestLogger } from "./IRequestLogger";
|
||||||
import Sinon = require("sinon");
|
import Sinon = require("sinon");
|
||||||
import { RequestLogger } from "../../src/lib/logging/RequestLogger";
|
import { RequestLogger } from "./RequestLogger";
|
||||||
import Winston = require("winston");
|
import Winston = require("winston");
|
||||||
import Express = require("express");
|
import Express = require("express");
|
||||||
|
|
|
@ -2,11 +2,11 @@ import * as sinon from "sinon";
|
||||||
import * as Assert from "assert";
|
import * as Assert from "assert";
|
||||||
import BluebirdPromise = require("bluebird");
|
import BluebirdPromise = require("bluebird");
|
||||||
|
|
||||||
import { MailSenderStub } from "../mocks/notifiers/MailSenderStub";
|
import { MailSenderStub } from "./MailSenderStub.spec";
|
||||||
import EMailNotifier = require("../../src/lib/notifiers/EMailNotifier");
|
import EmailNotifier = require("./EmailNotifier");
|
||||||
|
|
||||||
|
|
||||||
describe("test email notifier", function () {
|
describe("notifiers/EmailNotifier", function () {
|
||||||
it("should send an email to given user", function () {
|
it("should send an email to given user", function () {
|
||||||
const mailSender = new MailSenderStub();
|
const mailSender = new MailSenderStub();
|
||||||
const options = {
|
const options = {
|
||||||
|
@ -17,7 +17,7 @@ describe("test email notifier", function () {
|
||||||
};
|
};
|
||||||
|
|
||||||
mailSender.sendStub.returns(BluebirdPromise.resolve());
|
mailSender.sendStub.returns(BluebirdPromise.resolve());
|
||||||
const sender = new EMailNotifier.EMailNotifier(options, mailSender);
|
const sender = new EmailNotifier.EmailNotifier(options, mailSender);
|
||||||
const subject = "subject";
|
const subject = "subject";
|
||||||
const url = "http://test.com";
|
const url = "http://test.com";
|
||||||
|
|
||||||
|
@ -39,7 +39,7 @@ describe("test email notifier", function () {
|
||||||
};
|
};
|
||||||
|
|
||||||
mailSender.sendStub.returns(BluebirdPromise.reject(new Error("Failed to send mail")));
|
mailSender.sendStub.returns(BluebirdPromise.reject(new Error("Failed to send mail")));
|
||||||
const sender = new EMailNotifier.EMailNotifier(options, mailSender);
|
const sender = new EmailNotifier.EmailNotifier(options, mailSender);
|
||||||
const subject = "subject";
|
const subject = "subject";
|
||||||
const url = "http://test.com";
|
const url = "http://test.com";
|
||||||
|
|
|
@ -2,10 +2,10 @@
|
||||||
import * as BluebirdPromise from "bluebird";
|
import * as BluebirdPromise from "bluebird";
|
||||||
|
|
||||||
import { AbstractEmailNotifier } from "../notifiers/AbstractEmailNotifier";
|
import { AbstractEmailNotifier } from "../notifiers/AbstractEmailNotifier";
|
||||||
import { EmailNotifierConfiguration } from "../configuration/Configuration";
|
import { EmailNotifierConfiguration } from "../configuration/schema/NotifierConfiguration";
|
||||||
import { IMailSender } from "./IMailSender";
|
import { IMailSender } from "./IMailSender";
|
||||||
|
|
||||||
export class EMailNotifier extends AbstractEmailNotifier {
|
export class EmailNotifier extends AbstractEmailNotifier {
|
||||||
private mailSender: IMailSender;
|
private mailSender: IMailSender;
|
||||||
private sender: string;
|
private sender: string;
|
||||||
|
|
|
@ -4,7 +4,7 @@ import * as Fs from "fs";
|
||||||
import { INotifier } from "./INotifier";
|
import { INotifier } from "./INotifier";
|
||||||
import { Identity } from "../../../types/Identity";
|
import { Identity } from "../../../types/Identity";
|
||||||
|
|
||||||
import { FileSystemNotifierConfiguration } from "../configuration/Configuration";
|
import { FileSystemNotifierConfiguration } from "../configuration/schema/NotifierConfiguration";
|
||||||
|
|
||||||
export class FileSystemNotifier implements INotifier {
|
export class FileSystemNotifier implements INotifier {
|
||||||
private filename: string;
|
private filename: string;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { IMailSender } from "./IMailSender";
|
import { IMailSender } from "./IMailSender";
|
||||||
import { SmtpNotifierConfiguration, EmailNotifierConfiguration } from "../configuration/Configuration";
|
import { SmtpNotifierConfiguration, EmailNotifierConfiguration } from "../configuration/schema/NotifierConfiguration";
|
||||||
|
|
||||||
export interface IMailSenderBuilder {
|
export interface IMailSenderBuilder {
|
||||||
buildEmail(options: EmailNotifierConfiguration): IMailSender;
|
buildEmail(options: EmailNotifierConfiguration): IMailSender;
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
|
|
||||||
import { MailSenderBuilder } from "../../src/lib/notifiers/MailSenderBuilder";
|
import { MailSenderBuilder } from ".//MailSenderBuilder";
|
||||||
import Nodemailer = require("nodemailer");
|
import Nodemailer = require("nodemailer");
|
||||||
import Sinon = require("sinon");
|
import Sinon = require("sinon");
|
||||||
import Assert = require("assert");
|
import Assert = require("assert");
|
||||||
|
|
||||||
describe("test MailSenderBuilder", function() {
|
describe("notifiers/MailSenderBuilder", function() {
|
||||||
let createTransportStub: Sinon.SinonStub;
|
let createTransportStub: Sinon.SinonStub;
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
createTransportStub = Sinon.stub(Nodemailer, "createTransport");
|
createTransportStub = Sinon.stub(Nodemailer, "createTransport");
|
|
@ -3,7 +3,7 @@ import { IMailSenderBuilder } from "./IMailSenderBuilder";
|
||||||
import { MailSender } from "./MailSender";
|
import { MailSender } from "./MailSender";
|
||||||
import Nodemailer = require("nodemailer");
|
import Nodemailer = require("nodemailer");
|
||||||
import NodemailerSmtpTransport = require("nodemailer-smtp-transport");
|
import NodemailerSmtpTransport = require("nodemailer-smtp-transport");
|
||||||
import { SmtpNotifierConfiguration, EmailNotifierConfiguration } from "../configuration/Configuration";
|
import { SmtpNotifierConfiguration, EmailNotifierConfiguration } from "../configuration/schema/NotifierConfiguration";
|
||||||
|
|
||||||
export class MailSenderBuilder implements IMailSenderBuilder {
|
export class MailSenderBuilder implements IMailSenderBuilder {
|
||||||
private nodemailer: typeof Nodemailer;
|
private nodemailer: typeof Nodemailer;
|
||||||
|
|
|
@ -3,7 +3,7 @@ import BluebirdPromise = require("bluebird");
|
||||||
import Nodemailer = require("nodemailer");
|
import Nodemailer = require("nodemailer");
|
||||||
import Sinon = require("sinon");
|
import Sinon = require("sinon");
|
||||||
import { IMailSender } from "../../../src/lib/notifiers/IMailSender";
|
import { IMailSender } from "../../../src/lib/notifiers/IMailSender";
|
||||||
import { SmtpNotifierConfiguration, EmailNotifierConfiguration } from "../../../src/lib/configuration/Configuration";
|
import { SmtpNotifierConfiguration, EmailNotifierConfiguration } from "../../../src/lib/configuration/schema/NotifierConfiguration";
|
||||||
|
|
||||||
export class MailSenderBuilderStub implements IMailSenderBuilder {
|
export class MailSenderBuilderStub implements IMailSenderBuilder {
|
||||||
buildEmailStub: Sinon.SinonStub;
|
buildEmailStub: Sinon.SinonStub;
|
|
@ -3,13 +3,13 @@ import * as sinon from "sinon";
|
||||||
import * as BluebirdPromise from "bluebird";
|
import * as BluebirdPromise from "bluebird";
|
||||||
import * as assert from "assert";
|
import * as assert from "assert";
|
||||||
|
|
||||||
import { NotifierFactory } from "../../src/lib/notifiers/NotifierFactory";
|
import { NotifierFactory } from "./NotifierFactory";
|
||||||
import { EMailNotifier } from "../../src/lib/notifiers/EMailNotifier";
|
import { EmailNotifier } from "./EmailNotifier";
|
||||||
import { SmtpNotifier } from "../../src/lib/notifiers/SmtpNotifier";
|
import { SmtpNotifier } from "./SmtpNotifier";
|
||||||
import { MailSenderBuilderStub } from "../mocks/notifiers/MailSenderBuilderStub";
|
import { MailSenderBuilderStub } from "./MailSenderBuilderStub.spec";
|
||||||
|
|
||||||
|
|
||||||
describe("test notifier factory", function () {
|
describe("notifiers/NotifierFactory", function () {
|
||||||
let mailSenderBuilderStub: MailSenderBuilderStub;
|
let mailSenderBuilderStub: MailSenderBuilderStub;
|
||||||
it("should build a Email Notifier", function () {
|
it("should build a Email Notifier", function () {
|
||||||
const options = {
|
const options = {
|
||||||
|
@ -21,7 +21,7 @@ describe("test notifier factory", function () {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
mailSenderBuilderStub = new MailSenderBuilderStub();
|
mailSenderBuilderStub = new MailSenderBuilderStub();
|
||||||
assert(NotifierFactory.build(options, mailSenderBuilderStub) instanceof EMailNotifier);
|
assert(NotifierFactory.build(options, mailSenderBuilderStub) instanceof EmailNotifier);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should build a SMTP Notifier", function () {
|
it("should build a SMTP Notifier", function () {
|
|
@ -1,10 +1,10 @@
|
||||||
|
|
||||||
import { NotifierConfiguration } from "../configuration/Configuration";
|
import { NotifierConfiguration } from "../configuration/schema/NotifierConfiguration";
|
||||||
import Nodemailer = require("nodemailer");
|
import Nodemailer = require("nodemailer");
|
||||||
import { INotifier } from "./INotifier";
|
import { INotifier } from "./INotifier";
|
||||||
|
|
||||||
import { FileSystemNotifier } from "./FileSystemNotifier";
|
import { FileSystemNotifier } from "./FileSystemNotifier";
|
||||||
import { EMailNotifier } from "./EMailNotifier";
|
import { EmailNotifier } from "./EmailNotifier";
|
||||||
import { SmtpNotifier } from "./SmtpNotifier";
|
import { SmtpNotifier } from "./SmtpNotifier";
|
||||||
import { IMailSender } from "./IMailSender";
|
import { IMailSender } from "./IMailSender";
|
||||||
import { IMailSenderBuilder } from "./IMailSenderBuilder";
|
import { IMailSenderBuilder } from "./IMailSenderBuilder";
|
||||||
|
@ -13,7 +13,7 @@ export class NotifierFactory {
|
||||||
static build(options: NotifierConfiguration, mailSenderBuilder: IMailSenderBuilder): INotifier {
|
static build(options: NotifierConfiguration, mailSenderBuilder: IMailSenderBuilder): INotifier {
|
||||||
if ("email" in options) {
|
if ("email" in options) {
|
||||||
const mailSender = mailSenderBuilder.buildEmail(options.email);
|
const mailSender = mailSenderBuilder.buildEmail(options.email);
|
||||||
return new EMailNotifier(options.email, mailSender);
|
return new EmailNotifier(options.email, mailSender);
|
||||||
}
|
}
|
||||||
else if ("smtp" in options) {
|
else if ("smtp" in options) {
|
||||||
const mailSender = mailSenderBuilder.buildSmtp(options.smtp);
|
const mailSender = mailSenderBuilder.buildSmtp(options.smtp);
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import Sinon = require("sinon");
|
import Sinon = require("sinon");
|
||||||
import BluebirdPromise = require("bluebird");
|
import BluebirdPromise = require("bluebird");
|
||||||
|
|
||||||
import { INotifier } from "../../src/lib/notifiers/INotifier";
|
import { INotifier } from "./INotifier";
|
||||||
|
|
||||||
export class NotifierStub implements INotifier {
|
export class NotifierStub implements INotifier {
|
||||||
notifyStub: Sinon.SinonStub;
|
notifyStub: Sinon.SinonStub;
|
|
@ -4,7 +4,7 @@ import * as BluebirdPromise from "bluebird";
|
||||||
|
|
||||||
import { IMailSender } from "./IMailSender";
|
import { IMailSender } from "./IMailSender";
|
||||||
import { AbstractEmailNotifier } from "../notifiers/AbstractEmailNotifier";
|
import { AbstractEmailNotifier } from "../notifiers/AbstractEmailNotifier";
|
||||||
import { SmtpNotifierConfiguration } from "../configuration/Configuration";
|
import { SmtpNotifierConfiguration } from "../configuration/schema/NotifierConfiguration";
|
||||||
|
|
||||||
export class SmtpNotifier extends AbstractEmailNotifier {
|
export class SmtpNotifier extends AbstractEmailNotifier {
|
||||||
private mailSender: IMailSender;
|
private mailSender: IMailSender;
|
||||||
|
|
|
@ -3,12 +3,12 @@ import Sinon = require("sinon");
|
||||||
import BluebirdPromise = require("bluebird");
|
import BluebirdPromise = require("bluebird");
|
||||||
import Assert = require("assert");
|
import Assert = require("assert");
|
||||||
|
|
||||||
import { Regulator } from "../../src/lib/regulation/Regulator";
|
import { Regulator } from "./Regulator";
|
||||||
import MockDate = require("mockdate");
|
import MockDate = require("mockdate");
|
||||||
import exceptions = require("../../src/lib/Exceptions");
|
import exceptions = require("../Exceptions");
|
||||||
import { UserDataStoreStub } from "../mocks/storage/UserDataStoreStub";
|
import { UserDataStoreStub } from "../storage/UserDataStoreStub.spec";
|
||||||
|
|
||||||
describe("test authentication regulator", function () {
|
describe("regulation/Regulator", function () {
|
||||||
const USER1 = "USER1";
|
const USER1 = "USER1";
|
||||||
const USER2 = "USER2";
|
const USER2 = "USER2";
|
||||||
let userDataStoreStub: UserDataStoreStub;
|
let userDataStoreStub: UserDataStoreStub;
|
|
@ -0,0 +1,22 @@
|
||||||
|
import Bluebird = require("bluebird");
|
||||||
|
import Sinon = require("sinon");
|
||||||
|
import { IRegulator } from "./IRegulator";
|
||||||
|
|
||||||
|
|
||||||
|
export class RegulatorStub implements IRegulator {
|
||||||
|
markStub: Sinon.SinonStub;
|
||||||
|
regulateStub: Sinon.SinonStub;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.markStub = Sinon.stub();
|
||||||
|
this.regulateStub = Sinon.stub();
|
||||||
|
}
|
||||||
|
|
||||||
|
mark(userId: string, isAuthenticationSuccessful: boolean): Bluebird<void> {
|
||||||
|
return this.markStub(userId, isAuthenticationSuccessful);
|
||||||
|
}
|
||||||
|
|
||||||
|
regulate(userId: string): Bluebird<void> {
|
||||||
|
return this.regulateStub(userId);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,12 +1,12 @@
|
||||||
import Sinon = require("sinon");
|
import Sinon = require("sinon");
|
||||||
import Express = require("express");
|
import Express = require("express");
|
||||||
import Assert = require("assert");
|
import Assert = require("assert");
|
||||||
import Get401 from "../../../../src/lib/routes/error/401/get";
|
import Get401 from "./get";
|
||||||
import { ServerVariables } from "../../../../src/lib/ServerVariables";
|
import { ServerVariables } from "../../../ServerVariables";
|
||||||
import { ServerVariablesMockBuilder, ServerVariablesMock }
|
import { ServerVariablesMockBuilder, ServerVariablesMock }
|
||||||
from "../../../mocks/ServerVariablesMockBuilder";
|
from "../../../ServerVariablesMockBuilder.spec";
|
||||||
|
|
||||||
describe("Server error 401", function () {
|
describe("routes/error/401/get", function () {
|
||||||
let vars: ServerVariables;
|
let vars: ServerVariables;
|
||||||
let mocks: ServerVariablesMock;
|
let mocks: ServerVariablesMock;
|
||||||
let req: any;
|
let req: any;
|
|
@ -1,12 +1,12 @@
|
||||||
import Sinon = require("sinon");
|
import Sinon = require("sinon");
|
||||||
import Express = require("express");
|
import Express = require("express");
|
||||||
import Assert = require("assert");
|
import Assert = require("assert");
|
||||||
import Get403 from "../../../../src/lib/routes/error/403/get";
|
import Get403 from "./get";
|
||||||
import { ServerVariables } from "../../../../src/lib/ServerVariables";
|
import { ServerVariables } from "../../../ServerVariables";
|
||||||
import { ServerVariablesMockBuilder, ServerVariablesMock }
|
import { ServerVariablesMockBuilder, ServerVariablesMock }
|
||||||
from "../../../mocks/ServerVariablesMockBuilder";
|
from "../../../ServerVariablesMockBuilder.spec";
|
||||||
|
|
||||||
describe("Server error 403", function () {
|
describe("routes/error/403/get", function () {
|
||||||
let vars: ServerVariables;
|
let vars: ServerVariables;
|
||||||
let mocks: ServerVariablesMock;
|
let mocks: ServerVariablesMock;
|
||||||
let req: any;
|
let req: any;
|
|
@ -1,9 +1,9 @@
|
||||||
import Sinon = require("sinon");
|
import Sinon = require("sinon");
|
||||||
import Express = require("express");
|
import Express = require("express");
|
||||||
import Assert = require("assert");
|
import Assert = require("assert");
|
||||||
import Get404 from "../../../../src/lib/routes/error/404/get";
|
import Get404 from "./get";
|
||||||
|
|
||||||
describe("Server error 404", function () {
|
describe("routes/error/404/get", function () {
|
||||||
it("should render the page", function () {
|
it("should render the page", function () {
|
||||||
const req = {} as Express.Request;
|
const req = {} as Express.Request;
|
||||||
const res = {
|
const res = {
|
|
@ -2,18 +2,18 @@
|
||||||
import Sinon = require("sinon");
|
import Sinon = require("sinon");
|
||||||
import BluebirdPromise = require("bluebird");
|
import BluebirdPromise = require("bluebird");
|
||||||
import Assert = require("assert");
|
import Assert = require("assert");
|
||||||
import FirstFactorPost = require("../../../src/lib/routes/firstfactor/post");
|
import FirstFactorPost = require("./post");
|
||||||
import exceptions = require("../../../src/lib/Exceptions");
|
import exceptions = require("../../Exceptions");
|
||||||
import { AuthenticationSessionHandler } from "../../../src/lib/AuthenticationSessionHandler";
|
import { AuthenticationSessionHandler } from "../../AuthenticationSessionHandler";
|
||||||
import { AuthenticationSession } from "../../../types/AuthenticationSession";
|
import { AuthenticationSession } from "../../../../types/AuthenticationSession";
|
||||||
import Endpoints = require("../../../../shared/api");
|
import Endpoints = require("../../../../../shared/api");
|
||||||
import AuthenticationRegulatorMock = require("../../mocks/AuthenticationRegulator");
|
import AuthenticationRegulatorMock = require("../../regulation/RegulatorStub.spec");
|
||||||
import { AccessControllerStub } from "../../mocks/AccessControllerStub";
|
import { AccessControllerStub } from "../../access_control/AccessControllerStub.spec";
|
||||||
import ExpressMock = require("../../mocks/express");
|
import ExpressMock = require("../../stubs/express.spec");
|
||||||
import { ServerVariablesMock, ServerVariablesMockBuilder } from "../../mocks/ServerVariablesMockBuilder";
|
import { ServerVariablesMock, ServerVariablesMockBuilder } from "../../ServerVariablesMockBuilder.spec";
|
||||||
import { ServerVariables } from "../../../src/lib/ServerVariables";
|
import { ServerVariables } from "../../ServerVariables";
|
||||||
|
|
||||||
describe("test the first factor validation route", function () {
|
describe("routes/firstfactor/post", function () {
|
||||||
let req: ExpressMock.RequestMock;
|
let req: ExpressMock.RequestMock;
|
||||||
let res: ExpressMock.ResponseMock;
|
let res: ExpressMock.ResponseMock;
|
||||||
let emails: string[];
|
let emails: string[];
|
|
@ -1,17 +1,17 @@
|
||||||
|
|
||||||
import PasswordResetFormPost = require("../../../src/lib/routes/password-reset/form/post");
|
import PasswordResetFormPost = require("./post");
|
||||||
import { PasswordUpdater } from "../../../src/lib/ldap/PasswordUpdater";
|
import { PasswordUpdater } from "../../../ldap/PasswordUpdater";
|
||||||
import { AuthenticationSessionHandler } from "../../../src/lib/AuthenticationSessionHandler";
|
import { AuthenticationSessionHandler } from "../../../AuthenticationSessionHandler";
|
||||||
import { AuthenticationSession } from "../../../types/AuthenticationSession";
|
import { AuthenticationSession } from "../../../../../types/AuthenticationSession";
|
||||||
import { UserDataStore } from "../../../src/lib/storage/UserDataStore";
|
import { UserDataStore } from "../../../storage/UserDataStore";
|
||||||
import Sinon = require("sinon");
|
import Sinon = require("sinon");
|
||||||
import Assert = require("assert");
|
import Assert = require("assert");
|
||||||
import BluebirdPromise = require("bluebird");
|
import BluebirdPromise = require("bluebird");
|
||||||
import ExpressMock = require("../../mocks/express");
|
import ExpressMock = require("../../../stubs/express.spec");
|
||||||
import { ServerVariablesMock, ServerVariablesMockBuilder } from "../../mocks/ServerVariablesMockBuilder";
|
import { ServerVariablesMock, ServerVariablesMockBuilder } from "../../../ServerVariablesMockBuilder.spec";
|
||||||
import { ServerVariables } from "../../../src/lib/ServerVariables";
|
import { ServerVariables } from "../../../ServerVariables";
|
||||||
|
|
||||||
describe("test reset password route", function () {
|
describe("routes/password-reset/form/post", function () {
|
||||||
let req: ExpressMock.RequestMock;
|
let req: ExpressMock.RequestMock;
|
||||||
let res: ExpressMock.ResponseMock;
|
let res: ExpressMock.ResponseMock;
|
||||||
let vars: ServerVariables;
|
let vars: ServerVariables;
|
||||||
|
@ -48,8 +48,9 @@ describe("test reset password route", function () {
|
||||||
mail_attribute: "mail",
|
mail_attribute: "mail",
|
||||||
user: "user",
|
user: "user",
|
||||||
password: "password",
|
password: "password",
|
||||||
users_dn: "ou=users,dc=example,dc=com",
|
additional_users_dn: "ou=users",
|
||||||
groups_dn: "ou=groups,dc=example,dc=com",
|
additional_groups_dn: "ou=groups",
|
||||||
|
base_dn: "dc=example,dc=com",
|
||||||
users_filter: "user",
|
users_filter: "user",
|
||||||
group_name_attribute: "cn",
|
group_name_attribute: "cn",
|
||||||
groups_filter: "groups"
|
groups_filter: "groups"
|
|
@ -1,18 +1,18 @@
|
||||||
|
|
||||||
import PasswordResetHandler
|
import PasswordResetHandler
|
||||||
from "../../../../src/lib/routes/password-reset/identity/PasswordResetHandler";
|
from "./PasswordResetHandler";
|
||||||
import PasswordUpdater = require("../../../../src/lib/ldap/PasswordUpdater");
|
import PasswordUpdater = require("../../../ldap/PasswordUpdater");
|
||||||
import { UserDataStore } from "../../../../src/lib/storage/UserDataStore";
|
import { UserDataStore } from "../../../storage/UserDataStore";
|
||||||
import Sinon = require("sinon");
|
import Sinon = require("sinon");
|
||||||
import winston = require("winston");
|
import winston = require("winston");
|
||||||
import assert = require("assert");
|
import assert = require("assert");
|
||||||
import BluebirdPromise = require("bluebird");
|
import BluebirdPromise = require("bluebird");
|
||||||
import ExpressMock = require("../../../mocks/express");
|
import ExpressMock = require("../../../stubs/express.spec");
|
||||||
import { ServerVariablesMock, ServerVariablesMockBuilder }
|
import { ServerVariablesMock, ServerVariablesMockBuilder }
|
||||||
from "../../../mocks/ServerVariablesMockBuilder";
|
from "../../../ServerVariablesMockBuilder.spec";
|
||||||
import { ServerVariables } from "../../../../src/lib/ServerVariables";
|
import { ServerVariables } from "../../../ServerVariables";
|
||||||
|
|
||||||
describe("test reset password identity check", function () {
|
describe("routes/password-reset/identity/PasswordResetHandler", function () {
|
||||||
let req: ExpressMock.RequestMock;
|
let req: ExpressMock.RequestMock;
|
||||||
let res: ExpressMock.ResponseMock;
|
let res: ExpressMock.ResponseMock;
|
||||||
let mocks: ServerVariablesMock;
|
let mocks: ServerVariablesMock;
|
|
@ -4,7 +4,7 @@ import objectPath = require("object-path");
|
||||||
|
|
||||||
import exceptions = require("../../../Exceptions");
|
import exceptions = require("../../../Exceptions");
|
||||||
import { Identity } from "../../../../../types/Identity";
|
import { Identity } from "../../../../../types/Identity";
|
||||||
import { IdentityValidable } from "../../../IdentityCheckMiddleware";
|
import { IdentityValidable } from "../../../IdentityValidable";
|
||||||
import { PRE_VALIDATION_TEMPLATE } from "../../../IdentityCheckPreValidationTemplate";
|
import { PRE_VALIDATION_TEMPLATE } from "../../../IdentityCheckPreValidationTemplate";
|
||||||
import Constants = require("../constants");
|
import Constants = require("../constants");
|
||||||
import { IRequestLogger } from "../../../logging/IRequestLogger";
|
import { IRequestLogger } from "../../../logging/IRequestLogger";
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
import SecondFactorGet from "../../../src/lib/routes/secondfactor/get";
|
import SecondFactorGet from "./get";
|
||||||
import { ServerVariablesMockBuilder, ServerVariablesMock }
|
import { ServerVariablesMockBuilder, ServerVariablesMock }
|
||||||
from "../../mocks/ServerVariablesMockBuilder";
|
from "../../ServerVariablesMockBuilder.spec";
|
||||||
import { ServerVariables } from "../../../src/lib/ServerVariables";
|
import { ServerVariables } from "../../ServerVariables";
|
||||||
import Sinon = require("sinon");
|
import Sinon = require("sinon");
|
||||||
import ExpressMock = require("../../mocks/express");
|
import ExpressMock = require("../../stubs/express.spec");
|
||||||
import Assert = require("assert");
|
import Assert = require("assert");
|
||||||
import Endpoints = require("../../../../shared/api");
|
import Endpoints = require("../../../../../shared/api");
|
||||||
import BluebirdPromise = require("bluebird");
|
import BluebirdPromise = require("bluebird");
|
||||||
|
|
||||||
describe("test second factor GET endpoint handler", function () {
|
describe("routes/secondfactor/get", function () {
|
||||||
let mocks: ServerVariablesMock;
|
let mocks: ServerVariablesMock;
|
||||||
let vars: ServerVariables;
|
let vars: ServerVariables;
|
||||||
let req: ExpressMock.RequestMock;
|
let req: ExpressMock.RequestMock;
|
|
@ -1,11 +1,11 @@
|
||||||
import Redirect from "../../../src/lib/routes/secondfactor/redirect";
|
import Redirect from "./redirect";
|
||||||
import ExpressMock = require("../../mocks/express");
|
import ExpressMock = require("../../stubs/express.spec");
|
||||||
import { ServerVariablesMockBuilder, ServerVariablesMock }
|
import { ServerVariablesMockBuilder, ServerVariablesMock }
|
||||||
from "../../mocks/ServerVariablesMockBuilder";
|
from "../../ServerVariablesMockBuilder.spec";
|
||||||
import { ServerVariables } from "../../../src/lib/ServerVariables";
|
import { ServerVariables } from "../../ServerVariables";
|
||||||
import Assert = require("assert");
|
import Assert = require("assert");
|
||||||
|
|
||||||
describe("test second factor redirect", function() {
|
describe("routes/secondfactor/redirect", function() {
|
||||||
let req: ExpressMock.RequestMock;
|
let req: ExpressMock.RequestMock;
|
||||||
let res: ExpressMock.ResponseMock;
|
let res: ExpressMock.ResponseMock;
|
||||||
let mocks: ServerVariablesMock;
|
let mocks: ServerVariablesMock;
|
|
@ -1,15 +1,15 @@
|
||||||
import Sinon = require("sinon");
|
import Sinon = require("sinon");
|
||||||
import RegistrationHandler from "../../../../../src/lib/routes/secondfactor/totp/identity/RegistrationHandler";
|
import RegistrationHandler from "./RegistrationHandler";
|
||||||
import { Identity } from "../../../../../types/Identity";
|
import { Identity } from "../../../../../../types/Identity";
|
||||||
import { UserDataStore } from "../../../../../src/lib/storage/UserDataStore";
|
import { UserDataStore } from "../../../../storage/UserDataStore";
|
||||||
import BluebirdPromise = require("bluebird");
|
import BluebirdPromise = require("bluebird");
|
||||||
import ExpressMock = require("../../../../mocks/express");
|
import ExpressMock = require("../../../../stubs/express.spec");
|
||||||
import { ServerVariablesMock, ServerVariablesMockBuilder }
|
import { ServerVariablesMock, ServerVariablesMockBuilder }
|
||||||
from "../../../../mocks/ServerVariablesMockBuilder";
|
from "../../../../ServerVariablesMockBuilder.spec";
|
||||||
import { ServerVariables } from "../../../../../src/lib/ServerVariables";
|
import { ServerVariables } from "../../../../ServerVariables";
|
||||||
import Assert = require("assert");
|
import Assert = require("assert");
|
||||||
|
|
||||||
describe("test totp register", function () {
|
describe("routes/secondfactor/totp/identity/RegistrationHandler", function () {
|
||||||
let req: ExpressMock.RequestMock;
|
let req: ExpressMock.RequestMock;
|
||||||
let res: ExpressMock.ResponseMock;
|
let res: ExpressMock.ResponseMock;
|
||||||
let mocks: ServerVariablesMock;
|
let mocks: ServerVariablesMock;
|
|
@ -4,7 +4,7 @@ import BluebirdPromise = require("bluebird");
|
||||||
import objectPath = require("object-path");
|
import objectPath = require("object-path");
|
||||||
|
|
||||||
import { Identity } from "../../../../../../types/Identity";
|
import { Identity } from "../../../../../../types/Identity";
|
||||||
import { IdentityValidable } from "../../../../IdentityCheckMiddleware";
|
import { IdentityValidable } from "../../../../IdentityValidable";
|
||||||
import { PRE_VALIDATION_TEMPLATE } from "../../../../IdentityCheckPreValidationTemplate";
|
import { PRE_VALIDATION_TEMPLATE } from "../../../../IdentityCheckPreValidationTemplate";
|
||||||
import Constants = require("../constants");
|
import Constants = require("../constants");
|
||||||
import Endpoints = require("../../../../../../../shared/api");
|
import Endpoints = require("../../../../../../../shared/api");
|
||||||
|
@ -16,18 +16,18 @@ import { IRequestLogger } from "../../../../logging/IRequestLogger";
|
||||||
import { IUserDataStore } from "../../../../storage/IUserDataStore";
|
import { IUserDataStore } from "../../../../storage/IUserDataStore";
|
||||||
import { ITotpHandler } from "../../../../authentication/totp/ITotpHandler";
|
import { ITotpHandler } from "../../../../authentication/totp/ITotpHandler";
|
||||||
import { TOTPSecret } from "../../../../../../types/TOTPSecret";
|
import { TOTPSecret } from "../../../../../../types/TOTPSecret";
|
||||||
import { TOTPConfiguration } from "../../../../configuration/Configuration";
|
import { TotpConfiguration } from "../../../../configuration/schema/TotpConfiguration";
|
||||||
|
|
||||||
|
|
||||||
export default class RegistrationHandler implements IdentityValidable {
|
export default class RegistrationHandler implements IdentityValidable {
|
||||||
private logger: IRequestLogger;
|
private logger: IRequestLogger;
|
||||||
private userDataStore: IUserDataStore;
|
private userDataStore: IUserDataStore;
|
||||||
private totp: ITotpHandler;
|
private totp: ITotpHandler;
|
||||||
private configuration: TOTPConfiguration;
|
private configuration: TotpConfiguration;
|
||||||
|
|
||||||
constructor(logger: IRequestLogger,
|
constructor(logger: IRequestLogger,
|
||||||
userDataStore: IUserDataStore,
|
userDataStore: IUserDataStore,
|
||||||
totp: ITotpHandler, configuration: TOTPConfiguration) {
|
totp: ITotpHandler, configuration: TotpConfiguration) {
|
||||||
this.logger = logger;
|
this.logger = logger;
|
||||||
this.userDataStore = userDataStore;
|
this.userDataStore = userDataStore;
|
||||||
this.totp = totp;
|
this.totp = totp;
|
||||||
|
|
|
@ -2,17 +2,17 @@
|
||||||
import BluebirdPromise = require("bluebird");
|
import BluebirdPromise = require("bluebird");
|
||||||
import Sinon = require("sinon");
|
import Sinon = require("sinon");
|
||||||
import Assert = require("assert");
|
import Assert = require("assert");
|
||||||
import Exceptions = require("../../../../../src/lib/Exceptions");
|
import Exceptions = require("../../../../Exceptions");
|
||||||
import { AuthenticationSessionHandler } from "../../../../../src/lib/AuthenticationSessionHandler";
|
import { AuthenticationSessionHandler } from "../../../../AuthenticationSessionHandler";
|
||||||
import { AuthenticationSession } from "../../../../../types/AuthenticationSession";
|
import { AuthenticationSession } from "../../../../../../types/AuthenticationSession";
|
||||||
import SignPost = require("../../../../../src/lib/routes/secondfactor/totp/sign/post");
|
import SignPost = require("./post");
|
||||||
import { ServerVariables } from "../../../../../src/lib/ServerVariables";
|
import { ServerVariables } from "../../../../ServerVariables";
|
||||||
|
|
||||||
import ExpressMock = require("../../../../mocks/express");
|
import ExpressMock = require("../../../../stubs/express.spec");
|
||||||
import { UserDataStoreStub } from "../../../../mocks/storage/UserDataStoreStub";
|
import { UserDataStoreStub } from "../../../../storage/UserDataStoreStub.spec";
|
||||||
import { ServerVariablesMock, ServerVariablesMockBuilder } from "../../../../mocks/ServerVariablesMockBuilder";
|
import { ServerVariablesMock, ServerVariablesMockBuilder } from "../../../../ServerVariablesMockBuilder.spec";
|
||||||
|
|
||||||
describe("test totp route", function () {
|
describe("routes/secondfactor/totp/sign/post", function () {
|
||||||
let req: ExpressMock.RequestMock;
|
let req: ExpressMock.RequestMock;
|
||||||
let res: ExpressMock.ResponseMock;
|
let res: ExpressMock.ResponseMock;
|
||||||
let authSession: AuthenticationSession;
|
let authSession: AuthenticationSession;
|
|
@ -1,11 +1,9 @@
|
||||||
|
import Bluebird = require("bluebird");
|
||||||
|
import Express = require("express");
|
||||||
|
|
||||||
import exceptions = require("../../../../Exceptions");
|
|
||||||
import objectPath = require("object-path");
|
|
||||||
import express = require("express");
|
|
||||||
import { TOTPSecretDocument } from "../../../../storage/TOTPSecretDocument";
|
import { TOTPSecretDocument } from "../../../../storage/TOTPSecretDocument";
|
||||||
import BluebirdPromise = require("bluebird");
|
|
||||||
import Endpoints = require("../../../../../../../shared/api");
|
import Endpoints = require("../../../../../../../shared/api");
|
||||||
import redirect from "../../redirect";
|
import Redirect from "../../redirect";
|
||||||
import ErrorReplies = require("../../../../ErrorReplies");
|
import ErrorReplies = require("../../../../ErrorReplies");
|
||||||
import { AuthenticationSessionHandler } from "../../../../AuthenticationSessionHandler";
|
import { AuthenticationSessionHandler } from "../../../../AuthenticationSessionHandler";
|
||||||
import { AuthenticationSession } from "../../../../../../types/AuthenticationSession";
|
import { AuthenticationSession } from "../../../../../../types/AuthenticationSession";
|
||||||
|
@ -15,11 +13,11 @@ import { ServerVariables } from "../../../../ServerVariables";
|
||||||
const UNAUTHORIZED_MESSAGE = "Unauthorized access";
|
const UNAUTHORIZED_MESSAGE = "Unauthorized access";
|
||||||
|
|
||||||
export default function (vars: ServerVariables) {
|
export default function (vars: ServerVariables) {
|
||||||
function handler(req: express.Request, res: express.Response): BluebirdPromise<void> {
|
function handler(req: Express.Request, res: Express.Response): Bluebird<void> {
|
||||||
let authSession: AuthenticationSession;
|
let authSession: AuthenticationSession;
|
||||||
const token = req.body.token;
|
const token = req.body.token;
|
||||||
|
|
||||||
return new BluebirdPromise(function (resolve, reject) {
|
return new Bluebird(function (resolve, reject) {
|
||||||
authSession = AuthenticationSessionHandler.get(req, vars.logger);
|
authSession = AuthenticationSessionHandler.get(req, vars.logger);
|
||||||
vars.logger.info(req, "Initiate TOTP validation for user \"%s\".", authSession.userid);
|
vars.logger.info(req, "Initiate TOTP validation for user \"%s\".", authSession.userid);
|
||||||
resolve();
|
resolve();
|
||||||
|
@ -29,12 +27,12 @@ export default function (vars: ServerVariables) {
|
||||||
})
|
})
|
||||||
.then(function (doc: TOTPSecretDocument) {
|
.then(function (doc: TOTPSecretDocument) {
|
||||||
if (!vars.totpHandler.validate(token, doc.secret.base32))
|
if (!vars.totpHandler.validate(token, doc.secret.base32))
|
||||||
return BluebirdPromise.reject(new Error("Invalid TOTP token."));
|
return Bluebird.reject(new Error("Invalid TOTP token."));
|
||||||
|
|
||||||
vars.logger.debug(req, "TOTP validation succeeded.");
|
vars.logger.debug(req, "TOTP validation succeeded.");
|
||||||
authSession.second_factor = true;
|
authSession.second_factor = true;
|
||||||
redirect(vars)(req, res);
|
Redirect(vars)(req, res);
|
||||||
return BluebirdPromise.resolve();
|
return Bluebird.resolve();
|
||||||
})
|
})
|
||||||
.catch(ErrorReplies.replyWithError200(req, res, vars.logger,
|
.catch(ErrorReplies.replyWithError200(req, res, vars.logger,
|
||||||
UserMessages.OPERATION_FAILED));
|
UserMessages.OPERATION_FAILED));
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue