mirror of
https://github.com/0rangebananaspy/authelia.git
synced 2024-09-14 22:47:21 +07:00
Merge pull request #89 from clems4ever/redis-connection-issue-logs
Make failing connection to redis more clear in the logs
This commit is contained in:
commit
ae5b647d23
|
@ -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
|
||||||
|
@ -44,4 +42,4 @@ Feature: User is correctly redirected
|
||||||
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 "Sec0" 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"
|
||||||
|
|
|
@ -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
Block a user