Add logs to detect redis connection issues earlier
Before this fix, the application was simply crashing during execution when connection to redis was failing. Now, it is correctly handled with failing promises and logs have been enabled to clearly see the problempull/89/head
parent
36962cfc2c
commit
0a33b2d5ee
|
@ -112,7 +112,7 @@ module.exports = function (grunt) {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
client: {
|
client: {
|
||||||
files: ['src/client/**/*.ts', 'test/client/**/*.ts'],
|
files: ['src/client/**/*.ts'],
|
||||||
tasks: ['build-dev'],
|
tasks: ['build-dev'],
|
||||||
options: {
|
options: {
|
||||||
interrupt: true,
|
interrupt: true,
|
||||||
|
@ -120,7 +120,7 @@ module.exports = function (grunt) {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
server: {
|
server: {
|
||||||
files: ['src/server/**/*.ts', 'test/server/**/*.ts'],
|
files: ['src/server/**/*.ts'],
|
||||||
tasks: ['build-dev', 'run:docker-restart', 'run:make-dev-views' ],
|
tasks: ['build-dev', 'run:docker-restart', 'run:make-dev-views' ],
|
||||||
options: {
|
options: {
|
||||||
interrupt: true,
|
interrupt: true,
|
||||||
|
|
|
@ -2,5 +2,7 @@ version: '2'
|
||||||
services:
|
services:
|
||||||
mongo:
|
mongo:
|
||||||
image: mongo:3.4
|
image: mongo:3.4
|
||||||
|
ports:
|
||||||
|
- "27017:27017"
|
||||||
networks:
|
networks:
|
||||||
- example-network
|
- example-network
|
||||||
|
|
|
@ -37,6 +37,7 @@
|
||||||
"object-path": "^0.11.3",
|
"object-path": "^0.11.3",
|
||||||
"pug": "^2.0.0-rc.2",
|
"pug": "^2.0.0-rc.2",
|
||||||
"randomstring": "^1.1.5",
|
"randomstring": "^1.1.5",
|
||||||
|
"redis": "^2.8.0",
|
||||||
"speakeasy": "^2.0.0",
|
"speakeasy": "^2.0.0",
|
||||||
"u2f": "^0.1.2",
|
"u2f": "^0.1.2",
|
||||||
"winston": "^2.3.1",
|
"winston": "^2.3.1",
|
||||||
|
@ -63,6 +64,7 @@
|
||||||
"@types/proxyquire": "^1.3.27",
|
"@types/proxyquire": "^1.3.27",
|
||||||
"@types/query-string": "^4.3.1",
|
"@types/query-string": "^4.3.1",
|
||||||
"@types/randomstring": "^1.1.5",
|
"@types/randomstring": "^1.1.5",
|
||||||
|
"@types/redis": "^2.6.0",
|
||||||
"@types/request": "0.0.46",
|
"@types/request": "0.0.46",
|
||||||
"@types/selenium-webdriver": "^3.0.4",
|
"@types/selenium-webdriver": "^3.0.4",
|
||||||
"@types/sinon": "^2.2.1",
|
"@types/sinon": "^2.2.1",
|
||||||
|
|
|
@ -11,52 +11,52 @@ import { QueryParametersRetriever } from "../QueryParametersRetriever";
|
||||||
|
|
||||||
|
|
||||||
export default function (window: Window, $: JQueryStatic, u2fApi: typeof U2fApi) {
|
export default function (window: Window, $: JQueryStatic, u2fApi: typeof U2fApi) {
|
||||||
const notifierTotp = new Notifier(".notification-totp", $);
|
const notifierTotp = new Notifier(".notification-totp", $);
|
||||||
const notifierU2f = new Notifier(".notification-u2f", $);
|
const notifierU2f = new Notifier(".notification-u2f", $);
|
||||||
|
|
||||||
function onAuthenticationSuccess(data: any) {
|
function onAuthenticationSuccess(data: any) {
|
||||||
const redirectUrl = QueryParametersRetriever.get("redirect");
|
const redirectUrl = QueryParametersRetriever.get("redirect");
|
||||||
if (redirectUrl)
|
if (redirectUrl)
|
||||||
window.location.href = redirectUrl;
|
window.location.href = redirectUrl;
|
||||||
else
|
else
|
||||||
window.location.href = Endpoints.FIRST_FACTOR_GET;
|
window.location.href = Endpoints.FIRST_FACTOR_GET;
|
||||||
}
|
}
|
||||||
|
|
||||||
function onSecondFactorTotpSuccess(data: any) {
|
function onSecondFactorTotpSuccess(data: any) {
|
||||||
onAuthenticationSuccess(data);
|
onAuthenticationSuccess(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
function onSecondFactorTotpFailure(err: Error) {
|
function onSecondFactorTotpFailure(err: Error) {
|
||||||
notifierTotp.error("Problem with TOTP validation.");
|
notifierTotp.error("Problem with TOTP validation.");
|
||||||
}
|
}
|
||||||
|
|
||||||
function onU2fAuthenticationSuccess(data: any) {
|
function onU2fAuthenticationSuccess(data: any) {
|
||||||
onAuthenticationSuccess(data);
|
onAuthenticationSuccess(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
function onU2fAuthenticationFailure() {
|
function onU2fAuthenticationFailure() {
|
||||||
notifierU2f.error("Problem with U2F validation. Did you register before authenticating?");
|
notifierU2f.error("Problem with U2F validation. Did you register before authenticating?");
|
||||||
}
|
}
|
||||||
|
|
||||||
function onTOTPFormSubmitted(): boolean {
|
function onTOTPFormSubmitted(): boolean {
|
||||||
const token = $(Constants.TOTP_TOKEN_SELECTOR).val();
|
const token = $(Constants.TOTP_TOKEN_SELECTOR).val();
|
||||||
jslogger.debug("TOTP token is %s", token);
|
jslogger.debug("TOTP token is %s", token);
|
||||||
|
|
||||||
TOTPValidator.validate(token, $)
|
TOTPValidator.validate(token, $)
|
||||||
.then(onSecondFactorTotpSuccess)
|
.then(onSecondFactorTotpSuccess)
|
||||||
.catch(onSecondFactorTotpFailure);
|
.catch(onSecondFactorTotpFailure);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
function onU2FFormSubmitted(): boolean {
|
function onU2FFormSubmitted(): boolean {
|
||||||
jslogger.debug("Start U2F authentication");
|
jslogger.debug("Start U2F authentication");
|
||||||
U2FValidator.validate($, notifierU2f, U2fApi)
|
U2FValidator.validate($, notifierU2f, U2fApi)
|
||||||
.then(onU2fAuthenticationSuccess, onU2fAuthenticationFailure);
|
.then(onU2fAuthenticationSuccess, onU2fAuthenticationFailure);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
$(window.document).ready(function () {
|
$(window.document).ready(function () {
|
||||||
$(Constants.TOTP_FORM_SELECTOR).on("submit", onTOTPFormSubmitted);
|
$(Constants.TOTP_FORM_SELECTOR).on("submit", onTOTPFormSubmitted);
|
||||||
$(Constants.U2F_FORM_SELECTOR).on("submit", onU2FFormSubmitted);
|
$(Constants.U2F_FORM_SELECTOR).on("submit", onU2FFormSubmitted);
|
||||||
});
|
});
|
||||||
}
|
}
|
|
@ -2,39 +2,54 @@
|
||||||
|
|
||||||
import express = require("express");
|
import express = require("express");
|
||||||
import U2f = require("u2f");
|
import U2f = require("u2f");
|
||||||
|
import { ServerVariablesHandler } from "./ServerVariablesHandler";
|
||||||
|
import BluebirdPromise = require("bluebird");
|
||||||
|
|
||||||
export interface AuthenticationSession {
|
export interface AuthenticationSession {
|
||||||
|
userid: string;
|
||||||
|
first_factor: boolean;
|
||||||
|
second_factor: boolean;
|
||||||
|
identity_check?: {
|
||||||
|
challenge: string;
|
||||||
userid: string;
|
userid: string;
|
||||||
first_factor: boolean;
|
};
|
||||||
second_factor: boolean;
|
register_request?: U2f.Request;
|
||||||
identity_check?: {
|
sign_request?: U2f.Request;
|
||||||
challenge: string;
|
email: string;
|
||||||
userid: string;
|
groups: string[];
|
||||||
};
|
redirect?: string;
|
||||||
register_request?: U2f.Request;
|
|
||||||
sign_request?: U2f.Request;
|
|
||||||
email: string;
|
|
||||||
groups: string[];
|
|
||||||
redirect?: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const INITIAL_AUTHENTICATION_SESSION: AuthenticationSession = {
|
||||||
|
first_factor: false,
|
||||||
|
second_factor: false,
|
||||||
|
userid: undefined,
|
||||||
|
email: undefined,
|
||||||
|
groups: [],
|
||||||
|
register_request: undefined,
|
||||||
|
sign_request: undefined,
|
||||||
|
identity_check: undefined,
|
||||||
|
redirect: undefined
|
||||||
|
};
|
||||||
|
|
||||||
export function reset(req: express.Request): void {
|
export function reset(req: express.Request): void {
|
||||||
const authSession: AuthenticationSession = {
|
const logger = ServerVariablesHandler.getLogger(req.app);
|
||||||
first_factor: false,
|
logger.debug("Authentication session %s is being reset.", req.sessionID);
|
||||||
second_factor: false,
|
req.session.auth = Object.assign({}, INITIAL_AUTHENTICATION_SESSION, {});
|
||||||
userid: undefined,
|
|
||||||
email: undefined,
|
|
||||||
groups: [],
|
|
||||||
register_request: undefined,
|
|
||||||
sign_request: undefined,
|
|
||||||
identity_check: undefined,
|
|
||||||
redirect: undefined
|
|
||||||
};
|
|
||||||
req.session.auth = authSession;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function get(req: express.Request): AuthenticationSession {
|
export function get(req: express.Request): BluebirdPromise<AuthenticationSession> {
|
||||||
if (!req.session.auth)
|
const logger = ServerVariablesHandler.getLogger(req.app);
|
||||||
reset(req);
|
if (!req.session) {
|
||||||
return req.session.auth;
|
const errorMsg = "Something is wrong with session cookies. Please check Redis is running and Authelia can contact it.";
|
||||||
|
logger.error(errorMsg);
|
||||||
|
return BluebirdPromise.reject(new Error(errorMsg));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!req.session.auth) {
|
||||||
|
logger.debug("Authentication session %s was undefined. Resetting.", req.sessionID);
|
||||||
|
reset(req);
|
||||||
|
}
|
||||||
|
|
||||||
|
return BluebirdPromise.resolve(req.session.auth);
|
||||||
}
|
}
|
|
@ -9,10 +9,11 @@ import AuthenticationSession = require("./AuthenticationSession");
|
||||||
export function validate(req: express.Request): BluebirdPromise<void> {
|
export function validate(req: express.Request): BluebirdPromise<void> {
|
||||||
return FirstFactorValidator.validate(req)
|
return FirstFactorValidator.validate(req)
|
||||||
.then(function () {
|
.then(function () {
|
||||||
const authSession = AuthenticationSession.get(req);
|
return AuthenticationSession.get(req);
|
||||||
|
})
|
||||||
|
.then(function (authSession: AuthenticationSession.AuthenticationSession) {
|
||||||
if (!authSession.second_factor)
|
if (!authSession.second_factor)
|
||||||
return BluebirdPromise.reject("No second factor variable");
|
return BluebirdPromise.reject("No second factor variable.");
|
||||||
|
|
||||||
return BluebirdPromise.resolve();
|
return BluebirdPromise.resolve();
|
||||||
});
|
});
|
||||||
}
|
}
|
|
@ -6,9 +6,11 @@ import Exceptions = require("./Exceptions");
|
||||||
import AuthenticationSession = require("./AuthenticationSession");
|
import AuthenticationSession = require("./AuthenticationSession");
|
||||||
|
|
||||||
export function validate(req: express.Request): BluebirdPromise<void> {
|
export function validate(req: express.Request): BluebirdPromise<void> {
|
||||||
const authSession = AuthenticationSession.get(req);
|
return AuthenticationSession.get(req)
|
||||||
if (!authSession.userid || !authSession.first_factor)
|
.then(function (authSession: AuthenticationSession.AuthenticationSession) {
|
||||||
return BluebirdPromise.reject(new Exceptions.FirstFactorValidationError("First factor has not been validated yet."));
|
if (!authSession.userid || !authSession.first_factor)
|
||||||
|
return BluebirdPromise.reject(new Exceptions.FirstFactorValidationError("First factor has not been validated yet."));
|
||||||
|
|
||||||
return BluebirdPromise.resolve();
|
return BluebirdPromise.resolve();
|
||||||
|
});
|
||||||
}
|
}
|
|
@ -10,7 +10,7 @@ import { IUserDataStore } from "./storage/IUserDataStore";
|
||||||
import { Winston } from "../../types/Dependencies";
|
import { Winston } from "../../types/Dependencies";
|
||||||
import express = require("express");
|
import express = require("express");
|
||||||
import ErrorReplies = require("./ErrorReplies");
|
import ErrorReplies = require("./ErrorReplies");
|
||||||
import { ServerVariablesHandler } from "./ServerVariablesHandler";
|
import { ServerVariablesHandler } from "./ServerVariablesHandler";
|
||||||
import AuthenticationSession = require("./AuthenticationSession");
|
import AuthenticationSession = require("./AuthenticationSession");
|
||||||
|
|
||||||
import Identity = require("../../types/Identity");
|
import Identity = require("../../types/Identity");
|
||||||
|
@ -66,7 +66,7 @@ export function get_finish_validation(handler: IdentityValidable): express.Reque
|
||||||
const logger = ServerVariablesHandler.getLogger(req.app);
|
const logger = ServerVariablesHandler.getLogger(req.app);
|
||||||
const userDataStore = ServerVariablesHandler.getUserDataStore(req.app);
|
const userDataStore = ServerVariablesHandler.getUserDataStore(req.app);
|
||||||
|
|
||||||
const authSession = AuthenticationSession.get(req);
|
let authSession: AuthenticationSession.AuthenticationSession;
|
||||||
const identityToken = objectPath.get<express.Request, string>(req, "query.identity_token");
|
const identityToken = objectPath.get<express.Request, string>(req, "query.identity_token");
|
||||||
logger.info("GET identity_check: identity token provided is %s", identityToken);
|
logger.info("GET identity_check: identity token provided is %s", identityToken);
|
||||||
|
|
||||||
|
@ -74,6 +74,12 @@ export function get_finish_validation(handler: IdentityValidable): express.Reque
|
||||||
.then(function () {
|
.then(function () {
|
||||||
return handler.postValidationInit(req);
|
return handler.postValidationInit(req);
|
||||||
})
|
})
|
||||||
|
.then(function () {
|
||||||
|
return AuthenticationSession.get(req);
|
||||||
|
})
|
||||||
|
.then(function (_authSession: AuthenticationSession.AuthenticationSession) {
|
||||||
|
authSession = _authSession;
|
||||||
|
})
|
||||||
.then(function () {
|
.then(function () {
|
||||||
return consumeToken(identityToken, handler.challenge(), userDataStore, logger);
|
return consumeToken(identityToken, handler.challenge(), userDataStore, logger);
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
|
|
||||||
import express = require("express");
|
import Express = require("express");
|
||||||
import { UserDataStore } from "./storage/UserDataStore";
|
import { UserDataStore } from "./storage/UserDataStore";
|
||||||
import { Winston } from "../../types/Dependencies";
|
import { Winston } from "../../types/Dependencies";
|
||||||
|
|
||||||
|
@ -23,22 +23,29 @@ import U2FSignRequestGet = require("./routes/secondfactor/u2f/sign_request/get")
|
||||||
import U2FRegisterPost = require("./routes/secondfactor/u2f/register/post");
|
import U2FRegisterPost = require("./routes/secondfactor/u2f/register/post");
|
||||||
import U2FRegisterRequestGet = require("./routes/secondfactor/u2f/register_request/get");
|
import U2FRegisterRequestGet = require("./routes/secondfactor/u2f/register_request/get");
|
||||||
|
|
||||||
|
|
||||||
import ResetPasswordFormPost = require("./routes/password-reset/form/post");
|
import ResetPasswordFormPost = require("./routes/password-reset/form/post");
|
||||||
import ResetPasswordRequestPost = require("./routes/password-reset/request/get");
|
import ResetPasswordRequestPost = require("./routes/password-reset/request/get");
|
||||||
|
|
||||||
import Error401Get = require("./routes/error/401/get");
|
import Error401Get = require("./routes/error/401/get");
|
||||||
import Error403Get = require("./routes/error/403/get");
|
import Error403Get = require("./routes/error/403/get");
|
||||||
import Error404Get = require("./routes/error/404/get");
|
import Error404Get = require("./routes/error/404/get");
|
||||||
|
import { ServerVariablesHandler } from "./ServerVariablesHandler";
|
||||||
|
|
||||||
import Endpoints = require("../endpoints");
|
import Endpoints = require("../endpoints");
|
||||||
|
|
||||||
|
function withLog(fn: (req: Express.Request, res: Express.Response) => void) {
|
||||||
|
return function(req: Express.Request, res: Express.Response) {
|
||||||
|
const logger = ServerVariablesHandler.getLogger(req.app);
|
||||||
|
logger.info("Request %s handled on %s", req.method, req.originalUrl);
|
||||||
|
fn(req, res);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export class RestApi {
|
export class RestApi {
|
||||||
static setup(app: express.Application): void {
|
static setup(app: Express.Application): void {
|
||||||
app.get(Endpoints.FIRST_FACTOR_GET, FirstFactorGet.default);
|
app.get(Endpoints.FIRST_FACTOR_GET, withLog(FirstFactorGet.default));
|
||||||
app.get(Endpoints.SECOND_FACTOR_GET, SecondFactorGet.default);
|
app.get(Endpoints.SECOND_FACTOR_GET, withLog(SecondFactorGet.default));
|
||||||
app.get(Endpoints.LOGOUT_GET, LogoutGet.default);
|
app.get(Endpoints.LOGOUT_GET, withLog(LogoutGet.default));
|
||||||
|
|
||||||
IdentityCheckMiddleware.register(app, Endpoints.SECOND_FACTOR_TOTP_IDENTITY_START_GET,
|
IdentityCheckMiddleware.register(app, Endpoints.SECOND_FACTOR_TOTP_IDENTITY_START_GET,
|
||||||
Endpoints.SECOND_FACTOR_TOTP_IDENTITY_FINISH_GET, new TOTPRegistrationIdentityHandler());
|
Endpoints.SECOND_FACTOR_TOTP_IDENTITY_FINISH_GET, new TOTPRegistrationIdentityHandler());
|
||||||
|
@ -49,25 +56,21 @@ export class RestApi {
|
||||||
IdentityCheckMiddleware.register(app, Endpoints.RESET_PASSWORD_IDENTITY_START_GET,
|
IdentityCheckMiddleware.register(app, Endpoints.RESET_PASSWORD_IDENTITY_START_GET,
|
||||||
Endpoints.RESET_PASSWORD_IDENTITY_FINISH_GET, new ResetPasswordIdentityHandler());
|
Endpoints.RESET_PASSWORD_IDENTITY_FINISH_GET, new ResetPasswordIdentityHandler());
|
||||||
|
|
||||||
app.get(Endpoints.RESET_PASSWORD_REQUEST_GET, ResetPasswordRequestPost.default);
|
app.get(Endpoints.RESET_PASSWORD_REQUEST_GET, withLog(ResetPasswordRequestPost.default));
|
||||||
app.post(Endpoints.RESET_PASSWORD_FORM_POST, ResetPasswordFormPost.default);
|
app.post(Endpoints.RESET_PASSWORD_FORM_POST, withLog(ResetPasswordFormPost.default));
|
||||||
|
|
||||||
app.get(Endpoints.VERIFY_GET, VerifyGet.default);
|
app.get(Endpoints.VERIFY_GET, withLog(VerifyGet.default));
|
||||||
|
app.post(Endpoints.FIRST_FACTOR_POST, withLog(FirstFactorPost.default));
|
||||||
|
app.post(Endpoints.SECOND_FACTOR_TOTP_POST, withLog(TOTPSignGet.default));
|
||||||
|
|
||||||
app.post(Endpoints.FIRST_FACTOR_POST, FirstFactorPost.default);
|
app.get(Endpoints.SECOND_FACTOR_U2F_SIGN_REQUEST_GET, withLog(U2FSignRequestGet.default));
|
||||||
|
app.post(Endpoints.SECOND_FACTOR_U2F_SIGN_POST, withLog(U2FSignPost.default));
|
||||||
|
|
||||||
|
app.get(Endpoints.SECOND_FACTOR_U2F_REGISTER_REQUEST_GET, withLog(U2FRegisterRequestGet.default));
|
||||||
|
app.post(Endpoints.SECOND_FACTOR_U2F_REGISTER_POST, withLog(U2FRegisterPost.default));
|
||||||
|
|
||||||
app.post(Endpoints.SECOND_FACTOR_TOTP_POST, TOTPSignGet.default);
|
app.get(Endpoints.ERROR_401_GET, withLog(Error401Get.default));
|
||||||
|
app.get(Endpoints.ERROR_403_GET, withLog(Error403Get.default));
|
||||||
|
app.get(Endpoints.ERROR_404_GET, withLog(Error404Get.default));
|
||||||
app.get(Endpoints.SECOND_FACTOR_U2F_SIGN_REQUEST_GET, U2FSignRequestGet.default);
|
|
||||||
app.post(Endpoints.SECOND_FACTOR_U2F_SIGN_POST, U2FSignPost.default);
|
|
||||||
|
|
||||||
app.get(Endpoints.SECOND_FACTOR_U2F_REGISTER_REQUEST_GET, U2FRegisterRequestGet.default);
|
|
||||||
app.post(Endpoints.SECOND_FACTOR_U2F_REGISTER_POST, U2FRegisterPost.default);
|
|
||||||
|
|
||||||
app.get(Endpoints.ERROR_401_GET, Error401Get.default);
|
|
||||||
app.get(Endpoints.ERROR_403_GET, Error403Get.default);
|
|
||||||
app.get(Endpoints.ERROR_404_GET, Error404Get.default);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
import ExpressSession = require("express-session");
|
import ExpressSession = require("express-session");
|
||||||
import { AppConfiguration } from "./Configuration";
|
import { AppConfiguration } from "./Configuration";
|
||||||
import { GlobalDependencies } from "../../../types/Dependencies";
|
import { GlobalDependencies } from "../../../types/Dependencies";
|
||||||
|
import Redis = require("redis");
|
||||||
|
|
||||||
export class SessionConfigurationBuilder {
|
export class SessionConfigurationBuilder {
|
||||||
|
|
||||||
|
@ -21,9 +22,16 @@ export class SessionConfigurationBuilder {
|
||||||
let redisOptions;
|
let redisOptions;
|
||||||
if (configuration.session.redis.host
|
if (configuration.session.redis.host
|
||||||
&& configuration.session.redis.port) {
|
&& configuration.session.redis.port) {
|
||||||
redisOptions = {
|
const client = Redis.createClient({
|
||||||
host: configuration.session.redis.host,
|
host: configuration.session.redis.host,
|
||||||
port: configuration.session.redis.port
|
port: configuration.session.redis.port
|
||||||
|
});
|
||||||
|
client.on("error", function (err: Error) {
|
||||||
|
console.error("Redis error:", err);
|
||||||
|
});
|
||||||
|
redisOptions = {
|
||||||
|
client: client,
|
||||||
|
logErrors: true
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,21 +5,22 @@ import FirstFactorValidator = require("../FirstFactorValidator");
|
||||||
import Exceptions = require("../Exceptions");
|
import Exceptions = require("../Exceptions");
|
||||||
import ErrorReplies = require("../ErrorReplies");
|
import ErrorReplies = require("../ErrorReplies");
|
||||||
import objectPath = require("object-path");
|
import objectPath = require("object-path");
|
||||||
import { ServerVariablesHandler } from "../ServerVariablesHandler";
|
import { ServerVariablesHandler } from "../ServerVariablesHandler";
|
||||||
import AuthenticationSession = require("../AuthenticationSession");
|
import AuthenticationSession = require("../AuthenticationSession");
|
||||||
|
|
||||||
type Handler = (req: express.Request, res: express.Response) => BluebirdPromise<void>;
|
type Handler = (req: express.Request, res: express.Response) => BluebirdPromise<void>;
|
||||||
|
|
||||||
export default function (callback: Handler): Handler {
|
export default function (callback: Handler): Handler {
|
||||||
return function (req: express.Request, res: express.Response): BluebirdPromise<void> {
|
return function (req: express.Request, res: express.Response): BluebirdPromise<void> {
|
||||||
const logger = ServerVariablesHandler.getLogger(req.app);
|
const logger = ServerVariablesHandler.getLogger(req.app);
|
||||||
|
|
||||||
const authSession = AuthenticationSession.get(req);
|
return AuthenticationSession.get(req)
|
||||||
logger.debug("AuthSession is %s", JSON.stringify(authSession));
|
.then(function (authSession) {
|
||||||
return FirstFactorValidator.validate(req)
|
return FirstFactorValidator.validate(req);
|
||||||
.then(function () {
|
})
|
||||||
return callback(req, res);
|
.then(function () {
|
||||||
})
|
return callback(req, res);
|
||||||
.catch(Exceptions.FirstFactorValidationError, ErrorReplies.replyWithError401(res, logger));
|
})
|
||||||
};
|
.catch(Exceptions.FirstFactorValidationError, ErrorReplies.replyWithError401(res, logger));
|
||||||
|
};
|
||||||
}
|
}
|
|
@ -5,19 +5,29 @@ import winston = require("winston");
|
||||||
import Endpoints = require("../../../endpoints");
|
import Endpoints = require("../../../endpoints");
|
||||||
import AuthenticationValidator = require("../../AuthenticationValidator");
|
import AuthenticationValidator = require("../../AuthenticationValidator");
|
||||||
import { ServerVariablesHandler } from "../../ServerVariablesHandler";
|
import { ServerVariablesHandler } from "../../ServerVariablesHandler";
|
||||||
|
import BluebirdPromise = require("bluebird");
|
||||||
|
|
||||||
export default function (req: express.Request, res: express.Response) {
|
export default function (req: express.Request, res: express.Response): BluebirdPromise<void> {
|
||||||
const logger = ServerVariablesHandler.getLogger(req.app);
|
const logger = ServerVariablesHandler.getLogger(req.app);
|
||||||
|
|
||||||
logger.debug("First factor: headers are %s", JSON.stringify(req.headers));
|
logger.debug("First factor: headers are %s", JSON.stringify(req.headers));
|
||||||
|
|
||||||
AuthenticationValidator.validate(req)
|
return AuthenticationValidator.validate(req)
|
||||||
.then(function () {
|
.then(function () {
|
||||||
res.render("already-logged-in", { logout_endpoint: Endpoints.LOGOUT_GET });
|
const redirectUrl = req.query.redirect;
|
||||||
}, function () {
|
if (redirectUrl) {
|
||||||
res.render("firstfactor", {
|
res.redirect(redirectUrl);
|
||||||
first_factor_post_endpoint: Endpoints.FIRST_FACTOR_POST,
|
return BluebirdPromise.resolve();
|
||||||
reset_password_request_endpoint: Endpoints.RESET_PASSWORD_REQUEST_GET
|
}
|
||||||
});
|
else {
|
||||||
});
|
res.render("already-logged-in", { logout_endpoint: Endpoints.LOGOUT_GET });
|
||||||
|
return BluebirdPromise.resolve();
|
||||||
|
}
|
||||||
|
}, function () {
|
||||||
|
res.render("firstfactor", {
|
||||||
|
first_factor_post_endpoint: Endpoints.FIRST_FACTOR_POST,
|
||||||
|
reset_password_request_endpoint: Endpoints.RESET_PASSWORD_REQUEST_GET
|
||||||
|
});
|
||||||
|
return BluebirdPromise.resolve();
|
||||||
|
});
|
||||||
}
|
}
|
|
@ -12,63 +12,67 @@ import { ServerVariablesHandler } from "../../ServerVariablesHandler";
|
||||||
import AuthenticationSession = require("../../AuthenticationSession");
|
import AuthenticationSession = require("../../AuthenticationSession");
|
||||||
|
|
||||||
export default function (req: express.Request, res: express.Response): BluebirdPromise<void> {
|
export default function (req: express.Request, res: express.Response): BluebirdPromise<void> {
|
||||||
const username: string = req.body.username;
|
const username: string = req.body.username;
|
||||||
const password: string = req.body.password;
|
const password: string = req.body.password;
|
||||||
|
|
||||||
const logger = ServerVariablesHandler.getLogger(req.app);
|
const logger = ServerVariablesHandler.getLogger(req.app);
|
||||||
const ldap = ServerVariablesHandler.getLdapAuthenticator(req.app);
|
const ldap = ServerVariablesHandler.getLdapAuthenticator(req.app);
|
||||||
const config = ServerVariablesHandler.getConfiguration(req.app);
|
const config = ServerVariablesHandler.getConfiguration(req.app);
|
||||||
|
|
||||||
if (!username || !password) {
|
if (!username || !password) {
|
||||||
const err = new Error("No username or password");
|
const err = new Error("No username or password");
|
||||||
ErrorReplies.replyWithError401(res, logger)(err);
|
ErrorReplies.replyWithError401(res, logger)(err);
|
||||||
return BluebirdPromise.reject(err);
|
return BluebirdPromise.reject(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
const regulator = ServerVariablesHandler.getAuthenticationRegulator(req.app);
|
const regulator = ServerVariablesHandler.getAuthenticationRegulator(req.app);
|
||||||
const accessController = ServerVariablesHandler.getAccessController(req.app);
|
const accessController = ServerVariablesHandler.getAccessController(req.app);
|
||||||
const authSession = AuthenticationSession.get(req);
|
let authSession: AuthenticationSession.AuthenticationSession;
|
||||||
|
|
||||||
logger.info("1st factor: Starting authentication of user \"%s\"", username);
|
logger.info("1st factor: Starting authentication of user \"%s\"", username);
|
||||||
logger.debug("1st factor: Start bind operation against LDAP");
|
logger.debug("1st factor: Start bind operation against LDAP");
|
||||||
logger.debug("1st factor: username=%s", username);
|
logger.debug("1st factor: username=%s", username);
|
||||||
|
|
||||||
return regulator.regulate(username)
|
return AuthenticationSession.get(req)
|
||||||
.then(function () {
|
.then(function (_authSession: AuthenticationSession.AuthenticationSession) {
|
||||||
logger.info("1st factor: No regulation applied.");
|
authSession = _authSession;
|
||||||
return ldap.authenticate(username, password);
|
return regulator.regulate(username);
|
||||||
})
|
})
|
||||||
.then(function (groupsAndEmails: GroupsAndEmails) {
|
.then(function () {
|
||||||
logger.info("1st factor: LDAP binding successful. Retrieved information about user are %s",
|
logger.info("1st factor: No regulation applied.");
|
||||||
JSON.stringify(groupsAndEmails));
|
return ldap.authenticate(username, password);
|
||||||
authSession.userid = username;
|
})
|
||||||
authSession.first_factor = true;
|
.then(function (groupsAndEmails: GroupsAndEmails) {
|
||||||
|
logger.info("1st factor: LDAP binding successful. Retrieved information about user are %s",
|
||||||
|
JSON.stringify(groupsAndEmails));
|
||||||
|
authSession.userid = username;
|
||||||
|
authSession.first_factor = true;
|
||||||
|
|
||||||
const emails: string[] = groupsAndEmails.emails;
|
const emails: string[] = groupsAndEmails.emails;
|
||||||
const groups: string[] = groupsAndEmails.groups;
|
const groups: string[] = groupsAndEmails.groups;
|
||||||
|
|
||||||
if (!emails || emails.length <= 0) {
|
if (!emails || emails.length <= 0) {
|
||||||
const errMessage = "No emails found. The user should have at least one email address to reset password.";
|
const errMessage = "No emails found. The user should have at least one email address to reset password.";
|
||||||
logger.error("1s factor: %s", errMessage);
|
logger.error("1s factor: %s", errMessage);
|
||||||
return BluebirdPromise.reject(new Error(errMessage));
|
return BluebirdPromise.reject(new Error(errMessage));
|
||||||
}
|
}
|
||||||
|
|
||||||
authSession.email = emails[0];
|
authSession.email = emails[0];
|
||||||
authSession.groups = groups;
|
authSession.groups = groups;
|
||||||
|
|
||||||
logger.debug("1st factor: Mark successful authentication to regulator.");
|
logger.debug("1st factor: Mark successful authentication to regulator.");
|
||||||
regulator.mark(username, true);
|
regulator.mark(username, true);
|
||||||
|
|
||||||
res.status(204);
|
res.status(204);
|
||||||
res.send();
|
res.send();
|
||||||
return BluebirdPromise.resolve();
|
return BluebirdPromise.resolve();
|
||||||
})
|
})
|
||||||
.catch(exceptions.LdapSearchError, ErrorReplies.replyWithError500(res, logger))
|
.catch(exceptions.LdapSearchError, ErrorReplies.replyWithError500(res, logger))
|
||||||
.catch(exceptions.LdapBindError, function (err: Error) {
|
.catch(exceptions.LdapBindError, function (err: Error) {
|
||||||
regulator.mark(username, false);
|
regulator.mark(username, false);
|
||||||
return ErrorReplies.replyWithError401(res, logger)(err);
|
return ErrorReplies.replyWithError401(res, logger)(err);
|
||||||
})
|
})
|
||||||
.catch(exceptions.AuthenticationRegulationError, ErrorReplies.replyWithError403(res, logger))
|
.catch(exceptions.AuthenticationRegulationError, ErrorReplies.replyWithError403(res, logger))
|
||||||
.catch(exceptions.DomainAccessDenied, ErrorReplies.replyWithError401(res, logger))
|
.catch(exceptions.DomainAccessDenied, ErrorReplies.replyWithError401(res, logger))
|
||||||
.catch(ErrorReplies.replyWithError500(res, logger));
|
.catch(ErrorReplies.replyWithError500(res, logger));
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@ import express = require("express");
|
||||||
import BluebirdPromise = require("bluebird");
|
import BluebirdPromise = require("bluebird");
|
||||||
import objectPath = require("object-path");
|
import objectPath = require("object-path");
|
||||||
import exceptions = require("../../../Exceptions");
|
import exceptions = require("../../../Exceptions");
|
||||||
import { ServerVariablesHandler } from "../../../ServerVariablesHandler";
|
import { ServerVariablesHandler } from "../../../ServerVariablesHandler";
|
||||||
import AuthenticationSession = require("../../../AuthenticationSession");
|
import AuthenticationSession = require("../../../AuthenticationSession");
|
||||||
import ErrorReplies = require("../../../ErrorReplies");
|
import ErrorReplies = require("../../../ErrorReplies");
|
||||||
|
|
||||||
|
@ -12,23 +12,27 @@ import Constants = require("./../constants");
|
||||||
export default function (req: express.Request, res: express.Response): BluebirdPromise<void> {
|
export default function (req: express.Request, res: express.Response): BluebirdPromise<void> {
|
||||||
const logger = ServerVariablesHandler.getLogger(req.app);
|
const logger = ServerVariablesHandler.getLogger(req.app);
|
||||||
const ldapPasswordUpdater = ServerVariablesHandler.getLdapPasswordUpdater(req.app);
|
const ldapPasswordUpdater = ServerVariablesHandler.getLdapPasswordUpdater(req.app);
|
||||||
const authSession = AuthenticationSession.get(req);
|
let authSession: AuthenticationSession.AuthenticationSession;
|
||||||
|
|
||||||
const newPassword = objectPath.get<express.Request, string>(req, "body.password");
|
const newPassword = objectPath.get<express.Request, string>(req, "body.password");
|
||||||
|
|
||||||
const userid = authSession.identity_check.userid;
|
return AuthenticationSession.get(req)
|
||||||
const challenge = authSession.identity_check.challenge;
|
.then(function (_authSession: AuthenticationSession.AuthenticationSession) {
|
||||||
if (challenge != Constants.CHALLENGE) {
|
authSession = _authSession;
|
||||||
res.status(403);
|
logger.info("POST reset-password: User %s wants to reset his/her password.",
|
||||||
res.send();
|
authSession.identity_check.userid);
|
||||||
return;
|
logger.info("POST reset-password: Challenge %s", authSession.identity_check.challenge);
|
||||||
}
|
|
||||||
|
|
||||||
logger.info("POST reset-password: User %s wants to reset his/her password", userid);
|
if (authSession.identity_check.challenge != Constants.CHALLENGE) {
|
||||||
|
res.status(403);
|
||||||
|
res.send();
|
||||||
|
return BluebirdPromise.reject(new Error("Bad challenge."));
|
||||||
|
}
|
||||||
|
|
||||||
return ldapPasswordUpdater.updatePassword(userid, newPassword)
|
return ldapPasswordUpdater.updatePassword(authSession.identity_check.userid, newPassword);
|
||||||
|
})
|
||||||
.then(function () {
|
.then(function () {
|
||||||
logger.info("POST reset-password: Password reset for user '%s'", userid);
|
logger.info("POST reset-password: Password reset for user '%s'",
|
||||||
|
authSession.identity_check.userid);
|
||||||
AuthenticationSession.reset(req);
|
AuthenticationSession.reset(req);
|
||||||
res.status(204);
|
res.status(204);
|
||||||
res.send();
|
res.send();
|
||||||
|
|
|
@ -1,14 +1,17 @@
|
||||||
|
|
||||||
import express = require("express");
|
import Express = require("express");
|
||||||
import Endpoints = require("../../../endpoints");
|
import Endpoints = require("../../../endpoints");
|
||||||
import FirstFactorBlocker = require("../FirstFactorBlocker");
|
import FirstFactorBlocker = require("../FirstFactorBlocker");
|
||||||
import BluebirdPromise = require("bluebird");
|
import BluebirdPromise = require("bluebird");
|
||||||
|
import { ServerVariablesHandler } from "../../ServerVariablesHandler";
|
||||||
|
|
||||||
const TEMPLATE_NAME = "secondfactor";
|
const TEMPLATE_NAME = "secondfactor";
|
||||||
|
|
||||||
export default FirstFactorBlocker.default(handler);
|
export default FirstFactorBlocker.default(handler);
|
||||||
|
|
||||||
function handler(req: express.Request, res: express.Response): BluebirdPromise<void> {
|
function handler(req: Express.Request, res: Express.Response): BluebirdPromise<void> {
|
||||||
|
const logger = ServerVariablesHandler.getLogger(req.app);
|
||||||
|
logger.debug("secondfactor request is coming from %s", req.originalUrl);
|
||||||
res.render(TEMPLATE_NAME, {
|
res.render(TEMPLATE_NAME, {
|
||||||
totp_identity_start_endpoint: Endpoints.SECOND_FACTOR_TOTP_IDENTITY_START_GET,
|
totp_identity_start_endpoint: Endpoints.SECOND_FACTOR_TOTP_IDENTITY_START_GET,
|
||||||
u2f_identity_start_endpoint: Endpoints.SECOND_FACTOR_U2F_IDENTITY_START_GET
|
u2f_identity_start_endpoint: Endpoints.SECOND_FACTOR_U2F_IDENTITY_START_GET
|
||||||
|
|
|
@ -5,11 +5,15 @@ import winston = require("winston");
|
||||||
import Endpoints = require("../../../endpoints");
|
import Endpoints = require("../../../endpoints");
|
||||||
import { ServerVariablesHandler } from "../../ServerVariablesHandler";
|
import { ServerVariablesHandler } from "../../ServerVariablesHandler";
|
||||||
import AuthenticationSession = require("../../AuthenticationSession");
|
import AuthenticationSession = require("../../AuthenticationSession");
|
||||||
|
import BluebirdPromise = require("bluebird");
|
||||||
|
|
||||||
export default function (req: express.Request, res: express.Response) {
|
export default function (req: express.Request, res: express.Response): BluebirdPromise<void> {
|
||||||
const authSession = AuthenticationSession.get(req);
|
return AuthenticationSession.get(req)
|
||||||
const redirectUrl = req.query.redirect || Endpoints.FIRST_FACTOR_GET;
|
.then(function (authSession: AuthenticationSession.AuthenticationSession) {
|
||||||
res.json({
|
const redirectUrl = req.query.redirect || Endpoints.FIRST_FACTOR_GET;
|
||||||
redirection_url: redirectUrl
|
res.json({
|
||||||
});
|
redirection_url: redirectUrl
|
||||||
|
});
|
||||||
|
return BluebirdPromise.resolve();
|
||||||
|
});
|
||||||
}
|
}
|
|
@ -9,7 +9,7 @@ import { PRE_VALIDATION_TEMPLATE } from "../../../../IdentityCheckPreValidationT
|
||||||
import Constants = require("../constants");
|
import Constants = require("../constants");
|
||||||
import Endpoints = require("../../../../../endpoints");
|
import Endpoints = require("../../../../../endpoints");
|
||||||
import ErrorReplies = require("../../../../ErrorReplies");
|
import ErrorReplies = require("../../../../ErrorReplies");
|
||||||
import { ServerVariablesHandler } from "../../../../ServerVariablesHandler";
|
import { ServerVariablesHandler } from "../../../../ServerVariablesHandler";
|
||||||
import AuthenticationSession = require("../../../../AuthenticationSession");
|
import AuthenticationSession = require("../../../../AuthenticationSession");
|
||||||
|
|
||||||
import FirstFactorValidator = require("../../../../FirstFactorValidator");
|
import FirstFactorValidator = require("../../../../FirstFactorValidator");
|
||||||
|
@ -21,19 +21,21 @@ export default class RegistrationHandler implements IdentityValidable {
|
||||||
}
|
}
|
||||||
|
|
||||||
private retrieveIdentity(req: express.Request): BluebirdPromise<Identity> {
|
private retrieveIdentity(req: express.Request): BluebirdPromise<Identity> {
|
||||||
const authSession = AuthenticationSession.get(req);
|
return AuthenticationSession.get(req)
|
||||||
const userid = authSession.userid;
|
.then(function (authSession: AuthenticationSession.AuthenticationSession) {
|
||||||
const email = authSession.email;
|
const userid = authSession.userid;
|
||||||
|
const email = authSession.email;
|
||||||
|
|
||||||
if (!(userid && email)) {
|
if (!(userid && email)) {
|
||||||
return BluebirdPromise.reject(new Error("User ID or email is missing"));
|
return BluebirdPromise.reject(new Error("User ID or email is missing"));
|
||||||
}
|
}
|
||||||
|
|
||||||
const identity = {
|
const identity = {
|
||||||
email: email,
|
email: email,
|
||||||
userid: userid
|
userid: userid
|
||||||
};
|
};
|
||||||
return BluebirdPromise.resolve(identity);
|
return BluebirdPromise.resolve(identity);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
preValidationInit(req: express.Request): BluebirdPromise<Identity> {
|
preValidationInit(req: express.Request): BluebirdPromise<Identity> {
|
||||||
|
@ -52,33 +54,34 @@ export default class RegistrationHandler implements IdentityValidable {
|
||||||
return FirstFactorValidator.validate(req);
|
return FirstFactorValidator.validate(req);
|
||||||
}
|
}
|
||||||
|
|
||||||
postValidationResponse(req: express.Request, res: express.Response) {
|
postValidationResponse(req: express.Request, res: express.Response): BluebirdPromise<void> {
|
||||||
const logger = ServerVariablesHandler.getLogger(req.app);
|
const logger = ServerVariablesHandler.getLogger(req.app);
|
||||||
const authSession = AuthenticationSession.get(req);
|
return AuthenticationSession.get(req)
|
||||||
|
.then(function (authSession: AuthenticationSession.AuthenticationSession) {
|
||||||
|
const userid = authSession.identity_check.userid;
|
||||||
|
const challenge = authSession.identity_check.challenge;
|
||||||
|
|
||||||
const userid = authSession.identity_check.userid;
|
if (challenge != Constants.CHALLENGE || !userid) {
|
||||||
const challenge = authSession.identity_check.challenge;
|
res.status(403);
|
||||||
|
res.send();
|
||||||
|
return BluebirdPromise.reject(new Error("Bad challenge."));
|
||||||
|
}
|
||||||
|
|
||||||
if (challenge != Constants.CHALLENGE || !userid) {
|
const userDataStore = ServerVariablesHandler.getUserDataStore(req.app);
|
||||||
res.status(403);
|
const totpGenerator = ServerVariablesHandler.getTOTPGenerator(req.app);
|
||||||
res.send();
|
const secret = totpGenerator.generate();
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const userDataStore = ServerVariablesHandler.getUserDataStore(req.app);
|
logger.debug("POST new-totp-secret: save the TOTP secret in DB");
|
||||||
const totpGenerator = ServerVariablesHandler.getTOTPGenerator(req.app);
|
return userDataStore.saveTOTPSecret(userid, secret)
|
||||||
const secret = totpGenerator.generate();
|
.then(function () {
|
||||||
|
objectPath.set(req, "session", undefined);
|
||||||
|
|
||||||
logger.debug("POST new-totp-secret: save the TOTP secret in DB");
|
res.render(Constants.TEMPLATE_NAME, {
|
||||||
userDataStore.saveTOTPSecret(userid, secret)
|
base32_secret: secret.base32,
|
||||||
.then(function () {
|
otpauth_url: secret.otpauth_url,
|
||||||
objectPath.set(req, "session", undefined);
|
login_endpoint: Endpoints.FIRST_FACTOR_GET
|
||||||
|
});
|
||||||
res.render(Constants.TEMPLATE_NAME, {
|
});
|
||||||
base32_secret: secret.base32,
|
|
||||||
otpauth_url: secret.otpauth_url,
|
|
||||||
login_endpoint: Endpoints.FIRST_FACTOR_GET
|
|
||||||
});
|
|
||||||
})
|
})
|
||||||
.catch(ErrorReplies.replyWithError500(res, logger));
|
.catch(ErrorReplies.replyWithError500(res, logger));
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,17 +16,18 @@ const UNAUTHORIZED_MESSAGE = "Unauthorized access";
|
||||||
export default FirstFactorBlocker(handler);
|
export default FirstFactorBlocker(handler);
|
||||||
|
|
||||||
export function handler(req: express.Request, res: express.Response): BluebirdPromise<void> {
|
export function handler(req: express.Request, res: express.Response): BluebirdPromise<void> {
|
||||||
|
let authSession: AuthenticationSession.AuthenticationSession;
|
||||||
const logger = ServerVariablesHandler.getLogger(req.app);
|
const logger = ServerVariablesHandler.getLogger(req.app);
|
||||||
const authSession = AuthenticationSession.get(req);
|
|
||||||
const userid = authSession.userid;
|
|
||||||
logger.info("POST 2ndfactor totp: Initiate TOTP validation for user %s", userid);
|
|
||||||
|
|
||||||
const token = req.body.token;
|
const token = req.body.token;
|
||||||
const totpValidator = ServerVariablesHandler.getTOTPValidator(req.app);
|
const totpValidator = ServerVariablesHandler.getTOTPValidator(req.app);
|
||||||
const userDataStore = ServerVariablesHandler.getUserDataStore(req.app);
|
const userDataStore = ServerVariablesHandler.getUserDataStore(req.app);
|
||||||
|
|
||||||
logger.debug("POST 2ndfactor totp: Fetching secret for user %s", userid);
|
return AuthenticationSession.get(req)
|
||||||
return userDataStore.retrieveTOTPSecret(userid)
|
.then(function (_authSession: AuthenticationSession.AuthenticationSession) {
|
||||||
|
authSession = _authSession;
|
||||||
|
logger.info("POST 2ndfactor totp: Initiate TOTP validation for user %s", authSession.userid);
|
||||||
|
return userDataStore.retrieveTOTPSecret(authSession.userid);
|
||||||
|
})
|
||||||
.then(function (doc: TOTPSecretDocument) {
|
.then(function (doc: TOTPSecretDocument) {
|
||||||
logger.debug("POST 2ndfactor totp: TOTP secret is %s", JSON.stringify(doc));
|
logger.debug("POST 2ndfactor totp: TOTP secret is %s", JSON.stringify(doc));
|
||||||
return totpValidator.validate(token, doc.secret.base32);
|
return totpValidator.validate(token, doc.secret.base32);
|
||||||
|
|
|
@ -20,20 +20,22 @@ export default class RegistrationHandler implements IdentityValidable {
|
||||||
return CHALLENGE;
|
return CHALLENGE;
|
||||||
}
|
}
|
||||||
|
|
||||||
private retrieveIdentity(req: express.Request) {
|
private retrieveIdentity(req: express.Request): BluebirdPromise<Identity> {
|
||||||
const authSession = AuthenticationSession.get(req);
|
return AuthenticationSession.get(req)
|
||||||
const userid = authSession.userid;
|
.then(function (authSession: AuthenticationSession.AuthenticationSession) {
|
||||||
const email = authSession.email;
|
const userid = authSession.userid;
|
||||||
|
const email = authSession.email;
|
||||||
|
|
||||||
if (!(userid && email)) {
|
if (!(userid && email)) {
|
||||||
return BluebirdPromise.reject("User ID or email is missing");
|
return BluebirdPromise.reject(new Error("User ID or email is missing"));
|
||||||
}
|
}
|
||||||
|
|
||||||
const identity = {
|
const identity = {
|
||||||
email: email,
|
email: email,
|
||||||
userid: userid
|
userid: userid
|
||||||
};
|
};
|
||||||
return BluebirdPromise.resolve(identity);
|
return BluebirdPromise.resolve(identity);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
preValidationInit(req: express.Request): BluebirdPromise<Identity> {
|
preValidationInit(req: express.Request): BluebirdPromise<Identity> {
|
||||||
|
|
|
@ -18,53 +18,54 @@ export default FirstFactorBlocker(handler);
|
||||||
|
|
||||||
|
|
||||||
function handler(req: express.Request, res: express.Response): BluebirdPromise<void> {
|
function handler(req: express.Request, res: express.Response): BluebirdPromise<void> {
|
||||||
const authSession = AuthenticationSession.get(req);
|
let authSession: AuthenticationSession.AuthenticationSession;
|
||||||
const registrationRequest = authSession.register_request;
|
const userDataStore = ServerVariablesHandler.getUserDataStore(req.app);
|
||||||
|
const u2f = ServerVariablesHandler.getU2F(req.app);
|
||||||
|
const appid = u2f_common.extract_app_id(req);
|
||||||
|
const logger = ServerVariablesHandler.getLogger(req.app);
|
||||||
|
const registrationResponse: U2f.RegistrationData = req.body;
|
||||||
|
|
||||||
if (!registrationRequest) {
|
return AuthenticationSession.get(req)
|
||||||
|
.then(function (_authSession: AuthenticationSession.AuthenticationSession) {
|
||||||
|
authSession = _authSession;
|
||||||
|
const registrationRequest = authSession.register_request;
|
||||||
|
|
||||||
|
if (!registrationRequest) {
|
||||||
res.status(403);
|
res.status(403);
|
||||||
res.send();
|
res.send();
|
||||||
return BluebirdPromise.reject(new Error("No registration request"));
|
return BluebirdPromise.reject(new Error("No registration request"));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!authSession.identity_check
|
if (!authSession.identity_check
|
||||||
|| authSession.identity_check.challenge != "u2f-register") {
|
|| authSession.identity_check.challenge != "u2f-register") {
|
||||||
res.status(403);
|
res.status(403);
|
||||||
res.send();
|
res.send();
|
||||||
return BluebirdPromise.reject(new Error("Bad challenge for registration request"));
|
return BluebirdPromise.reject(new Error("Bad challenge for registration request"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logger.info("U2F register: Finishing registration");
|
||||||
|
logger.debug("U2F register: registrationRequest = %s", JSON.stringify(registrationRequest));
|
||||||
|
logger.debug("U2F register: registrationResponse = %s", JSON.stringify(registrationResponse));
|
||||||
|
|
||||||
const userDataStore = ServerVariablesHandler.getUserDataStore(req.app);
|
return BluebirdPromise.resolve(u2f.checkRegistration(registrationRequest, registrationResponse));
|
||||||
const u2f = ServerVariablesHandler.getU2F(req.app);
|
})
|
||||||
const userid = authSession.userid;
|
.then(function (u2fResult: U2f.RegistrationResult | U2f.Error): BluebirdPromise<void> {
|
||||||
const appid = u2f_common.extract_app_id(req);
|
if (objectPath.has(u2fResult, "errorCode"))
|
||||||
const logger = ServerVariablesHandler.getLogger(req.app);
|
return BluebirdPromise.reject(new Error("Error while registering."));
|
||||||
|
|
||||||
const registrationResponse: U2f.RegistrationData = req.body;
|
const registrationResult: U2f.RegistrationResult = u2fResult as U2f.RegistrationResult;
|
||||||
|
logger.info("U2F register: Store regisutration and reply");
|
||||||
logger.info("U2F register: Finishing registration");
|
logger.debug("U2F register: registration = %s", JSON.stringify(registrationResult));
|
||||||
logger.debug("U2F register: registrationRequest = %s", JSON.stringify(registrationRequest));
|
const registration: U2FRegistration = {
|
||||||
logger.debug("U2F register: registrationResponse = %s", JSON.stringify(registrationResponse));
|
keyHandle: registrationResult.keyHandle,
|
||||||
|
publicKey: registrationResult.publicKey
|
||||||
BluebirdPromise.resolve(u2f.checkRegistration(registrationRequest, registrationResponse))
|
};
|
||||||
.then(function (u2fResult: U2f.RegistrationResult | U2f.Error): BluebirdPromise<void> {
|
return userDataStore.saveU2FRegistration(authSession.userid, appid, registration);
|
||||||
if (objectPath.has(u2fResult, "errorCode"))
|
})
|
||||||
return BluebirdPromise.reject(new Error("Error while registering."));
|
.then(function () {
|
||||||
|
authSession.identity_check = undefined;
|
||||||
const registrationResult: U2f.RegistrationResult = u2fResult as U2f.RegistrationResult;
|
redirect(req, res);
|
||||||
logger.info("U2F register: Store regisutration and reply");
|
return BluebirdPromise.resolve();
|
||||||
logger.debug("U2F register: registration = %s", JSON.stringify(registrationResult));
|
})
|
||||||
const registration: U2FRegistration = {
|
.catch(ErrorReplies.replyWithError500(res, logger));
|
||||||
keyHandle: registrationResult.keyHandle,
|
|
||||||
publicKey: registrationResult.publicKey
|
|
||||||
};
|
|
||||||
return userDataStore.saveU2FRegistration(userid, appid, registration);
|
|
||||||
})
|
|
||||||
.then(function () {
|
|
||||||
authSession.identity_check = undefined;
|
|
||||||
redirect(req, res);
|
|
||||||
return BluebirdPromise.resolve();
|
|
||||||
})
|
|
||||||
.catch(ErrorReplies.replyWithError500(res, logger));
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,29 +8,34 @@ import express = require("express");
|
||||||
import U2f = require("u2f");
|
import U2f = require("u2f");
|
||||||
import FirstFactorBlocker from "../../../FirstFactorBlocker";
|
import FirstFactorBlocker from "../../../FirstFactorBlocker";
|
||||||
import ErrorReplies = require("../../../../ErrorReplies");
|
import ErrorReplies = require("../../../../ErrorReplies");
|
||||||
import { ServerVariablesHandler } from "../../../../ServerVariablesHandler";
|
import { ServerVariablesHandler } from "../../../../ServerVariablesHandler";
|
||||||
import AuthenticationSession = require("../../../../AuthenticationSession");
|
import AuthenticationSession = require("../../../../AuthenticationSession");
|
||||||
|
|
||||||
export default FirstFactorBlocker(handler);
|
export default FirstFactorBlocker(handler);
|
||||||
|
|
||||||
function handler(req: express.Request, res: express.Response): BluebirdPromise<void> {
|
function handler(req: express.Request, res: express.Response): BluebirdPromise<void> {
|
||||||
const logger = ServerVariablesHandler.getLogger(req.app);
|
const logger = ServerVariablesHandler.getLogger(req.app);
|
||||||
const authSession = AuthenticationSession.get(req);
|
let authSession: AuthenticationSession.AuthenticationSession;
|
||||||
|
|
||||||
if (!authSession.identity_check
|
return AuthenticationSession.get(req)
|
||||||
|| authSession.identity_check.challenge != "u2f-register") {
|
.then(function (_authSession: AuthenticationSession.AuthenticationSession) {
|
||||||
res.status(403);
|
authSession = _authSession;
|
||||||
res.send();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const u2f = ServerVariablesHandler.getU2F(req.app);
|
if (!authSession.identity_check
|
||||||
const appid: string = u2f_common.extract_app_id(req);
|
|| authSession.identity_check.challenge != "u2f-register") {
|
||||||
|
res.status(403);
|
||||||
|
res.send();
|
||||||
|
return BluebirdPromise.reject(new Error("Bad challenge."));
|
||||||
|
}
|
||||||
|
|
||||||
logger.debug("U2F register_request: headers=%s", JSON.stringify(req.headers));
|
const u2f = ServerVariablesHandler.getU2F(req.app);
|
||||||
logger.info("U2F register_request: Starting registration for appId %s", appid);
|
const appid: string = u2f_common.extract_app_id(req);
|
||||||
|
|
||||||
return BluebirdPromise.resolve(u2f.request(appid))
|
logger.debug("U2F register_request: headers=%s", JSON.stringify(req.headers));
|
||||||
|
logger.info("U2F register_request: Starting registration for appId %s", appid);
|
||||||
|
|
||||||
|
return BluebirdPromise.resolve(u2f.request(appid));
|
||||||
|
})
|
||||||
.then(function (registrationRequest: U2f.Request) {
|
.then(function (registrationRequest: U2f.Request) {
|
||||||
logger.debug("U2F register_request: registrationRequest = %s", JSON.stringify(registrationRequest));
|
logger.debug("U2F register_request: registrationRequest = %s", JSON.stringify(registrationRequest));
|
||||||
authSession.register_request = registrationRequest;
|
authSession.register_request = registrationRequest;
|
||||||
|
|
|
@ -11,7 +11,7 @@ import exceptions = require("../../../../Exceptions");
|
||||||
import FirstFactorBlocker from "../../../FirstFactorBlocker";
|
import FirstFactorBlocker from "../../../FirstFactorBlocker";
|
||||||
import redirect from "../../redirect";
|
import redirect from "../../redirect";
|
||||||
import ErrorReplies = require("../../../../ErrorReplies");
|
import ErrorReplies = require("../../../../ErrorReplies");
|
||||||
import { ServerVariablesHandler } from "../../../../ServerVariablesHandler";
|
import { ServerVariablesHandler } from "../../../../ServerVariablesHandler";
|
||||||
import AuthenticationSession = require("../../../../AuthenticationSession");
|
import AuthenticationSession = require("../../../../AuthenticationSession");
|
||||||
|
|
||||||
export default FirstFactorBlocker(handler);
|
export default FirstFactorBlocker(handler);
|
||||||
|
@ -19,17 +19,21 @@ export default FirstFactorBlocker(handler);
|
||||||
export function handler(req: express.Request, res: express.Response): BluebirdPromise<void> {
|
export function handler(req: express.Request, res: express.Response): BluebirdPromise<void> {
|
||||||
const logger = ServerVariablesHandler.getLogger(req.app);
|
const logger = ServerVariablesHandler.getLogger(req.app);
|
||||||
const userDataStore = ServerVariablesHandler.getUserDataStore(req.app);
|
const userDataStore = ServerVariablesHandler.getUserDataStore(req.app);
|
||||||
const authSession = AuthenticationSession.get(req);
|
let authSession: AuthenticationSession.AuthenticationSession;
|
||||||
|
|
||||||
if (!authSession.sign_request) {
|
return AuthenticationSession.get(req)
|
||||||
const err = new Error("No sign request");
|
.then(function (_authSession: AuthenticationSession.AuthenticationSession) {
|
||||||
ErrorReplies.replyWithError401(res, logger)(err);
|
authSession = _authSession;
|
||||||
return BluebirdPromise.reject(err);
|
if (!authSession.sign_request) {
|
||||||
}
|
const err = new Error("No sign request");
|
||||||
|
ErrorReplies.replyWithError401(res, logger)(err);
|
||||||
|
return BluebirdPromise.reject(err);
|
||||||
|
}
|
||||||
|
|
||||||
const userid = authSession.userid;
|
const userid = authSession.userid;
|
||||||
const appid = u2f_common.extract_app_id(req);
|
const appid = u2f_common.extract_app_id(req);
|
||||||
return userDataStore.retrieveU2FRegistration(userid, appid)
|
return userDataStore.retrieveU2FRegistration(userid, appid);
|
||||||
|
})
|
||||||
.then(function (doc: U2FRegistrationDocument): BluebirdPromise<U2f.SignatureResult | U2f.Error> {
|
.then(function (doc: U2FRegistrationDocument): BluebirdPromise<U2f.SignatureResult | U2f.Error> {
|
||||||
const appId = u2f_common.extract_app_id(req);
|
const appId = u2f_common.extract_app_id(req);
|
||||||
const u2f = ServerVariablesHandler.getU2F(req.app);
|
const u2f = ServerVariablesHandler.getU2F(req.app);
|
||||||
|
|
|
@ -11,43 +11,46 @@ import exceptions = require("../../../../Exceptions");
|
||||||
import { SignMessage } from "./SignMessage";
|
import { SignMessage } from "./SignMessage";
|
||||||
import FirstFactorBlocker from "../../../FirstFactorBlocker";
|
import FirstFactorBlocker from "../../../FirstFactorBlocker";
|
||||||
import ErrorReplies = require("../../../../ErrorReplies");
|
import ErrorReplies = require("../../../../ErrorReplies");
|
||||||
import { ServerVariablesHandler } from "../../../../ServerVariablesHandler";
|
import { ServerVariablesHandler } from "../../../../ServerVariablesHandler";
|
||||||
import AuthenticationSession = require("../../../../AuthenticationSession");
|
import AuthenticationSession = require("../../../../AuthenticationSession");
|
||||||
|
|
||||||
export default FirstFactorBlocker(handler);
|
export default FirstFactorBlocker(handler);
|
||||||
|
|
||||||
export function handler(req: express.Request, res: express.Response): BluebirdPromise<void> {
|
export function handler(req: express.Request, res: express.Response): BluebirdPromise<void> {
|
||||||
const logger = ServerVariablesHandler.getLogger(req.app);
|
const logger = ServerVariablesHandler.getLogger(req.app);
|
||||||
const userDataStore = ServerVariablesHandler.getUserDataStore(req.app);
|
const userDataStore = ServerVariablesHandler.getUserDataStore(req.app);
|
||||||
const authSession = AuthenticationSession.get(req);
|
let authSession: AuthenticationSession.AuthenticationSession;
|
||||||
|
const appId = u2f_common.extract_app_id(req);
|
||||||
|
|
||||||
const userId = authSession.userid;
|
return AuthenticationSession.get(req)
|
||||||
const appId = u2f_common.extract_app_id(req);
|
.then(function (_authSession: AuthenticationSession.AuthenticationSession) {
|
||||||
return userDataStore.retrieveU2FRegistration(userId, appId)
|
authSession = _authSession;
|
||||||
.then(function (doc: U2FRegistrationDocument): BluebirdPromise<SignMessage> {
|
return userDataStore.retrieveU2FRegistration(authSession.userid, appId);
|
||||||
if (!doc)
|
})
|
||||||
return BluebirdPromise.reject(new exceptions.AccessDeniedError("No U2F registration found"));
|
.then(function (doc: U2FRegistrationDocument): BluebirdPromise<SignMessage> {
|
||||||
|
if (!doc)
|
||||||
|
return BluebirdPromise.reject(new exceptions.AccessDeniedError("No U2F registration found"));
|
||||||
|
|
||||||
const u2f = ServerVariablesHandler.getU2F(req.app);
|
const u2f = ServerVariablesHandler.getU2F(req.app);
|
||||||
const appId: string = u2f_common.extract_app_id(req);
|
const appId: string = u2f_common.extract_app_id(req);
|
||||||
logger.info("U2F sign_request: Start authentication to app %s", appId);
|
logger.info("U2F sign_request: Start authentication to app %s", appId);
|
||||||
logger.debug("U2F sign_request: appId=%s, keyHandle=%s", appId, JSON.stringify(doc.registration.keyHandle));
|
logger.debug("U2F sign_request: appId=%s, keyHandle=%s", appId, JSON.stringify(doc.registration.keyHandle));
|
||||||
|
|
||||||
const request = u2f.request(appId, doc.registration.keyHandle);
|
const request = u2f.request(appId, doc.registration.keyHandle);
|
||||||
const authenticationMessage: SignMessage = {
|
const authenticationMessage: SignMessage = {
|
||||||
request: request,
|
request: request,
|
||||||
keyHandle: doc.registration.keyHandle
|
keyHandle: doc.registration.keyHandle
|
||||||
};
|
};
|
||||||
return BluebirdPromise.resolve(authenticationMessage);
|
return BluebirdPromise.resolve(authenticationMessage);
|
||||||
})
|
})
|
||||||
.then(function (authenticationMessage: SignMessage) {
|
.then(function (authenticationMessage: SignMessage) {
|
||||||
logger.info("U2F sign_request: Store authentication request and reply");
|
logger.info("U2F sign_request: Store authentication request and reply");
|
||||||
logger.debug("U2F sign_request: authenticationRequest=%s", authenticationMessage);
|
logger.debug("U2F sign_request: authenticationRequest=%s", authenticationMessage);
|
||||||
authSession.sign_request = authenticationMessage.request;
|
authSession.sign_request = authenticationMessage.request;
|
||||||
res.json(authenticationMessage);
|
res.json(authenticationMessage);
|
||||||
return BluebirdPromise.resolve();
|
return BluebirdPromise.resolve();
|
||||||
})
|
})
|
||||||
.catch(exceptions.AccessDeniedError, ErrorReplies.replyWithError401(res, logger))
|
.catch(exceptions.AccessDeniedError, ErrorReplies.replyWithError401(res, logger))
|
||||||
.catch(ErrorReplies.replyWithError500(res, logger));
|
.catch(ErrorReplies.replyWithError500(res, logger));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,18 +8,22 @@ import exceptions = require("../../Exceptions");
|
||||||
import winston = require("winston");
|
import winston = require("winston");
|
||||||
import AuthenticationValidator = require("../../AuthenticationValidator");
|
import AuthenticationValidator = require("../../AuthenticationValidator");
|
||||||
import ErrorReplies = require("../../ErrorReplies");
|
import ErrorReplies = require("../../ErrorReplies");
|
||||||
import { ServerVariablesHandler } from "../../ServerVariablesHandler";
|
import { ServerVariablesHandler } from "../../ServerVariablesHandler";
|
||||||
import AuthenticationSession = require("../../AuthenticationSession");
|
import AuthenticationSession = require("../../AuthenticationSession");
|
||||||
|
|
||||||
function verify_filter(req: express.Request, res: express.Response): BluebirdPromise<void> {
|
function verify_filter(req: express.Request, res: express.Response): BluebirdPromise<void> {
|
||||||
const logger = ServerVariablesHandler.getLogger(req.app);
|
const logger = ServerVariablesHandler.getLogger(req.app);
|
||||||
const accessController = ServerVariablesHandler.getAccessController(req.app);
|
const accessController = ServerVariablesHandler.getAccessController(req.app);
|
||||||
const authSession = AuthenticationSession.get(req);
|
let authSession: AuthenticationSession.AuthenticationSession;
|
||||||
|
|
||||||
logger.debug("Verify: headers are %s", JSON.stringify(req.headers));
|
return AuthenticationSession.get(req)
|
||||||
res.set("Redirect", encodeURIComponent("https://" + req.headers["host"] + req.headers["x-original-uri"]));
|
.then(function (_authSession: AuthenticationSession.AuthenticationSession) {
|
||||||
|
authSession = _authSession;
|
||||||
|
logger.debug("Verify: headers are %s", JSON.stringify(req.headers));
|
||||||
|
res.set("Redirect", encodeURIComponent("https://" + req.headers["host"] + req.headers["x-original-uri"]));
|
||||||
|
|
||||||
return AuthenticationValidator.validate(req)
|
return AuthenticationValidator.validate(req);
|
||||||
|
})
|
||||||
.then(function () {
|
.then(function () {
|
||||||
const username = authSession.userid;
|
const username = authSession.userid;
|
||||||
const groups = authSession.groups;
|
const groups = authSession.groups;
|
||||||
|
|
|
@ -1,7 +1,11 @@
|
||||||
Feature: User has access restricted access to domains
|
Feature: User has access restricted access to domains
|
||||||
|
|
||||||
|
@need-registered-user-john
|
||||||
Scenario: User john has admin access
|
Scenario: User john has admin access
|
||||||
When I register TOTP and login with user "john" and password "password"
|
When I visit "https://auth.test.local:8080"
|
||||||
|
And I login with user "john" and password "password"
|
||||||
|
And I use "REGISTERED" as TOTP token handle
|
||||||
|
And I click on "TOTP"
|
||||||
Then I have access to:
|
Then I have access to:
|
||||||
| url |
|
| url |
|
||||||
| https://public.test.local:8080/secret.html |
|
| https://public.test.local:8080/secret.html |
|
||||||
|
@ -11,8 +15,12 @@ Feature: User has access restricted access to domains
|
||||||
| https://mx1.mail.test.local:8080/secret.html |
|
| https://mx1.mail.test.local:8080/secret.html |
|
||||||
| https://mx2.mail.test.local:8080/secret.html |
|
| https://mx2.mail.test.local:8080/secret.html |
|
||||||
|
|
||||||
|
@need-registered-user-bob
|
||||||
Scenario: User bob has restricted access
|
Scenario: User bob has restricted access
|
||||||
When I register TOTP and login with user "bob" and password "password"
|
When I visit "https://auth.test.local:8080"
|
||||||
|
And I login with user "bob" and password "password"
|
||||||
|
And I use "REGISTERED" as TOTP token handle
|
||||||
|
And I click on "TOTP"
|
||||||
Then I have access to:
|
Then I have access to:
|
||||||
| url |
|
| url |
|
||||||
| https://public.test.local:8080/secret.html |
|
| https://public.test.local:8080/secret.html |
|
||||||
|
@ -24,8 +32,12 @@ Feature: User has access restricted access to domains
|
||||||
| url |
|
| url |
|
||||||
| https://secret1.test.local:8080/secret.html |
|
| https://secret1.test.local:8080/secret.html |
|
||||||
|
|
||||||
|
@need-registered-user-harry
|
||||||
Scenario: User harry has restricted access
|
Scenario: User harry has restricted access
|
||||||
When I register TOTP and login with user "harry" and password "password"
|
When I visit "https://auth.test.local:8080"
|
||||||
|
And I login with user "harry" and password "password"
|
||||||
|
And I use "REGISTERED" as TOTP token handle
|
||||||
|
And I click on "TOTP"
|
||||||
Then I have access to:
|
Then I have access to:
|
||||||
| url |
|
| url |
|
||||||
| https://public.test.local:8080/secret.html |
|
| https://public.test.local:8080/secret.html |
|
||||||
|
|
|
@ -14,7 +14,7 @@ Feature: User validate first factor
|
||||||
And I click on "Sign in"
|
And I click on "Sign in"
|
||||||
Then I get a notification of type "error" with message "Authentication failed. Please double check your credentials."
|
Then I get a notification of type "error" with message "Authentication failed. Please double check your credentials."
|
||||||
|
|
||||||
Scenario: User succeeds TOTP second factor
|
Scenario: User registers TOTP secret and succeeds authentication
|
||||||
Given I visit "https://auth.test.local:8080/"
|
Given I visit "https://auth.test.local:8080/"
|
||||||
And I login with user "john" and password "password"
|
And I login with user "john" and password "password"
|
||||||
And I register a TOTP secret called "Sec0"
|
And I register a TOTP secret called "Sec0"
|
||||||
|
@ -31,23 +31,6 @@ Feature: User validate first factor
|
||||||
And I click on "TOTP"
|
And I click on "TOTP"
|
||||||
Then I get a notification of type "error" with message "Problem with TOTP validation."
|
Then I get a notification of type "error" with message "Problem with TOTP validation."
|
||||||
|
|
||||||
Scenario: User logs out
|
Scenario: Logout redirects user to redirect URL given in parameter
|
||||||
Given I visit "https://auth.test.local:8080/"
|
|
||||||
And I login with user "john" and password "password"
|
|
||||||
And I register a TOTP secret called "Sec0"
|
|
||||||
And I visit "https://auth.test.local:8080/"
|
|
||||||
And I login with user "john" and password "password"
|
|
||||||
And I use "Sec0" as TOTP token handle
|
|
||||||
When I visit "https://auth.test.local:8080/logout?redirect=https://www.google.fr"
|
|
||||||
And I visit "https://secret.test.local:8080/secret.html"
|
|
||||||
Then I'm redirected to "https://auth.test.local:8080/"
|
|
||||||
|
|
||||||
Scenario: Logout redirects user
|
|
||||||
Given I visit "https://auth.test.local:8080/"
|
|
||||||
And I login with user "john" and password "password"
|
|
||||||
And I register a TOTP secret called "Sec0"
|
|
||||||
And I visit "https://auth.test.local:8080/"
|
|
||||||
And I login with user "john" and password "password"
|
|
||||||
And I use "Sec0" as TOTP token handle
|
|
||||||
When I visit "https://auth.test.local:8080/logout?redirect=https://www.google.fr"
|
When I visit "https://auth.test.local:8080/logout?redirect=https://www.google.fr"
|
||||||
Then I'm redirected to "https://www.google.fr"
|
Then I'm redirected to "https://www.google.fr"
|
||||||
|
|
|
@ -5,19 +5,17 @@ Feature: User is correctly redirected
|
||||||
When I click on the link to secret.test.local
|
When I click on the link to secret.test.local
|
||||||
Then I'm redirected to "https://auth.test.local:8080/"
|
Then I'm redirected to "https://auth.test.local:8080/"
|
||||||
|
|
||||||
|
@need-registered-user-john
|
||||||
Scenario: User is redirected to home page after several authentication tries
|
Scenario: User is redirected to home page after several authentication tries
|
||||||
Given I'm on https://auth.test.local:8080/
|
When I visit "https://public.test.local:8080/secret.html"
|
||||||
And I login with user "john" and password "password"
|
And I login with user "john" and password "badpassword"
|
||||||
And I register a TOTP secret called "Sec0"
|
|
||||||
And I visit "https://public.test.local:8080/secret.html"
|
|
||||||
When I login with user "john" and password "badpassword"
|
|
||||||
And I clear field "username"
|
And I clear field "username"
|
||||||
And I login with user "john" and password "password"
|
And I login with user "john" and password "password"
|
||||||
And I use "Sec0" as TOTP token handle
|
And I use "REGISTERED" as TOTP token handle
|
||||||
And I click on "TOTP"
|
And I click on "TOTP"
|
||||||
Then I'm redirected to "https://public.test.local:8080/secret.html"
|
Then I'm redirected to "https://public.test.local:8080/secret.html"
|
||||||
|
|
||||||
Scenario: User Harry does not have access to https://secret.test.local:8080/secret.html and thus he must get an error 401
|
Scenario: User Harry does not have access to https://secret.test.local:8080/secret.html and thus he must get an error 403
|
||||||
When I register TOTP and login with user "harry" and password "password"
|
When I register TOTP and login with user "harry" and password "password"
|
||||||
And I visit "https://secret.test.local:8080/secret.html"
|
And I visit "https://secret.test.local:8080/secret.html"
|
||||||
Then I get an error 403
|
Then I get an error 403
|
||||||
|
|
|
@ -1,14 +1,9 @@
|
||||||
Feature: Authelia regulates authentication to avoid brute force
|
Feature: Authelia regulates authentication to avoid brute force
|
||||||
|
|
||||||
@needs-test-config
|
@needs-test-config
|
||||||
|
@need-registered-user-blackhat
|
||||||
Scenario: Attacker tries too many authentication in a short period of time and get banned
|
Scenario: Attacker tries too many authentication in a short period of time and get banned
|
||||||
Given I visit "https://auth.test.local:8080/"
|
Given I visit "https://auth.test.local:8080/"
|
||||||
And I login with user "blackhat" and password "password"
|
|
||||||
And I register a TOTP secret called "Sec0"
|
|
||||||
And I visit "https://auth.test.local:8080/"
|
|
||||||
And I login with user "blackhat" and password "password" and I use TOTP token handle "Sec0"
|
|
||||||
And I visit "https://auth.test.local:8080/logout?redirect=https://auth.test.local:8080/"
|
|
||||||
And I visit "https://auth.test.local:8080/"
|
|
||||||
And I set field "username" to "blackhat"
|
And I set field "username" to "blackhat"
|
||||||
And I set field "password" to "bad-password"
|
And I set field "password" to "bad-password"
|
||||||
And I click on "Sign in"
|
And I click on "Sign in"
|
||||||
|
@ -24,14 +19,9 @@ Feature: Authelia regulates authentication to avoid brute force
|
||||||
Then I get a notification of type "error" with message "Authentication failed. Please double check your credentials."
|
Then I get a notification of type "error" with message "Authentication failed. Please double check your credentials."
|
||||||
|
|
||||||
@needs-test-config
|
@needs-test-config
|
||||||
|
@need-registered-user-blackhat
|
||||||
Scenario: User is unbanned after a configured amount of time
|
Scenario: User is unbanned after a configured amount of time
|
||||||
Given I visit "https://auth.test.local:8080/"
|
Given I visit "https://auth.test.local:8080/?redirect=https%3A%2F%2Fpublic.test.local%3A8080%2Fsecret.html"
|
||||||
And I login with user "blackhat" and password "password"
|
|
||||||
And I register a TOTP secret called "Sec0"
|
|
||||||
And I visit "https://auth.test.local:8080/"
|
|
||||||
And I login with user "blackhat" and password "password" and I use TOTP token handle "Sec0"
|
|
||||||
And I visit "https://auth.test.local:8080/logout?redirect=https://auth.test.local:8080/"
|
|
||||||
And I visit "https://auth.test.local:8080/"
|
|
||||||
And I set field "username" to "blackhat"
|
And I set field "username" to "blackhat"
|
||||||
And I set field "password" to "bad-password"
|
And I set field "password" to "bad-password"
|
||||||
And I click on "Sign in"
|
And I click on "Sign in"
|
||||||
|
@ -45,7 +35,7 @@ Feature: Authelia regulates authentication to avoid brute force
|
||||||
When I wait 6 seconds
|
When I wait 6 seconds
|
||||||
And I set field "password" to "password"
|
And I set field "password" to "password"
|
||||||
And I click on "Sign in"
|
And I click on "Sign in"
|
||||||
And I use "Sec0" as TOTP token handle
|
And I use "REGISTERED" as TOTP token handle
|
||||||
And I click on "TOTP"
|
And I click on "TOTP"
|
||||||
Then I have access to:
|
Then I have access to:
|
||||||
| url |
|
| url |
|
||||||
|
|
|
@ -1,20 +1,18 @@
|
||||||
Feature: Authelia keeps user sessions despite the application restart
|
Feature: Authelia keeps user sessions despite the application restart
|
||||||
|
|
||||||
|
@need-authenticated-user-john
|
||||||
Scenario: Session is still valid after Authelia restarts
|
Scenario: Session is still valid after Authelia restarts
|
||||||
When I register TOTP and login with user "john" and password "password"
|
When the application restarts
|
||||||
And the application restarts
|
|
||||||
Then I have access to:
|
Then I have access to:
|
||||||
| url |
|
| url |
|
||||||
| https://secret.test.local:8080/secret.html |
|
| https://secret.test.local:8080/secret.html |
|
||||||
|
|
||||||
|
@need-registered-user-john
|
||||||
Scenario: Secrets are stored even when Authelia restarts
|
Scenario: Secrets are stored even when Authelia restarts
|
||||||
Given I visit "https://auth.test.local:8080/"
|
|
||||||
And I login with user "john" and password "password"
|
|
||||||
And I register a TOTP secret called "Sec0"
|
|
||||||
When the application restarts
|
When the application restarts
|
||||||
And I visit "https://secret.test.local:8080/secret.html" and get redirected "https://auth.test.local:8080/?redirect=https%3A%2F%2Fsecret.test.local%3A8080%2Fsecret.html"
|
And I visit "https://secret.test.local:8080/secret.html" and get redirected "https://auth.test.local:8080/?redirect=https%3A%2F%2Fsecret.test.local%3A8080%2Fsecret.html"
|
||||||
And I login with user "john" and password "password"
|
And I login with user "john" and password "password"
|
||||||
And I use "Sec0" as TOTP token handle
|
And I use "REGISTERED" as TOTP token handle
|
||||||
And I click on "TOTP"
|
And I click on "TOTP"
|
||||||
Then I have access to:
|
Then I have access to:
|
||||||
| url |
|
| url |
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
Feature: Non authenticated users have no access to certain pages
|
Feature: Non authenticated users have no access to certain pages
|
||||||
|
|
||||||
Scenario Outline: User has no access to protected pages
|
Scenario Outline: Anonymous user has no access to protected pages
|
||||||
When I visit "<url>"
|
When I visit "<url>"
|
||||||
Then I get an error <error code>
|
Then I get an error <error code>
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ import Speakeasy = require("speakeasy");
|
||||||
import CustomWorld = require("../support/world");
|
import CustomWorld = require("../support/world");
|
||||||
|
|
||||||
Cucumber.defineSupportCode(function ({ Given, When, Then }) {
|
Cucumber.defineSupportCode(function ({ Given, When, Then }) {
|
||||||
When(/^I visit "(https:\/\/[a-z0-9:.\/=?-]+)"$/, function (link: string) {
|
When(/^I visit "(https:\/\/[a-zA-Z0-9:%.\/=?-]+)"$/, function (link: string) {
|
||||||
return this.visit(link);
|
return this.visit(link);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -2,23 +2,90 @@ import Cucumber = require("cucumber");
|
||||||
import fs = require("fs");
|
import fs = require("fs");
|
||||||
import BluebirdPromise = require("bluebird");
|
import BluebirdPromise = require("bluebird");
|
||||||
import ChildProcess = require("child_process");
|
import ChildProcess = require("child_process");
|
||||||
|
import { UserDataStore } from "../../../src/server/lib/storage/UserDataStore";
|
||||||
|
import { CollectionFactoryFactory } from "../../../src/server/lib/storage/CollectionFactoryFactory";
|
||||||
|
import { MongoConnector } from "../../../src/server/lib/connectors/mongo/MongoConnector";
|
||||||
|
import { IMongoClient } from "../../../src/server/lib/connectors/mongo/IMongoClient";
|
||||||
|
import { TOTPGenerator } from "../../../src/server/lib/TOTPGenerator";
|
||||||
|
import Speakeasy = require("speakeasy");
|
||||||
|
|
||||||
Cucumber.defineSupportCode(function({ setDefaultTimeout }) {
|
Cucumber.defineSupportCode(function ({ setDefaultTimeout }) {
|
||||||
setDefaultTimeout(20 * 1000);
|
setDefaultTimeout(20 * 1000);
|
||||||
});
|
});
|
||||||
|
|
||||||
Cucumber.defineSupportCode(function({ After, Before }) {
|
Cucumber.defineSupportCode(function ({ After, Before }) {
|
||||||
const exec = BluebirdPromise.promisify(ChildProcess.exec);
|
const exec = BluebirdPromise.promisify(ChildProcess.exec);
|
||||||
|
|
||||||
After(function() {
|
After(function () {
|
||||||
return this.driver.quit();
|
return this.driver.quit();
|
||||||
});
|
});
|
||||||
|
|
||||||
Before({tags: "@needs-test-config", timeout: 15 * 1000}, function () {
|
Before({ tags: "@needs-test-config", timeout: 20 * 1000 }, function () {
|
||||||
return exec("./scripts/example-commit/dc-example.sh -f docker-compose.test.yml up -d authelia && sleep 2");
|
return exec("./scripts/example-commit/dc-example.sh -f docker-compose.test.yml up -d authelia && sleep 2");
|
||||||
});
|
});
|
||||||
|
|
||||||
After({tags: "@needs-test-config", timeout: 15 * 1000}, function () {
|
After({ tags: "@needs-test-config", timeout: 20 * 1000 }, function () {
|
||||||
return exec("./scripts/example-commit/dc-example.sh up -d authelia && sleep 2");
|
return exec("./scripts/example-commit/dc-example.sh up -d authelia && sleep 2");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function registerUser(context: any, username: string) {
|
||||||
|
let secret: Speakeasy.Key;
|
||||||
|
const mongoConnector = new MongoConnector("mongodb://localhost:27017/authelia");
|
||||||
|
return mongoConnector.connect()
|
||||||
|
.then(function (mongoClient: IMongoClient) {
|
||||||
|
const collectionFactory = CollectionFactoryFactory.createMongo(mongoClient);
|
||||||
|
const userDataStore = new UserDataStore(collectionFactory);
|
||||||
|
|
||||||
|
const generator = new TOTPGenerator(Speakeasy);
|
||||||
|
secret = generator.generate();
|
||||||
|
return userDataStore.saveTOTPSecret(username, secret);
|
||||||
|
})
|
||||||
|
.then(function () {
|
||||||
|
context.totpSecrets["REGISTERED"] = secret.base32;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function declareNeedRegisteredUserHooks(username: string) {
|
||||||
|
Before({ tags: "@need-registered-user-" + username, timeout: 15 * 1000 }, function () {
|
||||||
|
return registerUser(this, username);
|
||||||
|
});
|
||||||
|
|
||||||
|
After({ tags: "@need-registered-user-" + username, timeout: 15 * 1000 }, function () {
|
||||||
|
this.totpSecrets["REGISTERED"] = undefined;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function needAuthenticatedUser(context: any, username: string): BluebirdPromise<void> {
|
||||||
|
return context.visit("https://auth.test.local:8080/")
|
||||||
|
.then(function () {
|
||||||
|
return registerUser(context, username);
|
||||||
|
})
|
||||||
|
.then(function () {
|
||||||
|
return context.loginWithUserPassword(username, "password");
|
||||||
|
})
|
||||||
|
.then(function () {
|
||||||
|
return context.useTotpTokenHandle("REGISTERED");
|
||||||
|
})
|
||||||
|
.then(function() {
|
||||||
|
return context.clickOnButton("TOTP");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function declareNeedAuthenticatedUserHooks(username: string) {
|
||||||
|
Before({ tags: "@need-authenticated-user-" + username, timeout: 15 * 1000 }, function () {
|
||||||
|
return needAuthenticatedUser(this, username);
|
||||||
|
});
|
||||||
|
|
||||||
|
After({ tags: "@need-authenticated-user-" + username, timeout: 15 * 1000 }, function () {
|
||||||
|
this.totpSecrets["REGISTERED"] = undefined;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function declareHooksForUser(username: string) {
|
||||||
|
declareNeedRegisteredUserHooks(username);
|
||||||
|
declareNeedAuthenticatedUserHooks(username);
|
||||||
|
}
|
||||||
|
|
||||||
|
const users = ["harry", "john", "bob", "blackhat"];
|
||||||
|
users.forEach(declareHooksForUser);
|
||||||
});
|
});
|
|
@ -91,6 +91,9 @@ function CustomWorld() {
|
||||||
};
|
};
|
||||||
|
|
||||||
this.useTotpTokenHandle = function (totpSecretHandle: string) {
|
this.useTotpTokenHandle = function (totpSecretHandle: string) {
|
||||||
|
if (!this.totpSecrets[totpSecretHandle])
|
||||||
|
throw new Error("No available TOTP token handle " + totpSecretHandle);
|
||||||
|
|
||||||
const token = Speakeasy.totp({
|
const token = Speakeasy.totp({
|
||||||
secret: this.totpSecrets[totpSecretHandle],
|
secret: this.totpSecrets[totpSecretHandle],
|
||||||
encoding: "base32"
|
encoding: "base32"
|
||||||
|
|
|
@ -155,9 +155,14 @@ describe("test identity check process", function () {
|
||||||
req.query.identity_token = "token";
|
req.query.identity_token = "token";
|
||||||
|
|
||||||
req.session = {};
|
req.session = {};
|
||||||
const authSession = AuthenticationSession.get(req as any);
|
let authSession: AuthenticationSession.AuthenticationSession;
|
||||||
const callback = IdentityValidator.get_finish_validation(identityValidable);
|
const callback = IdentityValidator.get_finish_validation(identityValidable);
|
||||||
return callback(req as any, res as any, undefined)
|
|
||||||
|
return AuthenticationSession.get(req as any)
|
||||||
|
.then(function (_authSession: AuthenticationSession.AuthenticationSession) {
|
||||||
|
authSession = _authSession;
|
||||||
|
return callback(req as any, res as any, undefined);
|
||||||
|
})
|
||||||
.then(function () { return BluebirdPromise.reject("Should fail"); })
|
.then(function () { return BluebirdPromise.reject("Should fail"); })
|
||||||
.catch(function () {
|
.catch(function () {
|
||||||
assert.equal(authSession.identity_check.userid, "user");
|
assert.equal(authSession.identity_check.userid, "user");
|
||||||
|
|
|
@ -45,6 +45,7 @@ describe("test the first factor validation route", function () {
|
||||||
|
|
||||||
req = {
|
req = {
|
||||||
app: {
|
app: {
|
||||||
|
get: sinon.stub().returns({ logger: winston })
|
||||||
},
|
},
|
||||||
body: {
|
body: {
|
||||||
username: "username",
|
username: "username",
|
||||||
|
@ -77,8 +78,12 @@ describe("test the first factor validation route", function () {
|
||||||
emails: emails,
|
emails: emails,
|
||||||
groups: groups
|
groups: groups
|
||||||
}));
|
}));
|
||||||
const authSession = AuthenticationSession.get(req as any);
|
let authSession: AuthenticationSession.AuthenticationSession;
|
||||||
return FirstFactorPost.default(req as any, res as any)
|
return AuthenticationSession.get(req as any)
|
||||||
|
.then(function (_authSession: AuthenticationSession.AuthenticationSession) {
|
||||||
|
authSession = _authSession;
|
||||||
|
return FirstFactorPost.default(req as any, res as any);
|
||||||
|
})
|
||||||
.then(function () {
|
.then(function () {
|
||||||
assert.equal("username", authSession.userid);
|
assert.equal("username", authSession.userid);
|
||||||
assert(res.send.calledOnce);
|
assert(res.send.calledOnce);
|
||||||
|
@ -94,13 +99,18 @@ describe("test the first factor validation route", function () {
|
||||||
|
|
||||||
it("should set first email address as user session variable", function () {
|
it("should set first email address as user session variable", function () {
|
||||||
const emails = ["test_ok@example.com"];
|
const emails = ["test_ok@example.com"];
|
||||||
const authSession = AuthenticationSession.get(req as any);
|
let authSession: AuthenticationSession.AuthenticationSession;
|
||||||
(serverVariables.ldapAuthenticator as any).authenticate.withArgs("username", "password")
|
(serverVariables.ldapAuthenticator as any).authenticate.withArgs("username", "password")
|
||||||
.returns(BluebirdPromise.resolve({
|
.returns(BluebirdPromise.resolve({
|
||||||
emails: emails,
|
emails: emails,
|
||||||
groups: groups
|
groups: groups
|
||||||
}));
|
}));
|
||||||
return FirstFactorPost.default(req as any, res as any)
|
|
||||||
|
return AuthenticationSession.get(req as any)
|
||||||
|
.then(function (_authSession: AuthenticationSession.AuthenticationSession) {
|
||||||
|
authSession = _authSession;
|
||||||
|
return FirstFactorPost.default(req as any, res as any);
|
||||||
|
})
|
||||||
.then(function () {
|
.then(function () {
|
||||||
assert.equal("test_ok@example.com", authSession.email);
|
assert.equal("test_ok@example.com", authSession.email);
|
||||||
});
|
});
|
||||||
|
|
|
@ -16,7 +16,6 @@ describe("test reset password route", function () {
|
||||||
let req: ExpressMock.RequestMock;
|
let req: ExpressMock.RequestMock;
|
||||||
let res: ExpressMock.ResponseMock;
|
let res: ExpressMock.ResponseMock;
|
||||||
let configuration: any;
|
let configuration: any;
|
||||||
let authSession: AuthenticationSession.AuthenticationSession;
|
|
||||||
let serverVariables: ServerVariablesMock.ServerVariablesMock;
|
let serverVariables: ServerVariablesMock.ServerVariablesMock;
|
||||||
|
|
||||||
beforeEach(function () {
|
beforeEach(function () {
|
||||||
|
@ -25,7 +24,7 @@ describe("test reset password route", function () {
|
||||||
userid: "user"
|
userid: "user"
|
||||||
},
|
},
|
||||||
app: {
|
app: {
|
||||||
get: Sinon.stub()
|
get: Sinon.stub().returns({ logger: winston })
|
||||||
},
|
},
|
||||||
session: {},
|
session: {},
|
||||||
headers: {
|
headers: {
|
||||||
|
@ -34,11 +33,6 @@ describe("test reset password route", function () {
|
||||||
};
|
};
|
||||||
|
|
||||||
AuthenticationSession.reset(req as any);
|
AuthenticationSession.reset(req as any);
|
||||||
authSession = AuthenticationSession.get(req as any);
|
|
||||||
authSession.userid = "user";
|
|
||||||
authSession.email = "user@example.com";
|
|
||||||
authSession.first_factor = true;
|
|
||||||
authSession.second_factor = false;
|
|
||||||
|
|
||||||
const options = {
|
const options = {
|
||||||
inMemoryOnly: true
|
inMemoryOnly: true
|
||||||
|
@ -65,54 +59,72 @@ describe("test reset password route", function () {
|
||||||
} as any;
|
} as any;
|
||||||
|
|
||||||
res = ExpressMock.ResponseMock();
|
res = ExpressMock.ResponseMock();
|
||||||
|
AuthenticationSession.get(req as any)
|
||||||
|
.then(function (authSession: AuthenticationSession.AuthenticationSession) {
|
||||||
|
authSession.userid = "user";
|
||||||
|
authSession.email = "user@example.com";
|
||||||
|
authSession.first_factor = true;
|
||||||
|
authSession.second_factor = false;
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("test reset password post", () => {
|
describe("test reset password post", () => {
|
||||||
it("should update the password and reset auth_session for reauthentication", function () {
|
it("should update the password and reset auth_session for reauthentication", function () {
|
||||||
authSession.identity_check = {
|
|
||||||
userid: "user",
|
|
||||||
challenge: "reset-password"
|
|
||||||
};
|
|
||||||
req.body = {};
|
req.body = {};
|
||||||
req.body.password = "new-password";
|
req.body.password = "new-password";
|
||||||
|
|
||||||
(serverVariables.ldapPasswordUpdater.updatePassword as sinon.SinonStub).returns(BluebirdPromise.resolve());
|
(serverVariables.ldapPasswordUpdater.updatePassword as sinon.SinonStub).returns(BluebirdPromise.resolve());
|
||||||
return PasswordResetFormPost.default(req as any, res as any)
|
|
||||||
|
return AuthenticationSession.get(req as any)
|
||||||
|
.then(function (authSession) {
|
||||||
|
authSession.identity_check = {
|
||||||
|
userid: "user",
|
||||||
|
challenge: "reset-password"
|
||||||
|
};
|
||||||
|
return PasswordResetFormPost.default(req as any, res as any);
|
||||||
|
})
|
||||||
.then(function () {
|
.then(function () {
|
||||||
const authSession = AuthenticationSession.get(req as any);
|
return AuthenticationSession.get(req as any);
|
||||||
|
}).then(function (_authSession: AuthenticationSession.AuthenticationSession) {
|
||||||
assert.equal(res.status.getCall(0).args[0], 204);
|
assert.equal(res.status.getCall(0).args[0], 204);
|
||||||
assert.equal(authSession.first_factor, false);
|
assert.equal(_authSession.first_factor, false);
|
||||||
assert.equal(authSession.second_factor, false);
|
assert.equal(_authSession.second_factor, false);
|
||||||
return BluebirdPromise.resolve();
|
return BluebirdPromise.resolve();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should fail if identity_challenge does not exist", function (done) {
|
it("should fail if identity_challenge does not exist", function () {
|
||||||
authSession.identity_check = {
|
return AuthenticationSession.get(req as any)
|
||||||
userid: "user",
|
.then(function (authSession) {
|
||||||
challenge: undefined
|
authSession.identity_check = {
|
||||||
};
|
userid: "user",
|
||||||
res.send = Sinon.spy(function () {
|
challenge: undefined
|
||||||
assert.equal(res.status.getCall(0).args[0], 403);
|
};
|
||||||
done();
|
return PasswordResetFormPost.default(req as any, res as any);
|
||||||
});
|
})
|
||||||
PasswordResetFormPost.default(req as any, res as any);
|
.then(function () {
|
||||||
|
assert.equal(res.status.getCall(0).args[0], 403);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should fail when ldap fails", function (done) {
|
it("should fail when ldap fails", function () {
|
||||||
authSession.identity_check = {
|
|
||||||
challenge: "reset-password",
|
|
||||||
userid: "user"
|
|
||||||
};
|
|
||||||
req.body = {};
|
req.body = {};
|
||||||
req.body.password = "new-password";
|
req.body.password = "new-password";
|
||||||
|
|
||||||
(serverVariables.ldapPasswordUpdater.updatePassword as Sinon.SinonStub).returns(BluebirdPromise.reject("Internal error with LDAP"));
|
(serverVariables.ldapPasswordUpdater.updatePassword as Sinon.SinonStub)
|
||||||
res.send = Sinon.spy(function () {
|
.returns(BluebirdPromise.reject("Internal error with LDAP"));
|
||||||
assert.equal(res.status.getCall(0).args[0], 500);
|
|
||||||
done();
|
return AuthenticationSession.get(req as any)
|
||||||
});
|
.then(function (authSession) {
|
||||||
PasswordResetFormPost.default(req as any, res as any);
|
authSession.identity_check = {
|
||||||
|
challenge: "reset-password",
|
||||||
|
userid: "user"
|
||||||
|
};
|
||||||
|
return PasswordResetFormPost.default(req as any, res as any);
|
||||||
|
}).then(function () {
|
||||||
|
assert.equal(res.status.getCall(0).args[0], 500);
|
||||||
|
return BluebirdPromise.resolve();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -23,11 +23,6 @@ describe("test totp register", function () {
|
||||||
req.session = {};
|
req.session = {};
|
||||||
|
|
||||||
AuthenticationSession.reset(req as any);
|
AuthenticationSession.reset(req as any);
|
||||||
authSession = AuthenticationSession.get(req as any);
|
|
||||||
authSession.userid = "user";
|
|
||||||
authSession.email = "user@example.com";
|
|
||||||
authSession.first_factor = true;
|
|
||||||
authSession.second_factor = false;
|
|
||||||
|
|
||||||
req.headers = {};
|
req.headers = {};
|
||||||
req.headers.host = "localhost";
|
req.headers.host = "localhost";
|
||||||
|
@ -43,6 +38,15 @@ describe("test totp register", function () {
|
||||||
mocks.userDataStore.saveTOTPSecretStub.returns(BluebirdPromise.resolve({}));
|
mocks.userDataStore.saveTOTPSecretStub.returns(BluebirdPromise.resolve({}));
|
||||||
|
|
||||||
res = ExpressMock.ResponseMock();
|
res = ExpressMock.ResponseMock();
|
||||||
|
|
||||||
|
return AuthenticationSession.get(req as any)
|
||||||
|
.then(function (_authSession: AuthenticationSession.AuthenticationSession) {
|
||||||
|
authSession = _authSession;
|
||||||
|
authSession.userid = "user";
|
||||||
|
authSession.email = "user@example.com";
|
||||||
|
authSession.first_factor = true;
|
||||||
|
authSession.second_factor = false;
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("test totp registration check", test_registration_check);
|
describe("test totp registration check", test_registration_check);
|
||||||
|
|
|
@ -23,6 +23,7 @@ describe("test totp route", function () {
|
||||||
const app_get = sinon.stub();
|
const app_get = sinon.stub();
|
||||||
req = {
|
req = {
|
||||||
app: {
|
app: {
|
||||||
|
get: sinon.stub().returns({ logger: winston })
|
||||||
},
|
},
|
||||||
body: {
|
body: {
|
||||||
token: "abc"
|
token: "abc"
|
||||||
|
@ -30,11 +31,6 @@ describe("test totp route", function () {
|
||||||
session: {}
|
session: {}
|
||||||
};
|
};
|
||||||
AuthenticationSession.reset(req as any);
|
AuthenticationSession.reset(req as any);
|
||||||
authSession = AuthenticationSession.get(req as any);
|
|
||||||
authSession.userid = "user";
|
|
||||||
authSession.first_factor = true;
|
|
||||||
authSession.second_factor = false;
|
|
||||||
|
|
||||||
const mocks = ServerVariablesMock.mock(req.app);
|
const mocks = ServerVariablesMock.mock(req.app);
|
||||||
res = ExpressMock.ResponseMock();
|
res = ExpressMock.ResponseMock();
|
||||||
|
|
||||||
|
@ -52,6 +48,14 @@ describe("test totp route", function () {
|
||||||
mocks.logger = winston;
|
mocks.logger = winston;
|
||||||
mocks.totpValidator = totpValidator;
|
mocks.totpValidator = totpValidator;
|
||||||
mocks.config = config;
|
mocks.config = config;
|
||||||
|
|
||||||
|
return AuthenticationSession.get(req as any)
|
||||||
|
.then(function (_authSession: AuthenticationSession.AuthenticationSession) {
|
||||||
|
authSession = _authSession;
|
||||||
|
authSession.userid = "user";
|
||||||
|
authSession.first_factor = true;
|
||||||
|
authSession.second_factor = false;
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -23,11 +23,6 @@ describe("test register handler", function () {
|
||||||
mocks.logger = winston;
|
mocks.logger = winston;
|
||||||
req.session = {};
|
req.session = {};
|
||||||
AuthenticationSession.reset(req as any);
|
AuthenticationSession.reset(req as any);
|
||||||
authSession = AuthenticationSession.get(req as any);
|
|
||||||
authSession.userid = "user";
|
|
||||||
authSession.email = "user@example.com";
|
|
||||||
authSession.first_factor = true;
|
|
||||||
authSession.second_factor = false;
|
|
||||||
req.headers = {};
|
req.headers = {};
|
||||||
req.headers.host = "localhost";
|
req.headers.host = "localhost";
|
||||||
|
|
||||||
|
@ -44,6 +39,15 @@ describe("test register handler", function () {
|
||||||
res.send = sinon.spy();
|
res.send = sinon.spy();
|
||||||
res.json = sinon.spy();
|
res.json = sinon.spy();
|
||||||
res.status = sinon.spy();
|
res.status = sinon.spy();
|
||||||
|
|
||||||
|
return AuthenticationSession.get(req as any)
|
||||||
|
.then(function (_authSession: AuthenticationSession.AuthenticationSession) {
|
||||||
|
authSession = _authSession;
|
||||||
|
authSession.userid = "user";
|
||||||
|
authSession.email = "user@example.com";
|
||||||
|
authSession.first_factor = true;
|
||||||
|
authSession.second_factor = false;
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("test u2f registration check", test_registration_check);
|
describe("test u2f registration check", test_registration_check);
|
||||||
|
|
|
@ -17,7 +17,6 @@ describe("test u2f routes: register", function () {
|
||||||
let req: ExpressMock.RequestMock;
|
let req: ExpressMock.RequestMock;
|
||||||
let res: ExpressMock.ResponseMock;
|
let res: ExpressMock.ResponseMock;
|
||||||
let mocks: ServerVariablesMock.ServerVariablesMock;
|
let mocks: ServerVariablesMock.ServerVariablesMock;
|
||||||
let authSession: AuthenticationSession.AuthenticationSession;
|
|
||||||
|
|
||||||
beforeEach(function () {
|
beforeEach(function () {
|
||||||
req = ExpressMock.RequestMock();
|
req = ExpressMock.RequestMock();
|
||||||
|
@ -26,16 +25,6 @@ describe("test u2f routes: register", function () {
|
||||||
mocks.logger = winston;
|
mocks.logger = winston;
|
||||||
|
|
||||||
req.session = {};
|
req.session = {};
|
||||||
AuthenticationSession.reset(req as any);
|
|
||||||
authSession = AuthenticationSession.get(req as any);
|
|
||||||
authSession.userid = "user";
|
|
||||||
authSession.first_factor = true;
|
|
||||||
authSession.second_factor = false;
|
|
||||||
authSession.identity_check = {
|
|
||||||
challenge: "u2f-register",
|
|
||||||
userid: "user"
|
|
||||||
};
|
|
||||||
|
|
||||||
req.headers = {};
|
req.headers = {};
|
||||||
req.headers.host = "localhost";
|
req.headers.host = "localhost";
|
||||||
|
|
||||||
|
@ -50,6 +39,18 @@ describe("test u2f routes: register", function () {
|
||||||
res.send = sinon.spy();
|
res.send = sinon.spy();
|
||||||
res.json = sinon.spy();
|
res.json = sinon.spy();
|
||||||
res.status = sinon.spy();
|
res.status = sinon.spy();
|
||||||
|
|
||||||
|
AuthenticationSession.reset(req as any);
|
||||||
|
return AuthenticationSession.get(req as any)
|
||||||
|
.then(function (authSession: AuthenticationSession.AuthenticationSession) {
|
||||||
|
authSession.userid = "user";
|
||||||
|
authSession.first_factor = true;
|
||||||
|
authSession.second_factor = false;
|
||||||
|
authSession.identity_check = {
|
||||||
|
challenge: "u2f-register",
|
||||||
|
userid: "user"
|
||||||
|
};
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("test registration", test_registration);
|
describe("test registration", test_registration);
|
||||||
|
@ -64,16 +65,22 @@ describe("test u2f routes: register", function () {
|
||||||
};
|
};
|
||||||
const u2f_mock = U2FMock.U2FMock();
|
const u2f_mock = U2FMock.U2FMock();
|
||||||
u2f_mock.checkRegistration.returns(BluebirdPromise.resolve(expectedStatus));
|
u2f_mock.checkRegistration.returns(BluebirdPromise.resolve(expectedStatus));
|
||||||
|
|
||||||
authSession.register_request = {
|
|
||||||
appId: "app",
|
|
||||||
challenge: "challenge",
|
|
||||||
keyHandle: "key",
|
|
||||||
version: "U2F_V2"
|
|
||||||
};
|
|
||||||
mocks.u2f = u2f_mock;
|
mocks.u2f = u2f_mock;
|
||||||
return U2FRegisterPost.default(req as any, res as any)
|
|
||||||
|
return AuthenticationSession.get(req as any)
|
||||||
|
.then(function (authSession) {
|
||||||
|
authSession.register_request = {
|
||||||
|
appId: "app",
|
||||||
|
challenge: "challenge",
|
||||||
|
keyHandle: "key",
|
||||||
|
version: "U2F_V2"
|
||||||
|
};
|
||||||
|
return U2FRegisterPost.default(req as any, res as any);
|
||||||
|
})
|
||||||
.then(function () {
|
.then(function () {
|
||||||
|
return AuthenticationSession.get(req as any);
|
||||||
|
})
|
||||||
|
.then(function (authSession) {
|
||||||
assert.equal("user", mocks.userDataStore.saveU2FRegistrationStub.getCall(0).args[0]);
|
assert.equal("user", mocks.userDataStore.saveU2FRegistrationStub.getCall(0).args[0]);
|
||||||
assert.equal(authSession.identity_check, undefined);
|
assert.equal(authSession.identity_check, undefined);
|
||||||
});
|
});
|
||||||
|
@ -83,15 +90,19 @@ describe("test u2f routes: register", function () {
|
||||||
const user_key_container = {};
|
const user_key_container = {};
|
||||||
const u2f_mock = U2FMock.U2FMock();
|
const u2f_mock = U2FMock.U2FMock();
|
||||||
u2f_mock.checkRegistration.returns({ errorCode: 500 });
|
u2f_mock.checkRegistration.returns({ errorCode: 500 });
|
||||||
|
|
||||||
authSession.register_request = {
|
|
||||||
appId: "app",
|
|
||||||
challenge: "challenge",
|
|
||||||
keyHandle: "key",
|
|
||||||
version: "U2F_V2"
|
|
||||||
};
|
|
||||||
mocks.u2f = u2f_mock;
|
mocks.u2f = u2f_mock;
|
||||||
return U2FRegisterPost.default(req as any, res as any)
|
|
||||||
|
return AuthenticationSession.get(req as any)
|
||||||
|
.then(function (authSession) {
|
||||||
|
authSession.register_request = {
|
||||||
|
appId: "app",
|
||||||
|
challenge: "challenge",
|
||||||
|
keyHandle: "key",
|
||||||
|
version: "U2F_V2"
|
||||||
|
};
|
||||||
|
|
||||||
|
return U2FRegisterPost.default(req as any, res as any);
|
||||||
|
})
|
||||||
.then(function () { return BluebirdPromise.reject(new Error("It should fail")); })
|
.then(function () { return BluebirdPromise.reject(new Error("It should fail")); })
|
||||||
.catch(function () {
|
.catch(function () {
|
||||||
assert.equal(500, res.status.getCall(0).args[0]);
|
assert.equal(500, res.status.getCall(0).args[0]);
|
||||||
|
@ -104,9 +115,12 @@ describe("test u2f routes: register", function () {
|
||||||
const u2f_mock = U2FMock.U2FMock();
|
const u2f_mock = U2FMock.U2FMock();
|
||||||
u2f_mock.checkRegistration.returns(BluebirdPromise.resolve());
|
u2f_mock.checkRegistration.returns(BluebirdPromise.resolve());
|
||||||
|
|
||||||
authSession.register_request = undefined;
|
|
||||||
mocks.u2f = u2f_mock;
|
mocks.u2f = u2f_mock;
|
||||||
return U2FRegisterPost.default(req as any, res as any)
|
return AuthenticationSession.get(req as any)
|
||||||
|
.then(function (authSession) {
|
||||||
|
authSession.register_request = undefined;
|
||||||
|
return U2FRegisterPost.default(req as any, res as any);
|
||||||
|
})
|
||||||
.then(function () { return BluebirdPromise.reject(new Error("It should fail")); })
|
.then(function () { return BluebirdPromise.reject(new Error("It should fail")); })
|
||||||
.catch(function () {
|
.catch(function () {
|
||||||
assert.equal(403, res.status.getCall(0).args[0]);
|
assert.equal(403, res.status.getCall(0).args[0]);
|
||||||
|
@ -119,9 +133,12 @@ describe("test u2f routes: register", function () {
|
||||||
const u2f_mock = U2FMock.U2FMock();
|
const u2f_mock = U2FMock.U2FMock();
|
||||||
u2f_mock.checkRegistration.returns(BluebirdPromise.resolve());
|
u2f_mock.checkRegistration.returns(BluebirdPromise.resolve());
|
||||||
|
|
||||||
authSession.register_request = undefined;
|
|
||||||
mocks.u2f = u2f_mock;
|
mocks.u2f = u2f_mock;
|
||||||
return U2FRegisterPost.default(req as any, res as any)
|
return AuthenticationSession.get(req as any)
|
||||||
|
.then(function (authSession) {
|
||||||
|
authSession.register_request = undefined;
|
||||||
|
return U2FRegisterPost.default(req as any, res as any);
|
||||||
|
})
|
||||||
.then(function () { return BluebirdPromise.reject(new Error("It should fail")); })
|
.then(function () { return BluebirdPromise.reject(new Error("It should fail")); })
|
||||||
.catch(function () {
|
.catch(function () {
|
||||||
assert.equal(403, res.status.getCall(0).args[0]);
|
assert.equal(403, res.status.getCall(0).args[0]);
|
||||||
|
@ -130,8 +147,11 @@ describe("test u2f routes: register", function () {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should return forbidden error when identity has not been verified", function () {
|
it("should return forbidden error when identity has not been verified", function () {
|
||||||
authSession.identity_check = undefined;
|
return AuthenticationSession.get(req as any)
|
||||||
return U2FRegisterPost.default(req as any, res as any)
|
.then(function (authSession) {
|
||||||
|
authSession.identity_check = undefined;
|
||||||
|
return U2FRegisterPost.default(req as any, res as any);
|
||||||
|
})
|
||||||
.then(function () { return BluebirdPromise.reject(new Error("It should fail")); })
|
.then(function () { return BluebirdPromise.reject(new Error("It should fail")); })
|
||||||
.catch(function () {
|
.catch(function () {
|
||||||
assert.equal(403, res.status.getCall(0).args[0]);
|
assert.equal(403, res.status.getCall(0).args[0]);
|
||||||
|
|
|
@ -14,82 +14,84 @@ import ServerVariablesMock = require("../../../../mocks/ServerVariablesMock");
|
||||||
import U2f = require("u2f");
|
import U2f = require("u2f");
|
||||||
|
|
||||||
describe("test u2f routes: register_request", function () {
|
describe("test u2f routes: register_request", function () {
|
||||||
let req: ExpressMock.RequestMock;
|
let req: ExpressMock.RequestMock;
|
||||||
let res: ExpressMock.ResponseMock;
|
let res: ExpressMock.ResponseMock;
|
||||||
let mocks: ServerVariablesMock.ServerVariablesMock;
|
let mocks: ServerVariablesMock.ServerVariablesMock;
|
||||||
let authSession: AuthenticationSession.AuthenticationSession;
|
let authSession: AuthenticationSession.AuthenticationSession;
|
||||||
|
|
||||||
beforeEach(function () {
|
beforeEach(function () {
|
||||||
req = ExpressMock.RequestMock();
|
req = ExpressMock.RequestMock();
|
||||||
req.app = {};
|
req.app = {};
|
||||||
mocks = ServerVariablesMock.mock(req.app);
|
mocks = ServerVariablesMock.mock(req.app);
|
||||||
mocks.logger = winston;
|
mocks.logger = winston;
|
||||||
req.session = {};
|
req.session = {};
|
||||||
AuthenticationSession.reset(req as any);
|
AuthenticationSession.reset(req as any);
|
||||||
authSession = AuthenticationSession.get(req as any);
|
|
||||||
|
|
||||||
|
req.headers = {};
|
||||||
|
req.headers.host = "localhost";
|
||||||
|
|
||||||
|
const options = {
|
||||||
|
inMemoryOnly: true
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
mocks.userDataStore.saveU2FRegistrationStub.returns(BluebirdPromise.resolve({}));
|
||||||
|
mocks.userDataStore.retrieveU2FRegistrationStub.returns(BluebirdPromise.resolve({}));
|
||||||
|
|
||||||
|
res = ExpressMock.ResponseMock();
|
||||||
|
res.send = sinon.spy();
|
||||||
|
res.json = sinon.spy();
|
||||||
|
res.status = sinon.spy();
|
||||||
|
|
||||||
|
return AuthenticationSession.get(req as any)
|
||||||
|
.then(function (_authSession: AuthenticationSession.AuthenticationSession) {
|
||||||
|
authSession = _authSession;
|
||||||
authSession.userid = "user";
|
authSession.userid = "user";
|
||||||
authSession.first_factor = true;
|
authSession.first_factor = true;
|
||||||
authSession.second_factor = false;
|
authSession.second_factor = false;
|
||||||
authSession.identity_check = {
|
authSession.identity_check = {
|
||||||
challenge: "u2f-register",
|
challenge: "u2f-register",
|
||||||
userid: "user"
|
userid: "user"
|
||||||
};
|
};
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
req.headers = {};
|
describe("test registration request", () => {
|
||||||
req.headers.host = "localhost";
|
it("should send back the registration request and save it in the session", function () {
|
||||||
|
const expectedRequest = {
|
||||||
|
test: "abc"
|
||||||
|
};
|
||||||
|
const user_key_container = {};
|
||||||
|
const u2f_mock = U2FMock.U2FMock();
|
||||||
|
u2f_mock.request.returns(BluebirdPromise.resolve(expectedRequest));
|
||||||
|
|
||||||
const options = {
|
mocks.u2f = u2f_mock;
|
||||||
inMemoryOnly: true
|
return U2FRegisterRequestGet.default(req as any, res as any)
|
||||||
};
|
.then(function () {
|
||||||
|
assert.deepEqual(expectedRequest, res.json.getCall(0).args[0]);
|
||||||
|
});
|
||||||
mocks.userDataStore.saveU2FRegistrationStub.returns(BluebirdPromise.resolve({}));
|
|
||||||
mocks.userDataStore.retrieveU2FRegistrationStub.returns(BluebirdPromise.resolve({}));
|
|
||||||
|
|
||||||
res = ExpressMock.ResponseMock();
|
|
||||||
res.send = sinon.spy();
|
|
||||||
res.json = sinon.spy();
|
|
||||||
res.status = sinon.spy();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("test registration request", () => {
|
it("should return internal error on registration request", function (done) {
|
||||||
it("should send back the registration request and save it in the session", function () {
|
res.send = sinon.spy(function (data: any) {
|
||||||
const expectedRequest = {
|
assert.equal(500, res.status.getCall(0).args[0]);
|
||||||
test: "abc"
|
done();
|
||||||
};
|
});
|
||||||
const user_key_container = {};
|
const user_key_container = {};
|
||||||
const u2f_mock = U2FMock.U2FMock();
|
const u2f_mock = U2FMock.U2FMock();
|
||||||
u2f_mock.request.returns(BluebirdPromise.resolve(expectedRequest));
|
u2f_mock.request.returns(BluebirdPromise.reject("Internal error"));
|
||||||
|
|
||||||
mocks.u2f = u2f_mock;
|
mocks.u2f = u2f_mock;
|
||||||
return U2FRegisterRequestGet.default(req as any, res as any)
|
U2FRegisterRequestGet.default(req as any, res as any);
|
||||||
.then(function () {
|
});
|
||||||
assert.deepEqual(expectedRequest, res.json.getCall(0).args[0]);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should return internal error on registration request", function (done) {
|
it("should return forbidden if identity has not been verified", function () {
|
||||||
res.send = sinon.spy(function (data: any) {
|
authSession.identity_check = undefined;
|
||||||
assert.equal(500, res.status.getCall(0).args[0]);
|
return U2FRegisterRequestGet.default(req as any, res as any)
|
||||||
done();
|
.then(function () {
|
||||||
});
|
assert.equal(403, res.status.getCall(0).args[0]);
|
||||||
const user_key_container = {};
|
|
||||||
const u2f_mock = U2FMock.U2FMock();
|
|
||||||
u2f_mock.request.returns(BluebirdPromise.reject("Internal error"));
|
|
||||||
|
|
||||||
mocks.u2f = u2f_mock;
|
|
||||||
U2FRegisterRequestGet.default(req as any, res as any);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should return forbidden if identity has not been verified", function (done) {
|
|
||||||
res.send = sinon.spy(function (data: any) {
|
|
||||||
assert.equal(403, res.status.getCall(0).args[0]);
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
authSession.identity_check = undefined;
|
|
||||||
U2FRegisterRequestGet.default(req as any, res as any);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -27,14 +27,6 @@ describe("test u2f routes: sign", function () {
|
||||||
|
|
||||||
req.session = {};
|
req.session = {};
|
||||||
AuthenticationSession.reset(req as any);
|
AuthenticationSession.reset(req as any);
|
||||||
authSession = AuthenticationSession.get(req as any);
|
|
||||||
authSession.userid = "user";
|
|
||||||
authSession.first_factor = true;
|
|
||||||
authSession.second_factor = false;
|
|
||||||
authSession.identity_check = {
|
|
||||||
challenge: "u2f-register",
|
|
||||||
userid: "user"
|
|
||||||
};
|
|
||||||
req.headers = {};
|
req.headers = {};
|
||||||
req.headers.host = "localhost";
|
req.headers.host = "localhost";
|
||||||
|
|
||||||
|
@ -46,6 +38,18 @@ describe("test u2f routes: sign", function () {
|
||||||
res.send = sinon.spy();
|
res.send = sinon.spy();
|
||||||
res.json = sinon.spy();
|
res.json = sinon.spy();
|
||||||
res.status = sinon.spy();
|
res.status = sinon.spy();
|
||||||
|
|
||||||
|
return AuthenticationSession.get(req as any)
|
||||||
|
.then(function (_authSession: AuthenticationSession.AuthenticationSession) {
|
||||||
|
authSession = _authSession;
|
||||||
|
authSession.userid = "user";
|
||||||
|
authSession.first_factor = true;
|
||||||
|
authSession.second_factor = false;
|
||||||
|
authSession.identity_check = {
|
||||||
|
challenge: "u2f-register",
|
||||||
|
userid: "user"
|
||||||
|
};
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should return status code 204", function () {
|
it("should return status code 204", function () {
|
||||||
|
|
|
@ -31,14 +31,6 @@ describe("test u2f routes: sign_request", function () {
|
||||||
req.session = {};
|
req.session = {};
|
||||||
|
|
||||||
AuthenticationSession.reset(req as any);
|
AuthenticationSession.reset(req as any);
|
||||||
authSession = AuthenticationSession.get(req as any);
|
|
||||||
authSession.userid = "user";
|
|
||||||
authSession.first_factor = true;
|
|
||||||
authSession.second_factor = false;
|
|
||||||
authSession.identity_check = {
|
|
||||||
challenge: "u2f-register",
|
|
||||||
userid: "user"
|
|
||||||
};
|
|
||||||
|
|
||||||
req.headers = {};
|
req.headers = {};
|
||||||
req.headers.host = "localhost";
|
req.headers.host = "localhost";
|
||||||
|
@ -51,6 +43,18 @@ describe("test u2f routes: sign_request", function () {
|
||||||
res.send = sinon.spy();
|
res.send = sinon.spy();
|
||||||
res.json = sinon.spy();
|
res.json = sinon.spy();
|
||||||
res.status = sinon.spy();
|
res.status = sinon.spy();
|
||||||
|
|
||||||
|
return AuthenticationSession.get(req as any)
|
||||||
|
.then(function (_authSession: AuthenticationSession.AuthenticationSession) {
|
||||||
|
authSession = _authSession;
|
||||||
|
authSession.userid = "user";
|
||||||
|
authSession.first_factor = true;
|
||||||
|
authSession.second_factor = false;
|
||||||
|
authSession.identity_check = {
|
||||||
|
challenge: "u2f-register",
|
||||||
|
userid: "user"
|
||||||
|
};
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should send back the sign request and save it in the session", function () {
|
it("should send back the sign request and save it in the session", function () {
|
||||||
|
|
|
@ -24,6 +24,9 @@ describe("test authentication token verification", function () {
|
||||||
|
|
||||||
req = ExpressMock.RequestMock();
|
req = ExpressMock.RequestMock();
|
||||||
res = ExpressMock.ResponseMock();
|
res = ExpressMock.ResponseMock();
|
||||||
|
req.app = {
|
||||||
|
get: sinon.stub().returns({ logger: winston })
|
||||||
|
};
|
||||||
req.session = {};
|
req.session = {};
|
||||||
AuthenticationSession.reset(req as any);
|
AuthenticationSession.reset(req as any);
|
||||||
req.headers = {};
|
req.headers = {};
|
||||||
|
@ -37,12 +40,13 @@ describe("test authentication token verification", function () {
|
||||||
it("should be already authenticated", function () {
|
it("should be already authenticated", function () {
|
||||||
req.session = {};
|
req.session = {};
|
||||||
AuthenticationSession.reset(req as any);
|
AuthenticationSession.reset(req as any);
|
||||||
const authSession = AuthenticationSession.get(req as any);
|
return AuthenticationSession.get(req as any)
|
||||||
authSession.first_factor = true;
|
.then(function (authSession: AuthenticationSession.AuthenticationSession) {
|
||||||
authSession.second_factor = true;
|
authSession.first_factor = true;
|
||||||
authSession.userid = "myuser";
|
authSession.second_factor = true;
|
||||||
|
authSession.userid = "myuser";
|
||||||
return VerifyGet.default(req as express.Request, res as any)
|
return VerifyGet.default(req as express.Request, res as any);
|
||||||
|
})
|
||||||
.then(function () {
|
.then(function () {
|
||||||
assert.equal(204, res.status.getCall(0).args[0]);
|
assert.equal(204, res.status.getCall(0).args[0]);
|
||||||
});
|
});
|
||||||
|
@ -113,23 +117,25 @@ describe("test authentication token verification", function () {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should not be authenticated when domain is not allowed for user", function () {
|
it("should not be authenticated when domain is not allowed for user", function () {
|
||||||
const authSession = AuthenticationSession.get(req as any);
|
return AuthenticationSession.get(req as any)
|
||||||
authSession.first_factor = true;
|
.then(function (authSession: AuthenticationSession.AuthenticationSession) {
|
||||||
authSession.second_factor = true;
|
authSession.first_factor = true;
|
||||||
authSession.userid = "myuser";
|
authSession.second_factor = true;
|
||||||
|
authSession.userid = "myuser";
|
||||||
|
|
||||||
req.headers.host = "test.example.com";
|
req.headers.host = "test.example.com";
|
||||||
|
|
||||||
accessController.isDomainAllowedForUser.returns(false);
|
accessController.isDomainAllowedForUser.returns(false);
|
||||||
accessController.isDomainAllowedForUser.withArgs("test.example.com", "user", ["group1", "group2"]).returns(true);
|
accessController.isDomainAllowedForUser.withArgs("test.example.com", "user", ["group1", "group2"]).returns(true);
|
||||||
|
|
||||||
return test_unauthorized_403({
|
return test_unauthorized_403({
|
||||||
first_factor: true,
|
first_factor: true,
|
||||||
second_factor: true,
|
second_factor: true,
|
||||||
userid: "user",
|
userid: "user",
|
||||||
groups: ["group1", "group2"],
|
groups: ["group1", "group2"],
|
||||||
email: undefined
|
email: undefined
|
||||||
});
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue