Add default_redirection_url as configuration option

This URL is used when user access the authentication domain without providing
the 'redirect' query parameter. In that case, Authelia does not know
where to redirect the user.
If the parameter is defined, Authelia can redirect the user to a default page
when no redirect parameter is provided.

When user is already authenticated and tries to access the authentication
domain, the "already logged in" page is rendered and it now tells the user he
is to be redirected in few seconds and uses this URL to redirect.

This parameter is optional. If it is not provided, there is only a notification
message at the end of the authentication process, as before, and the user is
not redirected when visiting the authentication domain while already
authenticated.
This commit is contained in:
Clement Michaud 2017-10-17 23:24:02 +02:00
parent 99b04809a5
commit 563e2da323
53 changed files with 834 additions and 920 deletions

View File

@ -1,6 +1,8 @@
import BluebirdPromise = require("bluebird");
import Endpoints = require("../../../../shared/api");
import { RedirectionMessage } from "../../../../shared/RedirectionMessage";
import { ErrorMessage } from "../../../../shared/ErrorMessage";
export function validate(token: string, $: JQueryStatic): BluebirdPromise<string> {
return new BluebirdPromise<string>(function (resolve, reject) {
@ -12,12 +14,12 @@ export function validate(token: string, $: JQueryStatic): BluebirdPromise<string
method: "POST",
dataType: "json"
} as JQueryAjaxSettings)
.done(function (body: any) {
if (body && body.error) {
reject(new Error(body.error));
.done(function (body: RedirectionMessage | ErrorMessage) {
if (body && "error" in body) {
reject(new Error((body as ErrorMessage).error));
return;
}
resolve(body);
resolve((body as RedirectionMessage).redirect);
})
.fail(function (xhr: JQueryXHR, textStatus: string) {
reject(new Error(textStatus));

View File

@ -6,21 +6,23 @@ import { SignMessage } from "../../../../shared/SignMessage";
import Endpoints = require("../../../../shared/api");
import UserMessages = require("../../../../shared/UserMessages");
import { INotifier } from "../INotifier";
import { RedirectionMessage } from "../../../../shared/RedirectionMessage";
import { ErrorMessage } from "../../../../shared/ErrorMessage";
function finishU2fAuthentication(responseData: U2fApi.SignResponse, $: JQueryStatic): BluebirdPromise<void> {
return new BluebirdPromise<void>(function (resolve, reject) {
function finishU2fAuthentication(responseData: U2fApi.SignResponse, $: JQueryStatic): BluebirdPromise<string> {
return new BluebirdPromise<string>(function (resolve, reject) {
$.ajax({
url: Endpoints.SECOND_FACTOR_U2F_SIGN_POST,
data: responseData,
method: "POST",
dataType: "json"
} as JQueryAjaxSettings)
.done(function (body: any) {
if (body && body.error) {
reject(new Error(body.error));
.done(function (body: RedirectionMessage | ErrorMessage) {
if (body && "error" in body) {
reject(new Error((body as ErrorMessage).error));
return;
}
resolve(body);
resolve((body as RedirectionMessage).redirect);
})
.fail(function (xhr: JQueryXHR, textStatus: string) {
reject(new Error(textStatus));
@ -28,8 +30,8 @@ function finishU2fAuthentication(responseData: U2fApi.SignResponse, $: JQuerySta
});
}
function startU2fAuthentication($: JQueryStatic, notifier: INotifier, u2fApi: typeof U2fApi): BluebirdPromise<void> {
return new BluebirdPromise<void>(function (resolve, reject) {
function startU2fAuthentication($: JQueryStatic, notifier: INotifier, u2fApi: typeof U2fApi): BluebirdPromise<string> {
return new BluebirdPromise<string>(function (resolve, reject) {
$.get(Endpoints.SECOND_FACTOR_U2F_SIGN_REQUEST_GET, {}, undefined, "json")
.done(function (signResponse: SignMessage) {
notifier.info(UserMessages.PLEASE_TOUCH_TOKEN);
@ -44,8 +46,8 @@ function startU2fAuthentication($: JQueryStatic, notifier: INotifier, u2fApi: ty
u2fApi.sign([signRequest], 60)
.then(function (signResponse: U2fApi.SignResponse) {
finishU2fAuthentication(signResponse, $)
.then(function (data) {
resolve(data);
.then(function (redirect: string) {
resolve(redirect);
}, function (err) {
notifier.error(UserMessages.U2F_TRANSACTION_FINISH_FAILED);
reject(err);
@ -62,6 +64,6 @@ function startU2fAuthentication($: JQueryStatic, notifier: INotifier, u2fApi: ty
}
export function validate($: JQueryStatic, notifier: INotifier, u2fApi: typeof U2fApi): BluebirdPromise<void> {
export function validate($: JQueryStatic, notifier: INotifier, u2fApi: typeof U2fApi): BluebirdPromise<string> {
return startU2fAuthentication($, notifier, u2fApi);
}

View File

@ -4,35 +4,37 @@ import jslogger = require("js-logger");
import TOTPValidator = require("./TOTPValidator");
import U2FValidator = require("./U2FValidator");
import Constants = require("./constants");
import ClientConstants = require("./constants");
import { Notifier } from "../Notifier";
import { QueryParametersRetriever } from "../QueryParametersRetriever";
import Endpoints = require("../../../../shared/api");
import ServerConstants = require("../../../../shared/constants");
import UserMessages = require("../../../../shared/UserMessages");
import SharedConstants = require("../../../../shared/constants");
export default function (window: Window, $: JQueryStatic, u2fApi: typeof U2fApi) {
const notifierTotp = new Notifier(".notification-totp", $);
const notifierU2f = new Notifier(".notification-u2f", $);
function onAuthenticationSuccess(data: any, notifier: Notifier) {
const redirectUrl = QueryParametersRetriever.get(ServerConstants.REDIRECT_QUERY_PARAM);
if (redirectUrl)
window.location.href = redirectUrl;
function onAuthenticationSuccess(serverRedirectUrl: string, notifier: Notifier) {
if (QueryParametersRetriever.get(SharedConstants.REDIRECT_QUERY_PARAM))
window.location.href = QueryParametersRetriever.get(SharedConstants.REDIRECT_QUERY_PARAM);
else if (serverRedirectUrl)
window.location.href = serverRedirectUrl;
else
notifier.success(UserMessages.AUTHENTICATION_SUCCEEDED);
}
function onSecondFactorTotpSuccess(data: any) {
onAuthenticationSuccess(data, notifierTotp);
function onSecondFactorTotpSuccess(redirectUrl: string) {
onAuthenticationSuccess(redirectUrl, notifierTotp);
}
function onSecondFactorTotpFailure(err: Error) {
notifierTotp.error(UserMessages.AUTHENTICATION_TOTP_FAILED);
}
function onU2fAuthenticationSuccess(data: any) {
onAuthenticationSuccess(data, notifierU2f);
function onU2fAuthenticationSuccess(redirectUrl: string) {
onAuthenticationSuccess(redirectUrl, notifierU2f);
}
function onU2fAuthenticationFailure() {
@ -40,7 +42,7 @@ export default function (window: Window, $: JQueryStatic, u2fApi: typeof U2fApi)
}
function onTOTPFormSubmitted(): boolean {
const token = $(Constants.TOTP_TOKEN_SELECTOR).val();
const token = $(ClientConstants.TOTP_TOKEN_SELECTOR).val();
TOTPValidator.validate(token, $)
.then(onSecondFactorTotpSuccess)
.catch(onSecondFactorTotpFailure);
@ -54,7 +56,7 @@ export default function (window: Window, $: JQueryStatic, u2fApi: typeof U2fApi)
}
$(window.document).ready(function () {
$(Constants.TOTP_FORM_SELECTOR).on("submit", onTOTPFormSubmitted);
$(Constants.U2F_FORM_SELECTOR).on("submit", onU2FFormSubmitted);
$(ClientConstants.TOTP_FORM_SELECTOR).on("submit", onTOTPFormSubmitted);
$(ClientConstants.U2F_FORM_SELECTOR).on("submit", onU2FFormSubmitted);
});
}

View File

@ -6,6 +6,8 @@ import jslogger = require("js-logger");
import { Notifier } from "../Notifier";
import Endpoints = require("../../../../shared/api");
import UserMessages = require("../../../../shared/UserMessages");
import { RedirectionMessage } from "../../../../shared/RedirectionMessage";
import { ErrorMessage } from "../../../../shared/ErrorMessage";
export default function (window: Window, $: JQueryStatic) {
const notifier = new Notifier(".notification", $);
@ -17,12 +19,12 @@ export default function (window: Window, $: JQueryStatic) {
return new BluebirdPromise<string>(function (resolve, reject) {
$.post(Endpoints.SECOND_FACTOR_U2F_REGISTER_POST, registrationData, undefined, "json")
.done(function (body: any) {
if (body && body.error) {
reject(new Error(body.error));
.done(function (body: RedirectionMessage | ErrorMessage) {
if (body && "error" in body) {
reject(new Error((body as ErrorMessage).error));
return;
}
resolve(body.redirection_url);
resolve((body as RedirectionMessage).redirect);
})
.fail(function (xhr, status) {
reject();

View File

@ -7,7 +7,7 @@ import Assert = require("assert");
describe("test TOTPValidator", function () {
it("should initiate an identity check successfully", () => {
const postPromise = JQueryMock.JQueryDeferredMock();
postPromise.done.yields();
postPromise.done.yields({ redirect: "https://home.test.url" });
postPromise.done.returns(postPromise);
const jqueryMock = JQueryMock.JQueryMock();

View File

@ -32,7 +32,7 @@ describe("test U2F validation", function () {
getPromise.done.returns(getPromise);
const postPromise = JQueryMock.JQueryDeferredMock();
postPromise.done.yields();
postPromise.done.yields({ redirect: "https://home.test.url" });
postPromise.done.returns(postPromise);
const jqueryMock = JQueryMock.JQueryMock();

View File

@ -10,6 +10,18 @@ port: 80
# Level of verbosity for logs
logs_level: debug
# Default redirection URL
#
# If user tries to authenticate without any referer, Authelia
# does not know where to redirect the user to at the end of the
# authentication process.
# This parameter allows you to specify the default redirection
# URL Authelia will use in such a case.
#
# Note: this parameter is optional. If not provided, user won't
# be redirected upon successful authentication.
default_redirection_url: https://home.test.local:8080/
# LDAP configuration
#
# Example: for user john, the DN will be cn=john,ou=users,dc=example,dc=com

View File

@ -2,24 +2,9 @@
import express = require("express");
import U2f = require("u2f");
import { ServerVariablesHandler } from "./ServerVariablesHandler";
import BluebirdPromise = require("bluebird");
export interface AuthenticationSession {
userid: string;
first_factor: boolean;
second_factor: boolean;
last_activity_datetime: number;
identity_check?: {
challenge: string;
userid: string;
};
register_request?: U2f.Request;
sign_request?: U2f.Request;
email: string;
groups: string[];
redirect?: string;
}
import { AuthenticationSession } from "../../types/AuthenticationSession";
import { IRequestLogger } from "./logging/IRequestLogger";
const INITIAL_AUTHENTICATION_SESSION: AuthenticationSession = {
first_factor: false,
@ -35,16 +20,13 @@ const INITIAL_AUTHENTICATION_SESSION: AuthenticationSession = {
};
export function reset(req: express.Request): void {
const logger = ServerVariablesHandler.getLogger(req.app);
logger.debug(req, "Authentication session %s is being reset.", req.sessionID);
req.session.auth = Object.assign({}, INITIAL_AUTHENTICATION_SESSION, {});
// Initialize last activity with current time
req.session.auth.last_activity_datetime = new Date().getTime();
}
export function get(req: express.Request): BluebirdPromise<AuthenticationSession> {
const logger = ServerVariablesHandler.getLogger(req.app);
export function get(req: express.Request, logger: IRequestLogger): BluebirdPromise<AuthenticationSession> {
if (!req.session) {
const errorMsg = "Something is wrong with session cookies. Please check Redis is running and Authelia can contact it.";
logger.error(req, errorMsg);

View File

@ -2,16 +2,16 @@
import BluebirdPromise = require("bluebird");
import express = require("express");
import objectPath = require("object-path");
import FirstFactorValidator = require("./FirstFactorValidator");
import AuthenticationSession = require("./AuthenticationSession");
import AuthenticationSessionHandler = require("./AuthenticationSession");
import { IRequestLogger } from "./logging/IRequestLogger";
export function validate(req: express.Request): BluebirdPromise<void> {
return FirstFactorValidator.validate(req)
export function validate(req: express.Request, logger: IRequestLogger): BluebirdPromise<void> {
return FirstFactorValidator.validate(req, logger)
.then(function () {
return AuthenticationSession.get(req);
return AuthenticationSessionHandler.get(req, logger);
})
.then(function (authSession: AuthenticationSession.AuthenticationSession) {
.then(function (authSession) {
if (!authSession.second_factor)
return BluebirdPromise.reject("No second factor variable.");
return BluebirdPromise.resolve();

View File

@ -3,11 +3,12 @@ import BluebirdPromise = require("bluebird");
import express = require("express");
import objectPath = require("object-path");
import Exceptions = require("./Exceptions");
import AuthenticationSession = require("./AuthenticationSession");
import AuthenticationSessionHandler = require("./AuthenticationSession");
import { IRequestLogger } from "./logging/IRequestLogger";
export function validate(req: express.Request): BluebirdPromise<void> {
return AuthenticationSession.get(req)
.then(function (authSession: AuthenticationSession.AuthenticationSession) {
export function validate(req: express.Request, logger: IRequestLogger): BluebirdPromise<void> {
return AuthenticationSessionHandler.get(req, logger)
.then(function (authSession) {
if (!authSession.userid || !authSession.first_factor)
return BluebirdPromise.reject(
new Exceptions.FirstFactorValidationError(

View File

@ -10,8 +10,9 @@ import { IUserDataStore } from "./storage/IUserDataStore";
import { Winston } from "../../types/Dependencies";
import express = require("express");
import ErrorReplies = require("./ErrorReplies");
import { ServerVariablesHandler } from "./ServerVariablesHandler";
import AuthenticationSession = require("./AuthenticationSession");
import AuthenticationSessionHandler = require("./AuthenticationSession");
import { AuthenticationSession } from "../../types/AuthenticationSession";
import { ServerVariables } from "./ServerVariables";
import Identity = require("../../types/Identity");
import { IdentityValidationDocument } from "./storage/IdentityValidationDocument";
@ -53,9 +54,9 @@ function consumeToken(token: string, challenge: string, userDataStore: IUserData
}
export function register(app: express.Application, pre_validation_endpoint: string,
post_validation_endpoint: string, handler: IdentityValidable) {
app.get(pre_validation_endpoint, get_start_validation(handler, post_validation_endpoint));
app.get(post_validation_endpoint, get_finish_validation(handler));
post_validation_endpoint: string, handler: IdentityValidable, vars: ServerVariables) {
app.get(pre_validation_endpoint, get_start_validation(handler, post_validation_endpoint, vars));
app.get(post_validation_endpoint, get_finish_validation(handler, vars));
}
function checkIdentityToken(req: express.Request, identityToken: string): BluebirdPromise<void> {
@ -64,27 +65,26 @@ function checkIdentityToken(req: express.Request, identityToken: string): Bluebi
return BluebirdPromise.resolve();
}
export function get_finish_validation(handler: IdentityValidable): express.RequestHandler {
export function get_finish_validation(handler: IdentityValidable,
vars: ServerVariables)
: express.RequestHandler {
return function (req: express.Request, res: express.Response): BluebirdPromise<void> {
const logger = ServerVariablesHandler.getLogger(req.app);
const userDataStore = ServerVariablesHandler.getUserDataStore(req.app);
let authSession: AuthenticationSession.AuthenticationSession;
let authSession: AuthenticationSession;
const identityToken = objectPath.get<express.Request, string>(req, "query.identity_token");
logger.debug(req, "Identity token provided is %s", identityToken);
vars.logger.debug(req, "Identity token provided is %s", identityToken);
return checkIdentityToken(req, identityToken)
.then(function () {
return handler.postValidationInit(req);
})
.then(function () {
return AuthenticationSession.get(req);
return AuthenticationSessionHandler.get(req, vars.logger);
})
.then(function (_authSession: AuthenticationSession.AuthenticationSession) {
.then(function (_authSession) {
authSession = _authSession;
})
.then(function () {
return consumeToken(identityToken, handler.challenge(), userDataStore);
return consumeToken(identityToken, handler.challenge(), vars.userDataStore);
})
.then(function (doc: IdentityValidationDocument) {
authSession.identity_check = {
@ -94,17 +94,16 @@ export function get_finish_validation(handler: IdentityValidable): express.Reque
handler.postValidationResponse(req, res);
return BluebirdPromise.resolve();
})
.catch(ErrorReplies.replyWithError401(req, res, logger));
.catch(ErrorReplies.replyWithError401(req, res, vars.logger));
};
}
export function get_start_validation(handler: IdentityValidable, postValidationEndpoint: string)
export function get_start_validation(handler: IdentityValidable,
postValidationEndpoint: string,
vars: ServerVariables)
: express.RequestHandler {
return function (req: express.Request, res: express.Response): BluebirdPromise<void> {
const logger = ServerVariablesHandler.getLogger(req.app);
const notifier = ServerVariablesHandler.getNotifier(req.app);
const userDataStore = ServerVariablesHandler.getUserDataStore(req.app);
let identity: Identity.Identity;
return handler.preValidationInit(req)
@ -112,25 +111,25 @@ export function get_start_validation(handler: IdentityValidable, postValidationE
identity = id;
const email = identity.email;
const userid = identity.userid;
logger.info(req, "Start identity validation of user \"%s\"", userid);
vars.logger.info(req, "Start identity validation of user \"%s\"", userid);
if (!(email && userid))
return BluebirdPromise.reject(new Exceptions.IdentityError(
"Missing user id or email address"));
return createAndSaveToken(userid, handler.challenge(), userDataStore);
return createAndSaveToken(userid, handler.challenge(), vars.userDataStore);
})
.then(function (token: string) {
const host = req.get("Host");
const link_url = util.format("https://%s%s?identity_token=%s", host,
postValidationEndpoint, token);
logger.info(req, "Notification sent to user \"%s\"", identity.userid);
return notifier.notify(identity.email, handler.mailSubject(), link_url);
vars.logger.info(req, "Notification sent to user \"%s\"", identity.userid);
return vars.notifier.notify(identity.email, handler.mailSubject(), link_url);
})
.then(function () {
handler.preValidationResponse(req, res);
return BluebirdPromise.resolve();
})
.catch(ErrorReplies.replyWithError401(req, res, logger));
.catch(ErrorReplies.replyWithError401(req, res, vars.logger));
};
}

View File

@ -32,14 +32,14 @@ import Error404Get = require("./routes/error/404/get");
import LoggedIn = require("./routes/loggedin/get");
import { ServerVariablesHandler } from "./ServerVariablesHandler";
import { ServerVariables } from "./ServerVariables";
import { IRequestLogger } from "./logging/IRequestLogger";
import Endpoints = require("../../../shared/api");
function withLog(fn: (req: Express.Request, res: Express.Response) => void) {
return function(req: Express.Request, res: Express.Response) {
const logger = ServerVariablesHandler.getLogger(req.app);
function withHeadersLogged(fn: (req: Express.Request, res: Express.Response) => void,
logger: IRequestLogger) {
return function (req: Express.Request, res: Express.Response) {
logger.debug(req, "Headers = %s", JSON.stringify(req.headers));
fn(req, res);
};
@ -47,35 +47,38 @@ function withLog(fn: (req: Express.Request, res: Express.Response) => void) {
export class RestApi {
static setup(app: Express.Application, vars: ServerVariables): void {
app.get(Endpoints.FIRST_FACTOR_GET, withLog(FirstFactorGet.default));
app.get(Endpoints.SECOND_FACTOR_GET, withLog(SecondFactorGet.default));
app.get(Endpoints.LOGOUT_GET, withLog(LogoutGet.default));
app.get(Endpoints.FIRST_FACTOR_GET, withHeadersLogged(FirstFactorGet.default(vars), vars.logger));
app.get(Endpoints.SECOND_FACTOR_GET, withHeadersLogged(SecondFactorGet.default(vars), vars.logger));
app.get(Endpoints.LOGOUT_GET, withHeadersLogged(LogoutGet.default, vars.logger));
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(vars.logger, vars.userDataStore, vars.totpHandler), vars);
IdentityCheckMiddleware.register(app, Endpoints.SECOND_FACTOR_U2F_IDENTITY_START_GET,
Endpoints.SECOND_FACTOR_U2F_IDENTITY_FINISH_GET, new U2FRegistrationIdentityHandler());
Endpoints.SECOND_FACTOR_U2F_IDENTITY_FINISH_GET,
new U2FRegistrationIdentityHandler(vars.logger), vars);
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(vars.logger, vars.ldapEmailsRetriever), vars);
app.get(Endpoints.RESET_PASSWORD_REQUEST_GET, withLog(ResetPasswordRequestPost.default));
app.post(Endpoints.RESET_PASSWORD_FORM_POST, withLog(ResetPasswordFormPost.default));
app.get(Endpoints.RESET_PASSWORD_REQUEST_GET, withHeadersLogged(ResetPasswordRequestPost.default, vars.logger));
app.post(Endpoints.RESET_PASSWORD_FORM_POST, withHeadersLogged(ResetPasswordFormPost.default(vars), vars.logger));
app.get(Endpoints.VERIFY_GET, withLog(VerifyGet.default(vars)));
app.post(Endpoints.FIRST_FACTOR_POST, withLog(FirstFactorPost.default(vars)));
app.post(Endpoints.SECOND_FACTOR_TOTP_POST, withLog(TOTPSignGet.default(vars)));
app.get(Endpoints.VERIFY_GET, withHeadersLogged(VerifyGet.default(vars), vars.logger));
app.post(Endpoints.FIRST_FACTOR_POST, withHeadersLogged(FirstFactorPost.default(vars), vars.logger));
app.post(Endpoints.SECOND_FACTOR_TOTP_POST, withHeadersLogged(TOTPSignGet.default(vars), vars.logger));
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_SIGN_REQUEST_GET, withHeadersLogged(U2FSignRequestGet.default(vars), vars.logger));
app.post(Endpoints.SECOND_FACTOR_U2F_SIGN_POST, withHeadersLogged(U2FSignPost.default(vars), vars.logger));
app.get(Endpoints.SECOND_FACTOR_U2F_REGISTER_REQUEST_GET, withLog(U2FRegisterRequestGet.default));
app.post(Endpoints.SECOND_FACTOR_U2F_REGISTER_POST, withLog(U2FRegisterPost.default));
app.get(Endpoints.SECOND_FACTOR_U2F_REGISTER_REQUEST_GET, withHeadersLogged(U2FRegisterRequestGet.default(vars), vars.logger));
app.post(Endpoints.SECOND_FACTOR_U2F_REGISTER_POST, withHeadersLogged(U2FRegisterPost.default(vars), vars.logger));
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.LOGGED_IN, withLog(LoggedIn.default));
app.get(Endpoints.ERROR_401_GET, withHeadersLogged(Error401Get.default, vars.logger));
app.get(Endpoints.ERROR_403_GET, withHeadersLogged(Error403Get.default, vars.logger));
app.get(Endpoints.ERROR_404_GET, withHeadersLogged(Error404Get.default, vars.logger));
app.get(Endpoints.LOGGED_IN, withHeadersLogged(LoggedIn.default(vars), vars.logger));
}
}

View File

@ -7,11 +7,11 @@ import { GlobalDependencies } from "../../types/Dependencies";
import { UserDataStore } from "./storage/UserDataStore";
import { ConfigurationParser } from "./configuration/ConfigurationParser";
import { RestApi } from "./RestApi";
import { ServerVariablesHandler, ServerVariablesInitializer } from "./ServerVariablesHandler";
import { SessionConfigurationBuilder } from "./configuration/SessionConfigurationBuilder";
import { GlobalLogger } from "./logging/GlobalLogger";
import { RequestLogger } from "./logging/RequestLogger";
import { ServerVariables } from "./ServerVariables";
import { ServerVariablesInitializer } from "./ServerVariablesInitializer";
import * as Express from "express";
import * as BodyParser from "body-parser";
@ -96,7 +96,6 @@ export default class Server {
.then(function (vars: ServerVariables) {
that.serverVariables = vars;
that.setupExpressApplication(config, app, deps);
ServerVariablesHandler.setup(app, vars);
return BluebirdPromise.resolve();
});
}

View File

@ -39,11 +39,6 @@ import { GlobalDependencies } from "../../types/Dependencies";
import { ServerVariables } from "./ServerVariables";
import { AuthenticationMethodCalculator } from "./AuthenticationMethodCalculator";
import express = require("express");
export const VARIABLES_KEY = "authelia-variables";
class UserDataStoreFactory {
static create(config: Configuration.AppConfiguration): BluebirdPromise<UserDataStore> {
if (config.storage.local) {
@ -104,53 +99,3 @@ export class ServerVariablesInitializer {
});
}
}
export class ServerVariablesHandler {
static setup(app: express.Application, variables: ServerVariables): void {
app.set(VARIABLES_KEY, variables);
}
static getLogger(app: express.Application): IRequestLogger {
return (app.get(VARIABLES_KEY) as ServerVariables).logger;
}
static getUserDataStore(app: express.Application): IUserDataStore {
return (app.get(VARIABLES_KEY) as ServerVariables).userDataStore;
}
static getNotifier(app: express.Application): INotifier {
return (app.get(VARIABLES_KEY) as ServerVariables).notifier;
}
static getLdapAuthenticator(app: express.Application): IAuthenticator {
return (app.get(VARIABLES_KEY) as ServerVariables).ldapAuthenticator;
}
static getLdapPasswordUpdater(app: express.Application): IPasswordUpdater {
return (app.get(VARIABLES_KEY) as ServerVariables).ldapPasswordUpdater;
}
static getLdapEmailsRetriever(app: express.Application): IEmailsRetriever {
return (app.get(VARIABLES_KEY) as ServerVariables).ldapEmailsRetriever;
}
static getConfiguration(app: express.Application): Configuration.AppConfiguration {
return (app.get(VARIABLES_KEY) as ServerVariables).config;
}
static getAuthenticationRegulator(app: express.Application): IRegulator {
return (app.get(VARIABLES_KEY) as ServerVariables).regulator;
}
static getAccessController(app: express.Application): IAccessController {
return (app.get(VARIABLES_KEY) as ServerVariables).accessController;
}
static getTotpHandler(app: express.Application): ITotpHandler {
return (app.get(VARIABLES_KEY) as ServerVariables).totpHandler;
}
static getU2F(app: express.Application): typeof U2F {
return (app.get(VARIABLES_KEY) as ServerVariables).u2f;
}
}

View File

@ -131,6 +131,7 @@ export interface UserConfiguration {
authentication_methods?: AuthenticationMethodsConfiguration;
access_control?: ACLConfiguration;
regulation: RegulationConfiguration;
default_redirection_url?: string;
}
export interface AppConfiguration {
@ -143,4 +144,5 @@ export interface AppConfiguration {
authentication_methods: AuthenticationMethodsConfiguration;
access_control?: ACLConfiguration;
regulation: RegulationConfiguration;
default_redirection_url?: string;
}

View File

@ -82,7 +82,8 @@ function adaptFromUserConfiguration(userConfiguration: UserConfiguration)
notifier: ObjectPath.get<object, NotifierConfiguration>(userConfiguration, "notifier"),
access_control: ACLAdapter.adapt(userConfiguration.access_control),
regulation: userConfiguration.regulation,
authentication_methods: authenticationMethods
authentication_methods: authenticationMethods,
default_redirection_url: userConfiguration.default_redirection_url
};
}

View File

@ -5,19 +5,17 @@ import FirstFactorValidator = require("../FirstFactorValidator");
import Exceptions = require("../Exceptions");
import ErrorReplies = require("../ErrorReplies");
import objectPath = require("object-path");
import { ServerVariablesHandler } from "../ServerVariablesHandler";
import AuthenticationSession = require("../AuthenticationSession");
import UserMessages = require("../../../../shared/UserMessages");
import { IRequestLogger } from "../logging/IRequestLogger";
type Handler = (req: express.Request, res: express.Response) => BluebirdPromise<void>;
export default function (callback: Handler): Handler {
export default function (callback: Handler, logger: IRequestLogger): Handler {
return function (req: express.Request, res: express.Response): BluebirdPromise<void> {
const logger = ServerVariablesHandler.getLogger(req.app);
return AuthenticationSession.get(req)
return AuthenticationSession.get(req, logger)
.then(function (authSession) {
return FirstFactorValidator.validate(req);
return FirstFactorValidator.validate(req, logger);
})
.then(function () {
return callback(req, res);

View File

@ -4,11 +4,11 @@ import objectPath = require("object-path");
import winston = require("winston");
import Endpoints = require("../../../../../shared/api");
import AuthenticationValidator = require("../../AuthenticationValidator");
import { ServerVariablesHandler } from "../../ServerVariablesHandler";
import BluebirdPromise = require("bluebird");
import AuthenticationSession = require("../../AuthenticationSession");
import Constants = require("../../../../../shared/constants");
import Util = require("util");
import { ServerVariables } from "../../ServerVariables";
function getRedirectParam(req: express.Request) {
return req.query[Constants.REDIRECT_QUERY_PARAM] != "undefined"
@ -40,8 +40,9 @@ function renderFirstFactor(res: express.Response) {
});
}
export default function (req: express.Request, res: express.Response): BluebirdPromise<void> {
return AuthenticationSession.get(req)
export default function (vars: ServerVariables) {
return function (req: express.Request, res: express.Response): BluebirdPromise<void> {
return AuthenticationSession.get(req, vars.logger)
.then(function (authSession) {
if (authSession.first_factor) {
if (authSession.second_factor)
@ -54,4 +55,5 @@ export default function (req: express.Request, res: express.Response): BluebirdP
renderFirstFactor(res);
return BluebirdPromise.resolve();
});
};
}

View File

@ -8,20 +8,20 @@ import { Regulator } from "../../regulation/Regulator";
import { GroupsAndEmails } from "../../ldap/IClient";
import Endpoint = require("../../../../../shared/api");
import ErrorReplies = require("../../ErrorReplies");
import { ServerVariablesHandler } from "../../ServerVariablesHandler";
import AuthenticationSession = require("../../AuthenticationSession");
import AuthenticationSessionHandler = require("../../AuthenticationSession");
import Constants = require("../../../../../shared/constants");
import { DomainExtractor } from "../../utils/DomainExtractor";
import UserMessages = require("../../../../../shared/UserMessages");
import { AuthenticationMethodCalculator } from "../../AuthenticationMethodCalculator";
import { ServerVariables } from "../../ServerVariables";
import { AuthenticationSession } from "../../../../types/AuthenticationSession";
export default function (vars: ServerVariables) {
return function (req: express.Request, res: express.Response)
: BluebirdPromise<void> {
const username: string = req.body.username;
const password: string = req.body.password;
let authSession: AuthenticationSession.AuthenticationSession;
let authSession: AuthenticationSession;
return BluebirdPromise.resolve()
.then(function () {
@ -29,9 +29,9 @@ export default function (vars: ServerVariables) {
return BluebirdPromise.reject(new Error("No username or password."));
}
vars.logger.info(req, "Starting authentication of user \"%s\"", username);
return AuthenticationSession.get(req);
return AuthenticationSessionHandler.get(req, vars.logger);
})
.then(function (_authSession: AuthenticationSession.AuthenticationSession) {
.then(function (_authSession) {
authSession = _authSession;
return vars.regulator.regulate(username);
})

View File

@ -2,16 +2,20 @@ import Express = require("express");
import Endpoints = require("../../../../../shared/api");
import FirstFactorBlocker from "../FirstFactorBlocker";
import BluebirdPromise = require("bluebird");
import AuthenticationSession = require("../../AuthenticationSession");
import AuthenticationSessionHandler = require("../../AuthenticationSession");
import { ServerVariables } from "../../ServerVariables";
export default FirstFactorBlocker(handler);
function handler(req: Express.Request, res: Express.Response): BluebirdPromise<void> {
return AuthenticationSession.get(req)
export default function (vars: ServerVariables) {
function handler(req: Express.Request, res: Express.Response): BluebirdPromise<void> {
return AuthenticationSessionHandler.get(req, vars.logger)
.then(function (authSession) {
res.render("already-logged-in", {
logout_endpoint: Endpoints.LOGOUT_GET,
username: authSession.userid
username: authSession.userid,
redirection_url: vars.config.default_redirection_url
});
});
}
return FirstFactorBlocker(handler, vars.logger);
}

View File

@ -3,38 +3,40 @@ import express = require("express");
import BluebirdPromise = require("bluebird");
import objectPath = require("object-path");
import exceptions = require("../../../Exceptions");
import { ServerVariablesHandler } from "../../../ServerVariablesHandler";
import AuthenticationSession = require("../../../AuthenticationSession");
import AuthenticationSessionHandler = require("../../../AuthenticationSession");
import { AuthenticationSession } from "../../../../../types/AuthenticationSession";
import ErrorReplies = require("../../../ErrorReplies");
import UserMessages = require("../../../../../../shared/UserMessages");
import { ServerVariables } from "../../../ServerVariables";
import Constants = require("./../constants");
export default function (req: express.Request, res: express.Response): BluebirdPromise<void> {
const logger = ServerVariablesHandler.getLogger(req.app);
const ldapPasswordUpdater = ServerVariablesHandler.getLdapPasswordUpdater(req.app);
let authSession: AuthenticationSession.AuthenticationSession;
export default function (vars: ServerVariables) {
return function (req: express.Request, res: express.Response): BluebirdPromise<void> {
let authSession: AuthenticationSession;
const newPassword = objectPath.get<express.Request, string>(req, "body.password");
return AuthenticationSession.get(req)
return AuthenticationSessionHandler.get(req, vars.logger)
.then(function (_authSession) {
authSession = _authSession;
logger.info(req, "User %s wants to reset his/her password.",
vars.logger.info(req, "User %s wants to reset his/her password.",
authSession.identity_check.userid);
logger.debug(req, "Challenge %s", authSession.identity_check.challenge);
vars.logger.debug(req, "Challenge %s", authSession.identity_check.challenge);
if (authSession.identity_check.challenge != Constants.CHALLENGE) {
return BluebirdPromise.reject(new Error("Bad challenge."));
}
return ldapPasswordUpdater.updatePassword(authSession.identity_check.userid, newPassword);
return vars.ldapPasswordUpdater.updatePassword(authSession.identity_check.userid, newPassword);
})
.then(function () {
logger.info(req, "Password reset for user '%s'",
vars.logger.info(req, "Password reset for user '%s'",
authSession.identity_check.userid);
AuthenticationSession.reset(req);
AuthenticationSessionHandler.reset(req);
res.status(204);
res.send();
return BluebirdPromise.resolve();
})
.catch(ErrorReplies.replyWithError200(req, res, logger, UserMessages.RESET_PASSWORD_FAILED));
.catch(ErrorReplies.replyWithError200(req, res, vars.logger,
UserMessages.RESET_PASSWORD_FAILED));
};
}

View File

@ -7,26 +7,32 @@ import { Identity } from "../../../../../types/Identity";
import { IdentityValidable } from "../../../IdentityCheckMiddleware";
import { PRE_VALIDATION_TEMPLATE } from "../../../IdentityCheckPreValidationTemplate";
import Constants = require("../constants");
import { Winston } from "winston";
import { ServerVariablesHandler } from "../../../ServerVariablesHandler";
import { IRequestLogger } from "../../../logging/IRequestLogger";
import { IEmailsRetriever } from "../../../ldap/IEmailsRetriever";
export const TEMPLATE_NAME = "password-reset-form";
export default class PasswordResetHandler implements IdentityValidable {
private logger: IRequestLogger;
private emailsRetriever: IEmailsRetriever;
constructor(logger: IRequestLogger, emailsRetriever: IEmailsRetriever) {
this.logger = logger;
this.emailsRetriever = emailsRetriever;
}
challenge(): string {
return Constants.CHALLENGE;
}
preValidationInit(req: express.Request): BluebirdPromise<Identity> {
const logger = ServerVariablesHandler.getLogger(req.app);
const userid: string = objectPath.get<express.Request, string>(req, "query.userid");
logger.debug(req, "User '%s' requested a password reset", userid);
this.logger.debug(req, "User '%s' requested a password reset", userid);
if (!userid)
return BluebirdPromise.reject(new exceptions.AccessDeniedError("No user id provided"));
const emailsRetriever = ServerVariablesHandler.getLdapEmailsRetriever(req.app);
return emailsRetriever.retrieve(userid)
return this.emailsRetriever.retrieve(userid)
.then(function (emails: string[]) {
if (!emails && emails.length <= 0) throw new Error("No email found");
const identity = {

View File

@ -3,15 +3,14 @@ import Express = require("express");
import Endpoints = require("../../../../../shared/api");
import FirstFactorBlocker = require("../FirstFactorBlocker");
import BluebirdPromise = require("bluebird");
import { ServerVariablesHandler } from "../../ServerVariablesHandler";
import AuthenticationSession = require("../../AuthenticationSession");
import AuthenticationSessionHandler = require("../../AuthenticationSession");
import { ServerVariables } from "../../ServerVariables";
const TEMPLATE_NAME = "secondfactor";
export default FirstFactorBlocker.default(handler);
function handler(req: Express.Request, res: Express.Response): BluebirdPromise<void> {
return AuthenticationSession.get(req)
export default function (vars: ServerVariables) {
function handler(req: Express.Request, res: Express.Response): BluebirdPromise<void> {
return AuthenticationSessionHandler.get(req, vars.logger)
.then(function (authSession) {
if (authSession.first_factor && authSession.second_factor) {
res.redirect(Endpoints.LOGGED_IN);
@ -25,4 +24,7 @@ function handler(req: Express.Request, res: Express.Response): BluebirdPromise<v
});
return BluebirdPromise.resolve();
});
}
return FirstFactorBlocker.default(handler, vars.logger);
}

View File

@ -3,22 +3,29 @@ import express = require("express");
import objectPath = require("object-path");
import winston = require("winston");
import Endpoints = require("../../../../../shared/api");
import { ServerVariablesHandler } from "../../ServerVariablesHandler";
import { ServerVariables } from "../../ServerVariables";
import AuthenticationSession = require("../../AuthenticationSession");
import BluebirdPromise = require("bluebird");
import ErrorReplies = require("../../ErrorReplies");
import UserMessages = require("../../../../../shared/UserMessages");
import { RedirectionMessage } from "../../../../../shared/RedirectionMessage";
import Constants = require("../../../../../shared/constants");
export default function (req: express.Request, res: express.Response): BluebirdPromise<void> {
const logger = ServerVariablesHandler.getLogger(req.app);
return AuthenticationSession.get(req)
.then(function (authSession: AuthenticationSession.AuthenticationSession) {
const redirectUrl = req.query.redirect || Endpoints.FIRST_FACTOR_GET;
export default function (vars: ServerVariables) {
return function (req: express.Request, res: express.Response): BluebirdPromise<void> {
return AuthenticationSession.get(req, vars.logger)
.then(function (authSession) {
let redirectUrl: string;
if (vars.config.default_redirection_url) {
redirectUrl = vars.config.default_redirection_url;
}
vars.logger.debug(req, "Request redirection to \"%s\".", redirectUrl);
res.json({
redirection_url: redirectUrl
});
redirect: redirectUrl
} as RedirectionMessage);
return BluebirdPromise.resolve();
})
.catch(ErrorReplies.replyWithError200(req, res, logger,
.catch(ErrorReplies.replyWithError200(req, res, vars.logger,
UserMessages.OPERATION_FAILED));
};
}

View File

@ -9,21 +9,34 @@ import { PRE_VALIDATION_TEMPLATE } from "../../../../IdentityCheckPreValidationT
import Constants = require("../constants");
import Endpoints = require("../../../../../../../shared/api");
import ErrorReplies = require("../../../../ErrorReplies");
import { ServerVariablesHandler } from "../../../../ServerVariablesHandler";
import AuthenticationSession = require("../../../../AuthenticationSession");
import UserMessages = require("../../../../../../../shared/UserMessages");
import FirstFactorValidator = require("../../../../FirstFactorValidator");
import { IRequestLogger } from "../../../../logging/IRequestLogger";
import { IUserDataStore } from "../../../../storage/IUserDataStore";
import { ITotpHandler } from "../../../../authentication/totp/ITotpHandler";
export default class RegistrationHandler implements IdentityValidable {
private logger: IRequestLogger;
private userDataStore: IUserDataStore;
private totp: ITotpHandler;
constructor(logger: IRequestLogger,
userDataStore: IUserDataStore,
totp: ITotpHandler) {
this.logger = logger;
this.userDataStore = userDataStore;
this.totp = totp;
}
challenge(): string {
return Constants.CHALLENGE;
}
private retrieveIdentity(req: express.Request): BluebirdPromise<Identity> {
return AuthenticationSession.get(req)
.then(function (authSession: AuthenticationSession.AuthenticationSession) {
return AuthenticationSession.get(req, this.logger)
.then(function (authSession) {
const userid = authSession.userid;
const email = authSession.email;
@ -41,7 +54,7 @@ export default class RegistrationHandler implements IdentityValidable {
preValidationInit(req: express.Request): BluebirdPromise<Identity> {
const that = this;
return FirstFactorValidator.validate(req)
return FirstFactorValidator.validate(req, this.logger)
.then(function () {
return that.retrieveIdentity(req);
});
@ -52,26 +65,22 @@ export default class RegistrationHandler implements IdentityValidable {
}
postValidationInit(req: express.Request) {
return FirstFactorValidator.validate(req);
return FirstFactorValidator.validate(req, this.logger);
}
postValidationResponse(req: express.Request, res: express.Response): BluebirdPromise<void> {
const logger = ServerVariablesHandler.getLogger(req.app);
return AuthenticationSession.get(req)
.then(function (authSession: AuthenticationSession.AuthenticationSession) {
const that = this;
return AuthenticationSession.get(req, this.logger)
.then(function (authSession) {
const userid = authSession.identity_check.userid;
const challenge = authSession.identity_check.challenge;
if (challenge != Constants.CHALLENGE || !userid) {
return BluebirdPromise.reject(new Error("Bad challenge."));
}
const userDataStore = ServerVariablesHandler.getUserDataStore(req.app);
const totpHandler = ServerVariablesHandler.getTotpHandler(req.app);
const secret = totpHandler.generate();
logger.debug(req, "Save the TOTP secret in DB");
return userDataStore.saveTOTPSecret(userid, secret)
const secret = that.totp.generate();
that.logger.debug(req, "Save the TOTP secret in DB");
return that.userDataStore.saveTOTPSecret(userid, secret)
.then(function () {
AuthenticationSession.reset(req);
@ -82,7 +91,7 @@ export default class RegistrationHandler implements IdentityValidable {
});
});
})
.catch(ErrorReplies.replyWithError200(req, res, logger, UserMessages.OPERATION_FAILED));
.catch(ErrorReplies.replyWithError200(req, res, that.logger, UserMessages.OPERATION_FAILED));
}
mailSubject(): string {

View File

@ -8,8 +8,8 @@ import FirstFactorBlocker from "../../../FirstFactorBlocker";
import Endpoints = require("../../../../../../../shared/api");
import redirect from "../../redirect";
import ErrorReplies = require("../../../../ErrorReplies");
import { ServerVariablesHandler } from "./../../../../ServerVariablesHandler";
import AuthenticationSession = require("../../../../AuthenticationSession");
import AuthenticationSessionHandler = require("../../../../AuthenticationSession");
import { AuthenticationSession } from "../../../../../../types/AuthenticationSession";
import UserMessages = require("../../../../../../../shared/UserMessages");
import { ServerVariables } from "../../../../ServerVariables";
@ -17,11 +17,11 @@ const UNAUTHORIZED_MESSAGE = "Unauthorized access";
export default function (vars: ServerVariables) {
function handler(req: express.Request, res: express.Response): BluebirdPromise<void> {
let authSession: AuthenticationSession.AuthenticationSession;
let authSession: AuthenticationSession;
const token = req.body.token;
return AuthenticationSession.get(req)
.then(function (_authSession: AuthenticationSession.AuthenticationSession) {
return AuthenticationSessionHandler.get(req, vars.logger)
.then(function (_authSession) {
authSession = _authSession;
vars.logger.info(req, "Initiate TOTP validation for user \"%s\".", authSession.userid);
return vars.userDataStore.retrieveTOTPSecret(authSession.userid);
@ -32,11 +32,11 @@ export default function (vars: ServerVariables) {
vars.logger.debug(req, "TOTP validation succeeded.");
authSession.second_factor = true;
redirect(req, res);
redirect(vars)(req, res);
return BluebirdPromise.resolve();
})
.catch(ErrorReplies.replyWithError200(req, res, vars.logger,
UserMessages.OPERATION_FAILED));
}
return FirstFactorBlocker(handler);
return FirstFactorBlocker(handler, vars.logger);
}

View File

@ -8,6 +8,7 @@ import { Identity } from "../../../../../../types/Identity";
import { PRE_VALIDATION_TEMPLATE } from "../../../../IdentityCheckPreValidationTemplate";
import FirstFactorValidator = require("../../../../FirstFactorValidator");
import AuthenticationSession = require("../../../../AuthenticationSession");
import { IRequestLogger } from "../../../../logging/IRequestLogger";
const CHALLENGE = "u2f-register";
const MAIL_SUBJECT = "Register your U2F device";
@ -16,13 +17,19 @@ const POST_VALIDATION_TEMPLATE_NAME = "u2f-register";
export default class RegistrationHandler implements IdentityValidable {
private logger: IRequestLogger;
constructor(logger: IRequestLogger) {
this.logger = logger;
}
challenge(): string {
return CHALLENGE;
}
private retrieveIdentity(req: express.Request): BluebirdPromise<Identity> {
return AuthenticationSession.get(req)
.then(function (authSession: AuthenticationSession.AuthenticationSession) {
return AuthenticationSession.get(req, this.logger)
.then(function (authSession) {
const userid = authSession.userid;
const email = authSession.email;
@ -40,7 +47,7 @@ export default class RegistrationHandler implements IdentityValidable {
preValidationInit(req: express.Request): BluebirdPromise<Identity> {
const that = this;
return FirstFactorValidator.validate(req)
return FirstFactorValidator.validate(req, this.logger)
.then(function () {
return that.retrieveIdentity(req);
});
@ -51,7 +58,7 @@ export default class RegistrationHandler implements IdentityValidable {
}
postValidationInit(req: express.Request) {
return FirstFactorValidator.validate(req);
return FirstFactorValidator.validate(req, this.logger);
}
postValidationResponse(req: express.Request, res: express.Response) {

View File

@ -10,24 +10,20 @@ import { U2FRegistration } from "../../../../../../types/U2FRegistration";
import FirstFactorBlocker from "../../../FirstFactorBlocker";
import redirect from "../../redirect";
import ErrorReplies = require("../../../../ErrorReplies");
import { ServerVariablesHandler } from "../../../../ServerVariablesHandler";
import AuthenticationSession = require("../../../../AuthenticationSession");
import { ServerVariables } from "../../../../ServerVariables";
import AuthenticationSessionHandler = require("../../../../AuthenticationSession");
import UserMessages = require("../../../../../../../shared/UserMessages");
import { AuthenticationSession } from "../../../../../../types/AuthenticationSession";
export default FirstFactorBlocker(handler);
function handler(req: express.Request, res: express.Response): BluebirdPromise<void> {
let authSession: AuthenticationSession.AuthenticationSession;
const userDataStore = ServerVariablesHandler.getUserDataStore(req.app);
const u2f = ServerVariablesHandler.getU2F(req.app);
export default function (vars: ServerVariables) {
function handler(req: express.Request, res: express.Response): BluebirdPromise<void> {
let authSession: AuthenticationSession;
const appid = u2f_common.extract_app_id(req);
const logger = ServerVariablesHandler.getLogger(req.app);
const registrationResponse: U2f.RegistrationData = req.body;
return AuthenticationSession.get(req)
.then(function (_authSession: AuthenticationSession.AuthenticationSession) {
return AuthenticationSessionHandler.get(req, vars.logger)
.then(function (_authSession) {
authSession = _authSession;
const registrationRequest = authSession.register_request;
@ -40,30 +36,33 @@ function handler(req: express.Request, res: express.Response): BluebirdPromise<v
return BluebirdPromise.reject(new Error("Bad challenge for registration request"));
}
logger.info(req, "Finishing registration");
logger.debug(req, "RegistrationRequest = %s", JSON.stringify(registrationRequest));
logger.debug(req, "RegistrationResponse = %s", JSON.stringify(registrationResponse));
vars.logger.info(req, "Finishing registration");
vars.logger.debug(req, "RegistrationRequest = %s", JSON.stringify(registrationRequest));
vars.logger.debug(req, "RegistrationResponse = %s", JSON.stringify(registrationResponse));
return BluebirdPromise.resolve(u2f.checkRegistration(registrationRequest, registrationResponse));
return BluebirdPromise.resolve(vars.u2f.checkRegistration(registrationRequest, registrationResponse));
})
.then(function (u2fResult: U2f.RegistrationResult | U2f.Error): BluebirdPromise<void> {
if (objectPath.has(u2fResult, "errorCode"))
return BluebirdPromise.reject(new Error("Error while registering."));
const registrationResult: U2f.RegistrationResult = u2fResult as U2f.RegistrationResult;
logger.info(req, "Store registration and reply");
logger.debug(req, "RegistrationResult = %s", JSON.stringify(registrationResult));
vars.logger.info(req, "Store registration and reply");
vars.logger.debug(req, "RegistrationResult = %s", JSON.stringify(registrationResult));
const registration: U2FRegistration = {
keyHandle: registrationResult.keyHandle,
publicKey: registrationResult.publicKey
};
return userDataStore.saveU2FRegistration(authSession.userid, appid, registration);
return vars.userDataStore.saveU2FRegistration(authSession.userid, appid, registration);
})
.then(function () {
authSession.identity_check = undefined;
redirect(req, res);
redirect(vars)(req, res);
return BluebirdPromise.resolve();
})
.catch(ErrorReplies.replyWithError200(req, res, logger,
.catch(ErrorReplies.replyWithError200(req, res, vars.logger,
UserMessages.OPERATION_FAILED));
}
return FirstFactorBlocker(handler, vars.logger);
}

View File

@ -8,18 +8,18 @@ import express = require("express");
import U2f = require("u2f");
import FirstFactorBlocker from "../../../FirstFactorBlocker";
import ErrorReplies = require("../../../../ErrorReplies");
import {  ServerVariablesHandler } from "../../../../ServerVariablesHandler";
import AuthenticationSession = require("../../../../AuthenticationSession");
import AuthenticationSessionHandler = require("../../../../AuthenticationSession");
import { AuthenticationSession } from "../../../../../../types/AuthenticationSession";
import UserMessages = require("../../../../../../../shared/UserMessages");
import { ServerVariables } from "../../../../ServerVariables";
export default FirstFactorBlocker(handler);
export default function (vars: ServerVariables) {
function handler(req: express.Request, res: express.Response): BluebirdPromise<void> {
let authSession: AuthenticationSession;
const appid: string = u2f_common.extract_app_id(req);
function handler(req: express.Request, res: express.Response): BluebirdPromise<void> {
const logger = ServerVariablesHandler.getLogger(req.app);
let authSession: AuthenticationSession.AuthenticationSession;
return AuthenticationSession.get(req)
.then(function (_authSession: AuthenticationSession.AuthenticationSession) {
return AuthenticationSessionHandler.get(req, vars.logger)
.then(function (_authSession) {
authSession = _authSession;
if (!authSession.identity_check
@ -29,19 +29,19 @@ function handler(req: express.Request, res: express.Response): BluebirdPromise<v
return BluebirdPromise.reject(new Error("Bad challenge."));
}
const u2f = ServerVariablesHandler.getU2F(req.app);
const appid: string = u2f_common.extract_app_id(req);
vars.logger.info(req, "Starting registration for appId '%s'", appid);
logger.info(req, "Starting registration for appId '%s'", appid);
return BluebirdPromise.resolve(u2f.request(appid));
return BluebirdPromise.resolve(vars.u2f.request(appid));
})
.then(function (registrationRequest: U2f.Request) {
logger.debug(req, "RegistrationRequest = %s", JSON.stringify(registrationRequest));
vars.logger.debug(req, "RegistrationRequest = %s", JSON.stringify(registrationRequest));
authSession.register_request = registrationRequest;
res.json(registrationRequest);
return BluebirdPromise.resolve();
})
.catch(ErrorReplies.replyWithError200(req, res, logger,
.catch(ErrorReplies.replyWithError200(req, res, vars.logger,
UserMessages.OPERATION_FAILED));
}
return FirstFactorBlocker(handler, vars.logger);
}

View File

@ -11,47 +11,45 @@ import exceptions = require("../../../../Exceptions");
import FirstFactorBlocker from "../../../FirstFactorBlocker";
import redirect from "../../redirect";
import ErrorReplies = require("../../../../ErrorReplies");
import { ServerVariablesHandler } from "../../../../ServerVariablesHandler";
import AuthenticationSession = require("../../../../AuthenticationSession");
import { ServerVariables } from "../../../../ServerVariables";
import AuthenticationSessionHandler = require("../../../../AuthenticationSession");
import UserMessages = require("../../../../../../../shared/UserMessages");
import { AuthenticationSession } from "../../../../../../types/AuthenticationSession";
export default FirstFactorBlocker(handler);
export default function (vars: ServerVariables) {
function handler(req: express.Request, res: express.Response): BluebirdPromise<void> {
let authSession: AuthenticationSession;
const appId = u2f_common.extract_app_id(req);
export function handler(req: express.Request, res: express.Response): BluebirdPromise<void> {
const logger = ServerVariablesHandler.getLogger(req.app);
const userDataStore = ServerVariablesHandler.getUserDataStore(req.app);
let authSession: AuthenticationSession.AuthenticationSession;
return AuthenticationSession.get(req)
.then(function (_authSession: AuthenticationSession.AuthenticationSession) {
return AuthenticationSessionHandler.get(req, vars.logger)
.then(function (_authSession) {
authSession = _authSession;
if (!authSession.sign_request) {
const err = new Error("No sign request");
ErrorReplies.replyWithError401(req, res, logger)(err);
ErrorReplies.replyWithError401(req, res, vars.logger)(err);
return BluebirdPromise.reject(err);
}
const userid = authSession.userid;
const appid = u2f_common.extract_app_id(req);
return userDataStore.retrieveU2FRegistration(userid, appid);
return vars.userDataStore.retrieveU2FRegistration(userid, appId);
})
.then(function (doc: U2FRegistrationDocument): BluebirdPromise<U2f.SignatureResult | U2f.Error> {
const appId = u2f_common.extract_app_id(req);
const u2f = ServerVariablesHandler.getU2F(req.app);
const signRequest = authSession.sign_request;
const signData: U2f.SignatureData = req.body;
logger.info(req, "Finish authentication");
return BluebirdPromise.resolve(u2f.checkSignature(signRequest, signData, doc.registration.publicKey));
vars.logger.info(req, "Finish authentication");
return BluebirdPromise.resolve(vars.u2f.checkSignature(signRequest, signData, doc.registration.publicKey));
})
.then(function (result: U2f.SignatureResult | U2f.Error): BluebirdPromise<void> {
if (objectPath.has(result, "errorCode"))
return BluebirdPromise.reject(new Error("Error while signing"));
logger.info(req, "Successful authentication");
vars.logger.info(req, "Successful authentication");
authSession.second_factor = true;
redirect(req, res);
redirect(vars)(req, res);
return BluebirdPromise.resolve();
})
.catch(ErrorReplies.replyWithError200(req, res, logger,
.catch(ErrorReplies.replyWithError200(req, res, vars.logger,
UserMessages.OPERATION_FAILED));
}
return FirstFactorBlocker(handler, vars.logger);
}

View File

@ -11,33 +11,30 @@ import exceptions = require("../../../../Exceptions");
import { SignMessage } from "../../../../../../../shared/SignMessage";
import FirstFactorBlocker from "../../../FirstFactorBlocker";
import ErrorReplies = require("../../../../ErrorReplies");
import { ServerVariablesHandler } from "../../../../ServerVariablesHandler";
import AuthenticationSession = require("../../../../AuthenticationSession");
import AuthenticationSessionHandler = require("../../../../AuthenticationSession");
import UserMessages = require("../../../../../../../shared/UserMessages");
import { ServerVariables } from "../../../../ServerVariables";
import { AuthenticationSession } from "../../../../../../types/AuthenticationSession";
export default FirstFactorBlocker(handler);
export function handler(req: express.Request, res: express.Response): BluebirdPromise<void> {
const logger = ServerVariablesHandler.getLogger(req.app);
const userDataStore = ServerVariablesHandler.getUserDataStore(req.app);
let authSession: AuthenticationSession.AuthenticationSession;
export default function (vars: ServerVariables) {
function handler(req: express.Request, res: express.Response): BluebirdPromise<void> {
let authSession: AuthenticationSession;
const appId = u2f_common.extract_app_id(req);
return AuthenticationSession.get(req)
.then(function (_authSession: AuthenticationSession.AuthenticationSession) {
return AuthenticationSessionHandler.get(req, vars.logger)
.then(function (_authSession) {
authSession = _authSession;
return userDataStore.retrieveU2FRegistration(authSession.userid, appId);
return vars.userDataStore.retrieveU2FRegistration(authSession.userid, appId);
})
.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 appId: string = u2f_common.extract_app_id(req);
logger.info(req, "Start authentication of app '%s'", appId);
logger.debug(req, "AppId = %s, keyHandle = %s", appId, JSON.stringify(doc.registration.keyHandle));
vars.logger.info(req, "Start authentication of app '%s'", appId);
vars.logger.debug(req, "AppId = %s, keyHandle = %s", appId, JSON.stringify(doc.registration.keyHandle));
const request = u2f.request(appId, doc.registration.keyHandle);
const request = vars.u2f.request(appId, doc.registration.keyHandle);
const authenticationMessage: SignMessage = {
request: request,
keyHandle: doc.registration.keyHandle
@ -45,13 +42,15 @@ export function handler(req: express.Request, res: express.Response): BluebirdPr
return BluebirdPromise.resolve(authenticationMessage);
})
.then(function (authenticationMessage: SignMessage) {
logger.info(req, "Store authentication request and reply");
logger.debug(req, "AuthenticationRequest = %s", authenticationMessage);
vars.logger.info(req, "Store authentication request and reply");
vars.logger.debug(req, "AuthenticationRequest = %s", authenticationMessage);
authSession.sign_request = authenticationMessage.request;
res.json(authenticationMessage);
return BluebirdPromise.resolve();
})
.catch(ErrorReplies.replyWithError200(req, res, logger,
.catch(ErrorReplies.replyWithError200(req, res, vars.logger,
UserMessages.OPERATION_FAILED));
}
}
return FirstFactorBlocker(handler, vars.logger);
}

View File

@ -7,7 +7,8 @@ import winston = require("winston");
import AuthenticationValidator = require("../../AuthenticationValidator");
import ErrorReplies = require("../../ErrorReplies");
import { AppConfiguration } from "../../configuration/Configuration";
import AuthenticationSession = require("../../AuthenticationSession");
import AuthenticationSessionHandler = require("../../AuthenticationSession");
import { AuthenticationSession } from "../../../../types/AuthenticationSession";
import Constants = require("../../../../../shared/constants");
import Util = require("util");
import { DomainExtractor } from "../../utils/DomainExtractor";
@ -22,7 +23,7 @@ const REMOTE_USER = "Remote-User";
const REMOTE_GROUPS = "Remote-Groups";
function verify_inactivity(req: express.Request,
authSession: AuthenticationSession.AuthenticationSession,
authSession: AuthenticationSession,
configuration: AppConfiguration, logger: IRequestLogger)
: BluebirdPromise<void> {
@ -43,17 +44,17 @@ function verify_inactivity(req: express.Request,
}
logger.debug(req, "Session has been reset after too long inactivity period.");
AuthenticationSession.reset(req);
AuthenticationSessionHandler.reset(req);
return BluebirdPromise.reject(new Error("Inactivity period exceeded."));
}
function verify_filter(req: express.Request, res: express.Response,
vars: ServerVariables): BluebirdPromise<void> {
let _authSession: AuthenticationSession.AuthenticationSession;
let _authSession: AuthenticationSession;
let username: string;
let groups: string[];
return AuthenticationSession.get(req)
return AuthenticationSessionHandler.get(req, vars.logger)
.then(function (authSession) {
_authSession = authSession;
username = _authSession.userid;
@ -97,6 +98,7 @@ function verify_filter(req: express.Request, res: express.Response,
.then(function () {
res.setHeader(REMOTE_USER, username);
res.setHeader(REMOTE_GROUPS, groups.join(","));
return BluebirdPromise.resolve();
});
}

View File

@ -5,5 +5,6 @@ block form-header
<img class="header-img" src="/img/success.png" alt="">
block content
<p>You are already logged in as <b>#{ username }</b>.<br/>
| Click <a href="#{ logout_endpoint }">here</a> to log off.<p>
<p>You are already logged in as <b>#{ username }</b>.<br/><br/>
| If you are not redirected in few seconds, click <a href="#{ redirection_url }">here</a>.<br/><br/>
| Otherwise, click <a href="#{ logout_endpoint }">here</a> to log off.<p>

View File

@ -7,7 +7,7 @@ html
link(rel="icon", href="/img/icon.png" type="image/png" sizes="32x32")/
link(rel="stylesheet", type="text/css", href="/css/authelia.css")/
if redirection_url
<meta http-equiv="refresh" content="5;url=#{redirection_url}">
<meta http-equiv="refresh" content="4;url=#{redirection_url}">
body
<div class="container">
<div class="row">

View File

@ -1,39 +1,41 @@
import sinon = require("sinon");
import IdentityValidator = require("../src/lib/IdentityCheckMiddleware");
import AuthenticationSession = require("../src/lib/AuthenticationSession");
import AuthenticationSessionHandler = require("../src/lib/AuthenticationSession");
import { AuthenticationSession } from "../types/AuthenticationSession";
import { UserDataStore } from "../src/lib/storage/UserDataStore";
import exceptions = require("../src/lib/Exceptions");
import { ServerVariables } from "../src/lib/ServerVariables";
import Assert = require("assert");
import Promise = require("bluebird");
import express = require("express");
import BluebirdPromise = require("bluebird");
import ExpressMock = require("./mocks/express");
import NotifierMock = require("./mocks/Notifier");
import IdentityValidatorMock = require("./mocks/IdentityValidator");
import ServerVariablesMock = require("./mocks/ServerVariablesMock");
import { RequestLoggerStub } from "./mocks/RequestLoggerStub";
import { ServerVariablesMock, ServerVariablesMockBuilder } from "./mocks/ServerVariablesMockBuilder";
describe("test identity check process", function () {
let mocks: ServerVariablesMock.ServerVariablesMock;
let req: ExpressMock.RequestMock;
let res: ExpressMock.ResponseMock;
let notifier: NotifierMock.NotifierMock;
let app: express.Application;
let app_get: sinon.SinonStub;
let app_post: sinon.SinonStub;
let identityValidable: IdentityValidatorMock.IdentityValidableMock;
let mocks: ServerVariablesMock;
let vars: ServerVariables;
beforeEach(function () {
const s = ServerVariablesMockBuilder.build();
mocks = s.mocks;
vars = s.variables;
req = ExpressMock.RequestMock();
res = ExpressMock.ResponseMock();
identityValidable = IdentityValidatorMock.IdentityValidableMock();
notifier = NotifierMock.NotifierMock();
notifier.notify = sinon.stub().returns(Promise.resolve());
req.headers = {};
req.session = {};
@ -42,9 +44,7 @@ describe("test identity check process", function () {
req.query = {};
req.app = {};
mocks = ServerVariablesMock.mock(req.app);
mocks.notifier = notifier;
mocks.notifier.notifyStub.returns(BluebirdPromise.resolve());
mocks.userDataStore.produceIdentityValidationTokenStub.returns(Promise.resolve());
mocks.userDataStore.consumeIdentityValidationTokenStub.returns(Promise.resolve({ userId: "user" }));
@ -64,7 +64,7 @@ describe("test identity check process", function () {
function test_start_get_handler() {
it("should send 401 if pre validation initialization throws a first factor error", function () {
identityValidable.preValidationInit.returns(BluebirdPromise.reject(new exceptions.FirstFactorValidationError("Error during prevalidation")));
const callback = IdentityValidator.get_start_validation(identityValidable, "/endpoint");
const callback = IdentityValidator.get_start_validation(identityValidable, "/endpoint", vars);
return callback(req as any, res as any, undefined)
.then(function () { return BluebirdPromise.reject("Should fail"); })
@ -77,7 +77,7 @@ describe("test identity check process", function () {
const identity = { userid: "abc" };
identityValidable.preValidationInit.returns(BluebirdPromise.resolve(identity));
const callback = IdentityValidator.get_start_validation(identityValidable, "/endpoint");
const callback = IdentityValidator.get_start_validation(identityValidable, "/endpoint", vars);
return callback(req as any, res as any, undefined)
.then(function () { return BluebirdPromise.reject("Should fail"); })
@ -91,7 +91,7 @@ describe("test identity check process", function () {
const identity = { email: "abc@example.com" };
identityValidable.preValidationInit.returns(BluebirdPromise.resolve(identity));
const callback = IdentityValidator.get_start_validation(identityValidable, "/endpoint");
const callback = IdentityValidator.get_start_validation(identityValidable, "/endpoint", vars);
return callback(req as any, res as any, undefined)
.then(function () { return BluebirdPromise.reject(new Error("It should fail")); })
@ -107,11 +107,11 @@ describe("test identity check process", function () {
req.get = sinon.stub().withArgs("Host").returns("localhost");
identityValidable.preValidationInit.returns(BluebirdPromise.resolve(identity));
const callback = IdentityValidator.get_start_validation(identityValidable, "/finish_endpoint");
const callback = IdentityValidator.get_start_validation(identityValidable, "/finish_endpoint", vars);
return callback(req as any, res as any, undefined)
.then(function () {
Assert(notifier.notify.calledOnce);
Assert(mocks.notifier.notifyStub.calledOnce);
Assert(mocks.userDataStore.produceIdentityValidationTokenStub.calledOnce);
Assert.equal(mocks.userDataStore.produceIdentityValidationTokenStub.getCall(0).args[0], "user");
Assert.equal(mocks.userDataStore.produceIdentityValidationTokenStub.getCall(0).args[3], 240000);
@ -122,7 +122,7 @@ describe("test identity check process", function () {
function test_finish_get_handler() {
it("should send 401 if no identity_token is provided", function () {
const callback = IdentityValidator.get_finish_validation(identityValidable);
const callback = IdentityValidator.get_finish_validation(identityValidable, vars);
return callback(req as any, res as any, undefined)
.then(function () { return BluebirdPromise.reject("Should fail"); })
@ -134,7 +134,7 @@ describe("test identity check process", function () {
it("should call postValidation if identity_token is provided and still valid", function () {
req.query.identity_token = "token";
const callback = IdentityValidator.get_finish_validation(identityValidable);
const callback = IdentityValidator.get_finish_validation(identityValidable, vars);
return callback(req as any, res as any, undefined);
});
@ -143,7 +143,7 @@ describe("test identity check process", function () {
mocks.userDataStore.consumeIdentityValidationTokenStub.returns(BluebirdPromise.reject(new Error("Invalid token")));
const callback = IdentityValidator.get_finish_validation(identityValidable);
const callback = IdentityValidator.get_finish_validation(identityValidable, vars);
return callback(req as any, res as any, undefined)
.then(function () { return BluebirdPromise.reject("Should fail"); })
.catch(function () {
@ -155,11 +155,11 @@ describe("test identity check process", function () {
req.query.identity_token = "token";
req.session = {};
let authSession: AuthenticationSession.AuthenticationSession;
const callback = IdentityValidator.get_finish_validation(identityValidable);
let authSession: AuthenticationSession;
const callback = IdentityValidator.get_finish_validation(identityValidable, vars);
return AuthenticationSession.get(req as any)
.then(function (_authSession: AuthenticationSession.AuthenticationSession) {
return AuthenticationSessionHandler.get(req as any, vars.logger)
.then(function (_authSession) {
authSession = _authSession;
return callback(req as any, res as any, undefined);
})

View File

@ -167,4 +167,13 @@ describe("test config parser", function () {
} as ACLConfiguration);
});
});
describe("default_redirection_url", function() {
it("should parse default_redirection_url", function() {
const userConfig = buildYamlConfig();
userConfig.default_redirection_url = "dummy_url";
const config = ConfigurationParser.parse(userConfig);
Assert.deepEqual(config.default_redirection_url, "dummy_url");
});
});
});

View File

@ -1,46 +0,0 @@
import Sinon = require("sinon");
import express = require("express");
import { RequestLoggerStub } from "./RequestLoggerStub";
import { UserDataStoreStub } from "./storage/UserDataStoreStub";
import { AuthenticationMethodCalculator } from "../../src/lib/AuthenticationMethodCalculator";
import { VARIABLES_KEY } from "../../src/lib/ServerVariablesHandler";
export interface ServerVariablesMock {
logger: any;
ldapAuthenticator: any;
ldapEmailsRetriever: any;
ldapPasswordUpdater: any;
totpValidator: any;
totpGenerator: any;
u2f: any;
userDataStore: UserDataStoreStub;
notifier: any;
regulator: any;
config: any;
accessController: any;
authenticationMethodsCalculator: any;
}
export function mock(app: express.Application): ServerVariablesMock {
const mocks: ServerVariablesMock = {
accessController: Sinon.stub(),
config: Sinon.stub(),
ldapAuthenticator: Sinon.stub() as any,
ldapEmailsRetriever: Sinon.stub() as any,
ldapPasswordUpdater: Sinon.stub() as any,
logger: new RequestLoggerStub(),
notifier: Sinon.stub(),
regulator: Sinon.stub(),
totpGenerator: Sinon.stub(),
totpValidator: Sinon.stub(),
u2f: Sinon.stub(),
userDataStore: new UserDataStoreStub(),
authenticationMethodsCalculator: new AuthenticationMethodCalculator({
default_method: "two_factor",
per_subdomain_methods: {}
})
};
app.get = Sinon.stub().withArgs(VARIABLES_KEY).returns(mocks);
return mocks;
}

View File

@ -2,13 +2,11 @@
import Sinon = require("sinon");
import BluebirdPromise = require("bluebird");
import Assert = require("assert");
import Winston = require("winston");
import FirstFactorPost = require("../../../src/lib/routes/firstfactor/post");
import exceptions = require("../../../src/lib/Exceptions");
import AuthenticationSession = require("../../../src/lib/AuthenticationSession");
import AuthenticationSessionHandler = require("../../../src/lib/AuthenticationSession");
import { AuthenticationSession } from "../../../types/AuthenticationSession";
import Endpoints = require("../../../../shared/api");
import AuthenticationRegulatorMock = require("../../mocks/AuthenticationRegulator");
import { AccessControllerStub } from "../../mocks/AccessControllerStub";
import ExpressMock = require("../../mocks/express");
@ -35,9 +33,6 @@ describe("test the first factor validation route", function () {
mocks.regulator.markStub.returns(BluebirdPromise.resolve());
req = {
app: {
get: Sinon.stub().returns({ logger: Winston })
},
body: {
username: "username",
password: "password"
@ -52,7 +47,6 @@ describe("test the first factor validation route", function () {
}
};
AuthenticationSession.reset(req as any);
res = ExpressMock.ResponseMock();
});
@ -62,9 +56,9 @@ describe("test the first factor validation route", function () {
emails: emails,
groups: groups
}));
let authSession: AuthenticationSession.AuthenticationSession;
return AuthenticationSession.get(req as any)
.then(function (_authSession: AuthenticationSession.AuthenticationSession) {
let authSession: AuthenticationSession;
return AuthenticationSessionHandler.get(req as any, vars.logger)
.then(function (_authSession) {
authSession = _authSession;
return FirstFactorPost.default(vars)(req as any, res as any);
})
@ -82,15 +76,15 @@ describe("test the first factor validation route", function () {
it("should set first email address as user session variable", function () {
const emails = ["test_ok@example.com"];
let authSession: AuthenticationSession.AuthenticationSession;
let authSession: AuthenticationSession;
mocks.ldapAuthenticator.authenticateStub.withArgs("username", "password")
.returns(BluebirdPromise.resolve({
emails: emails,
groups: groups
}));
return AuthenticationSession.get(req as any)
.then(function (_authSession: AuthenticationSession.AuthenticationSession) {
return AuthenticationSessionHandler.get(req as any, vars.logger)
.then(function (_authSession) {
authSession = _authSession;
return FirstFactorPost.default(vars)(req as any, res as any);
})

View File

@ -1,32 +1,28 @@
import PasswordResetHandler from "../../../../src/lib/routes/password-reset/identity/PasswordResetHandler";
import PasswordUpdater = require("../../../../src/lib/ldap/PasswordUpdater");
import { ServerVariablesHandler } from "../../../../src/lib/ServerVariablesHandler";
import { UserDataStore } from "../../../../src/lib/storage/UserDataStore";
import Sinon = require("sinon");
import winston = require("winston");
import assert = require("assert");
import BluebirdPromise = require("bluebird");
import ExpressMock = require("../../../mocks/express");
import ServerVariablesMock = require("../../../mocks/ServerVariablesMock");
import { ServerVariablesMock, ServerVariablesMockBuilder } from "../../../mocks/ServerVariablesMockBuilder";
import { ServerVariables } from "../../../../src/lib/ServerVariables";
describe("test reset password identity check", function () {
let req: ExpressMock.RequestMock;
let res: ExpressMock.ResponseMock;
let configuration: any;
let serverVariables: ServerVariablesMock.ServerVariablesMock;
let mocks: ServerVariablesMock;
let vars: ServerVariables;
beforeEach(function () {
req = {
query: {
userid: "user"
},
app: {
get: Sinon.stub()
},
session: {
auth_session: {
auth: {
userid: "user",
email: "user@example.com",
first_factor: true,
@ -42,31 +38,21 @@ describe("test reset password identity check", function () {
inMemoryOnly: true
};
serverVariables = ServerVariablesMock.mock(req.app);
const s = ServerVariablesMockBuilder.build();
mocks = s.mocks;
vars = s.variables;
serverVariables.userDataStore.saveU2FRegistrationStub.returns(BluebirdPromise.resolve({}));
serverVariables.userDataStore.retrieveU2FRegistrationStub.returns(BluebirdPromise.resolve({}));
serverVariables.userDataStore.produceIdentityValidationTokenStub.returns(BluebirdPromise.resolve({}));
serverVariables.userDataStore.consumeIdentityValidationTokenStub.returns(BluebirdPromise.resolve({}));
configuration = {
ldap: {
base_dn: "dc=example,dc=com",
user_name_attribute: "cn"
}
};
serverVariables.config = configuration;
serverVariables.ldapEmailsRetriever = {
retrieve: Sinon.stub()
} as any;
mocks.userDataStore.saveU2FRegistrationStub.returns(BluebirdPromise.resolve({}));
mocks.userDataStore.retrieveU2FRegistrationStub.returns(BluebirdPromise.resolve({}));
mocks.userDataStore.produceIdentityValidationTokenStub.returns(BluebirdPromise.resolve({}));
mocks.userDataStore.consumeIdentityValidationTokenStub.returns(BluebirdPromise.resolve({}));
res = ExpressMock.ResponseMock();
});
describe("test reset password identity pre check", () => {
it("should fail when no userid is provided", function () {
req.query.userid = undefined;
const handler = new PasswordResetHandler();
const handler = new PasswordResetHandler(vars.logger, vars.ldapEmailsRetriever);
return handler.preValidationInit(req as any)
.then(function () { return BluebirdPromise.reject("It should fail"); })
.catch(function (err: Error) {
@ -74,30 +60,18 @@ describe("test reset password identity check", function () {
});
});
it("should fail if ldap fail", function (done) {
(serverVariables.ldapEmailsRetriever as any).retrieve.returns(BluebirdPromise.reject("Internal error"));
new PasswordResetHandler().preValidationInit(req as any)
.catch(function (err: Error) {
done();
it("should fail if ldap fail", function () {
mocks.ldapEmailsRetriever.retrieveStub.returns(BluebirdPromise.reject("Internal error"));
new PasswordResetHandler(vars.logger, vars.ldapEmailsRetriever).preValidationInit(req as any)
.then(function () { return BluebirdPromise.reject(new Error("should not be here")); },
function (err: Error) {
return BluebirdPromise.resolve();
});
});
it("should perform a search in ldap to find email address", function (done) {
configuration.ldap.user_name_attribute = "uid";
(serverVariables.ldapEmailsRetriever as any).retrieve.returns(BluebirdPromise.resolve([]));
new PasswordResetHandler().preValidationInit(req as any)
.then(function () {
assert.equal("user", (serverVariables.ldapEmailsRetriever as any).retrieve.getCall(0).args[0]);
done();
});
});
it("should returns identity when ldap replies", function (done) {
(serverVariables.ldapEmailsRetriever as any).retrieve.returns(BluebirdPromise.resolve(["test@example.com"]));
new PasswordResetHandler().preValidationInit(req as any)
.then(function () {
done();
});
it("should returns identity when ldap replies", function () {
mocks.ldapEmailsRetriever.retrieveStub.returns(BluebirdPromise.resolve(["test@example.com"]));
return new PasswordResetHandler(vars.logger, vars.ldapEmailsRetriever).preValidationInit(req as any);
});
});
});

View File

@ -1,65 +1,60 @@
import PasswordResetFormPost = require("../../../src/lib/routes/password-reset/form/post");
import { PasswordUpdater } from "../../../src/lib/ldap/PasswordUpdater";
import AuthenticationSession = require("../../../src/lib/AuthenticationSession");
import { ServerVariablesHandler } from "../../../src/lib/ServerVariablesHandler";
import AuthenticationSessionHandler = require("../../../src/lib/AuthenticationSession");
import { UserDataStore } from "../../../src/lib/storage/UserDataStore";
import Sinon = require("sinon");
import winston = require("winston");
import Assert = require("assert");
import BluebirdPromise = require("bluebird");
import ExpressMock = require("../../mocks/express");
import ServerVariablesMock = require("../../mocks/ServerVariablesMock");
import { ServerVariablesMock, ServerVariablesMockBuilder } from "../../mocks/ServerVariablesMockBuilder";
import { ServerVariables } from "../../../src/lib/ServerVariables";
describe("test reset password route", function () {
let req: ExpressMock.RequestMock;
let res: ExpressMock.ResponseMock;
let configuration: any;
let serverVariables: ServerVariablesMock.ServerVariablesMock;
let vars: ServerVariables;
let mocks: ServerVariablesMock;
beforeEach(function () {
req = {
body: {
userid: "user"
},
app: {
get: Sinon.stub().returns({ logger: winston })
},
session: {},
headers: {
host: "localhost"
}
};
AuthenticationSession.reset(req as any);
const s = ServerVariablesMockBuilder.build();
mocks = s.mocks;
vars = s.variables;
const options = {
inMemoryOnly: true
};
serverVariables = ServerVariablesMock.mock(req.app);
serverVariables.userDataStore.saveU2FRegistrationStub.returns(BluebirdPromise.resolve({}));
serverVariables.userDataStore.retrieveU2FRegistrationStub.returns(BluebirdPromise.resolve({}));
serverVariables.userDataStore.produceIdentityValidationTokenStub.returns(BluebirdPromise.resolve({}));
serverVariables.userDataStore.consumeIdentityValidationTokenStub.returns(BluebirdPromise.resolve({}));
mocks.userDataStore.saveU2FRegistrationStub.returns(BluebirdPromise.resolve({}));
mocks.userDataStore.retrieveU2FRegistrationStub.returns(BluebirdPromise.resolve({}));
mocks.userDataStore.produceIdentityValidationTokenStub.returns(BluebirdPromise.resolve({}));
mocks.userDataStore.consumeIdentityValidationTokenStub.returns(BluebirdPromise.resolve({}));
configuration = {
ldap: {
base_dn: "dc=example,dc=com",
user_name_attribute: "cn"
}
mocks.config.ldap = {
url: "ldap://ldapjs",
mail_attribute: "mail",
user: "user",
password: "password",
users_dn: "ou=users,dc=example,dc=com",
groups_dn: "ou=groups,dc=example,dc=com",
users_filter: "user",
group_name_attribute: "cn",
groups_filter: "groups"
};
serverVariables.config = configuration;
serverVariables.ldapPasswordUpdater = {
updatePassword: Sinon.stub()
} as any;
res = ExpressMock.ResponseMock();
AuthenticationSession.get(req as any)
.then(function (authSession: AuthenticationSession.AuthenticationSession) {
AuthenticationSessionHandler.get(req as any, vars.logger)
.then(function (authSession) {
authSession.userid = "user";
authSession.email = "user@example.com";
authSession.first_factor = true;
@ -72,19 +67,19 @@ describe("test reset password route", function () {
req.body = {};
req.body.password = "new-password";
(serverVariables.ldapPasswordUpdater.updatePassword as sinon.SinonStub).returns(BluebirdPromise.resolve());
mocks.ldapPasswordUpdater.updatePasswordStub.returns(BluebirdPromise.resolve());
return AuthenticationSession.get(req as any)
return AuthenticationSessionHandler.get(req as any, vars.logger)
.then(function (authSession) {
authSession.identity_check = {
userid: "user",
challenge: "reset-password"
};
return PasswordResetFormPost.default(req as any, res as any);
return PasswordResetFormPost.default(vars)(req as any, res as any);
})
.then(function () {
return AuthenticationSession.get(req as any);
}).then(function (_authSession: AuthenticationSession.AuthenticationSession) {
return AuthenticationSessionHandler.get(req as any, vars.logger);
}).then(function (_authSession) {
Assert.equal(res.status.getCall(0).args[0], 204);
Assert.equal(_authSession.first_factor, false);
Assert.equal(_authSession.second_factor, false);
@ -93,13 +88,13 @@ describe("test reset password route", function () {
});
it("should fail if identity_challenge does not exist", function () {
return AuthenticationSession.get(req as any)
return AuthenticationSessionHandler.get(req as any, vars.logger)
.then(function (authSession) {
authSession.identity_check = {
userid: "user",
challenge: undefined
};
return PasswordResetFormPost.default(req as any, res as any);
return PasswordResetFormPost.default(vars)(req as any, res as any);
})
.then(function () {
Assert.equal(res.status.getCall(0).args[0], 200);
@ -113,16 +108,16 @@ describe("test reset password route", function () {
req.body = {};
req.body.password = "new-password";
(serverVariables.ldapPasswordUpdater.updatePassword as Sinon.SinonStub)
mocks.ldapPasswordUpdater.updatePasswordStub
.returns(BluebirdPromise.reject("Internal error with LDAP"));
return AuthenticationSession.get(req as any)
return AuthenticationSessionHandler.get(req as any, vars.logger)
.then(function (authSession) {
authSession.identity_check = {
challenge: "reset-password",
userid: "user"
};
return PasswordResetFormPost.default(req as any, res as any);
return PasswordResetFormPost.default(vars)(req as any, res as any);
}).then(function () {
Assert.equal(res.status.getCall(0).args[0], 200);
Assert.deepEqual(res.send.getCall(0).args[0], {

View File

@ -6,23 +6,30 @@ import AuthenticationSession = require("../../../../../src/lib/AuthenticationSes
import { UserDataStore } from "../../../../../src/lib/storage/UserDataStore";
import assert = require("assert");
import BluebirdPromise = require("bluebird");
import ExpressMock = require("../../../../mocks/express");
import ServerVariablesMock = require("../../../../mocks/ServerVariablesMock");
import { ServerVariablesMock, ServerVariablesMockBuilder } from "../../../../mocks/ServerVariablesMockBuilder";
import { ServerVariables } from "../../../../../src/lib/ServerVariables";
describe("test totp register", function () {
let req: ExpressMock.RequestMock;
let res: ExpressMock.ResponseMock;
const registrationHandler: RegistrationHandler = new RegistrationHandler();
let authSession: AuthenticationSession.AuthenticationSession;
let mocks: ServerVariablesMock;
let vars: ServerVariables;
beforeEach(function () {
const s = ServerVariablesMockBuilder.build();
mocks = s.mocks;
vars = s.variables;
req = ExpressMock.RequestMock();
const mocks = ServerVariablesMock.mock(req.app);
req.session = {};
AuthenticationSession.reset(req as any);
req.session = {
auth: {
userid: "user",
email: "user@example.com",
first_factor: true,
second_factor: false
}
};
req.headers = {};
req.headers.host = "localhost";
@ -37,23 +44,15 @@ describe("test totp register", function () {
mocks.userDataStore.saveTOTPSecretStub.returns(BluebirdPromise.resolve({}));
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);
function test_registration_check() {
it("should fail if first_factor has not been passed", function () {
authSession.first_factor = false;
return registrationHandler.preValidationInit(req as any)
req.session.auth.first_factor = false;
return new RegistrationHandler(vars.logger, vars.userDataStore, vars.totpHandler)
.preValidationInit(req as any)
.then(function () { return BluebirdPromise.reject(new Error("It should fail")); })
.catch(function (err: Error) {
return BluebirdPromise.resolve();
@ -61,27 +60,30 @@ describe("test totp register", function () {
});
it("should fail if userid is missing", function (done) {
authSession.first_factor = false;
authSession.userid = undefined;
req.session.auth.first_factor = false;
req.session.auth.userid = undefined;
registrationHandler.preValidationInit(req as any)
new RegistrationHandler(vars.logger, vars.userDataStore, vars.totpHandler)
.preValidationInit(req as any)
.catch(function (err: Error) {
done();
});
});
it("should fail if email is missing", function (done) {
authSession.first_factor = false;
authSession.email = undefined;
req.session.auth.first_factor = false;
req.session.auth.email = undefined;
registrationHandler.preValidationInit(req as any)
new RegistrationHandler(vars.logger, vars.userDataStore, vars.totpHandler)
.preValidationInit(req as any)
.catch(function (err: Error) {
done();
});
});
it("should succeed if first factor passed, userid and email are provided", function (done) {
registrationHandler.preValidationInit(req as any)
new RegistrationHandler(vars.logger, vars.userDataStore, vars.totpHandler)
.preValidationInit(req as any)
.then(function (identity: Identity) {
done();
});

View File

@ -5,7 +5,8 @@ import assert = require("assert");
import winston = require("winston");
import exceptions = require("../../../../../src/lib/Exceptions");
import AuthenticationSession = require("../../../../../src/lib/AuthenticationSession");
import AuthenticationSessionHandler = require("../../../../../src/lib/AuthenticationSession");
import { AuthenticationSession } from "../../../../../types/AuthenticationSession";
import SignPost = require("../../../../../src/lib/routes/secondfactor/totp/sign/post");
import { ServerVariables } from "../../../../../src/lib/ServerVariables";
@ -16,7 +17,7 @@ import { ServerVariablesMock, ServerVariablesMockBuilder } from "../../../../moc
describe("test totp route", function () {
let req: ExpressMock.RequestMock;
let res: ExpressMock.ResponseMock;
let authSession: AuthenticationSession.AuthenticationSession;
let authSession: AuthenticationSession;
let vars: ServerVariables;
let mocks: ServerVariablesMock;
@ -38,7 +39,6 @@ describe("test totp route", function () {
}
};
res = ExpressMock.ResponseMock();
AuthenticationSession.reset(req as any);
const doc = {
userid: "user",
@ -47,8 +47,8 @@ describe("test totp route", function () {
}
};
mocks.userDataStore.retrieveTOTPSecretStub.returns(BluebirdPromise.resolve(doc));
return AuthenticationSession.get(req as any)
.then(function (_authSession: AuthenticationSession.AuthenticationSession) {
return AuthenticationSessionHandler.get(req as any, vars.logger)
.then(function (_authSession) {
authSession = _authSession;
authSession.userid = "user";
authSession.first_factor = true;

View File

@ -9,19 +9,30 @@ import AuthenticationSession = require("../../../../../src/lib/AuthenticationSes
import ExpressMock = require("../../../../mocks/express");
import { UserDataStoreStub } from "../../../../mocks/storage/UserDataStoreStub";
import ServerVariablesMock = require("../../../../mocks/ServerVariablesMock");
import { ServerVariablesMock, ServerVariablesMockBuilder } from "../../../../mocks/ServerVariablesMockBuilder";
import { ServerVariables } from "../../../../../src/lib/ServerVariables";
describe("test register handler", function () {
let req: ExpressMock.RequestMock;
let res: ExpressMock.ResponseMock;
let authSession: AuthenticationSession.AuthenticationSession;
let mocks: ServerVariablesMock;
let vars: ServerVariables;
beforeEach(function () {
const s = ServerVariablesMockBuilder.build();
mocks = s.mocks;
vars = s.variables;
req = ExpressMock.RequestMock();
req.app = {};
const mocks = ServerVariablesMock.mock(req.app);
req.session = {};
AuthenticationSession.reset(req as any);
req.session = {
auth: {
userid: "user",
email: "user@example.com",
first_factor: true,
second_factor: false
}
};
req.headers = {};
req.headers.host = "localhost";
@ -38,23 +49,14 @@ describe("test register handler", function () {
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.email = "user@example.com";
authSession.first_factor = true;
authSession.second_factor = false;
});
});
describe("test u2f registration check", test_registration_check);
function test_registration_check() {
it("should fail if first_factor has not been passed", function () {
authSession.first_factor = false;
return new RegistrationHandler().preValidationInit(req as any)
req.session.auth.first_factor = false;
return new RegistrationHandler(vars.logger).preValidationInit(req as any)
.then(function () { return BluebirdPromise.reject(new Error("It should fail")); })
.catch(function (err: Error) {
return BluebirdPromise.resolve();
@ -62,27 +64,27 @@ describe("test register handler", function () {
});
it("should fail if userid is missing", function (done) {
authSession.first_factor = false;
authSession.userid = undefined;
req.session.auth.first_factor = false;
req.session.auth.userid = undefined;
new RegistrationHandler().preValidationInit(req as any)
new RegistrationHandler(vars.logger).preValidationInit(req as any)
.catch(function (err: Error) {
done();
});
});
it("should fail if email is missing", function (done) {
authSession.first_factor = false;
authSession.email = undefined;
req.session.auth.first_factor = false;
req.session.auth.email = undefined;
new RegistrationHandler().preValidationInit(req as any)
new RegistrationHandler(vars.logger).preValidationInit(req as any)
.catch(function (err: Error) {
done();
});
});
it("should succeed if first factor passed, userid and email are provided", function (done) {
new RegistrationHandler().preValidationInit(req as any)
new RegistrationHandler(vars.logger).preValidationInit(req as any)
.then(function (identity: Identity) {
done();
});

View File

@ -4,28 +4,39 @@ import BluebirdPromise = require("bluebird");
import assert = require("assert");
import U2FRegisterPost = require("../../../../../src/lib/routes/secondfactor/u2f/register/post");
import AuthenticationSession = require("../../../../../src/lib/AuthenticationSession");
import { ServerVariablesHandler } from "../../../../../src/lib/ServerVariablesHandler";
import winston = require("winston");
import ExpressMock = require("../../../../mocks/express");
import { UserDataStoreStub } from "../../../../mocks/storage/UserDataStoreStub";
import U2FMock = require("../../../../mocks/u2f");
import ServerVariablesMock = require("../../../../mocks/ServerVariablesMock");
import U2f = require("u2f");
import { ServerVariablesMockBuilder, ServerVariablesMock } from "../../../../mocks/ServerVariablesMockBuilder";
import { ServerVariables } from "../../../../../src/lib/ServerVariables";
describe("test u2f routes: register", function () {
let req: ExpressMock.RequestMock;
let res: ExpressMock.ResponseMock;
let mocks: ServerVariablesMock.ServerVariablesMock;
let mocks: ServerVariablesMock;
let vars: ServerVariables;
beforeEach(function () {
req = ExpressMock.RequestMock();
req.app = {};
mocks = ServerVariablesMock.mock(req.app);
req.session = {};
req.session = {
auth: {
userid: "user",
first_factor: true,
second_factor: false,
identity_check: {
challenge: "u2f-register",
userid: "user"
}
}
};
req.headers = {};
req.headers.host = "localhost";
const s = ServerVariablesMockBuilder.build();
mocks = s.mocks;
vars = s.variables;
const options = {
inMemoryOnly: true
};
@ -37,18 +48,6 @@ describe("test u2f routes: register", function () {
res.send = sinon.spy();
res.json = 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);
@ -61,11 +60,9 @@ describe("test u2f routes: register", function () {
publicKey: "pbk",
certificate: "cert"
};
const u2f_mock = U2FMock.U2FMock();
u2f_mock.checkRegistration.returns(BluebirdPromise.resolve(expectedStatus));
mocks.u2f = u2f_mock;
mocks.u2f.checkRegistrationStub.returns(BluebirdPromise.resolve(expectedStatus));
return AuthenticationSession.get(req as any)
return AuthenticationSession.get(req as any, vars.logger)
.then(function (authSession) {
authSession.register_request = {
appId: "app",
@ -73,10 +70,10 @@ describe("test u2f routes: register", function () {
keyHandle: "key",
version: "U2F_V2"
};
return U2FRegisterPost.default(req as any, res as any);
return U2FRegisterPost.default(vars)(req as any, res as any);
})
.then(function () {
return AuthenticationSession.get(req as any);
return AuthenticationSession.get(req as any, vars.logger);
})
.then(function (authSession) {
assert.equal("user", mocks.userDataStore.saveU2FRegistrationStub.getCall(0).args[0]);
@ -85,12 +82,9 @@ describe("test u2f routes: register", function () {
});
it("should return error message on finishRegistration error", function () {
const user_key_container = {};
const u2f_mock = U2FMock.U2FMock();
u2f_mock.checkRegistration.returns({ errorCode: 500 });
mocks.u2f = u2f_mock;
mocks.u2f.checkRegistrationStub.returns({ errorCode: 500 });
return AuthenticationSession.get(req as any)
return AuthenticationSession.get(req as any, vars.logger)
.then(function (authSession) {
authSession.register_request = {
appId: "app",
@ -99,7 +93,7 @@ describe("test u2f routes: register", function () {
version: "U2F_V2"
};
return U2FRegisterPost.default(req as any, res as any);
return U2FRegisterPost.default(vars)(req as any, res as any);
})
.then(function () { return BluebirdPromise.reject(new Error("It should fail")); })
.catch(function () {
@ -112,15 +106,11 @@ describe("test u2f routes: register", function () {
});
it("should return error message when register_request is not provided", function () {
const user_key_container = {};
const u2f_mock = U2FMock.U2FMock();
u2f_mock.checkRegistration.returns(BluebirdPromise.resolve());
mocks.u2f = u2f_mock;
return AuthenticationSession.get(req as any)
mocks.u2f.checkRegistrationStub.returns(BluebirdPromise.resolve());
return AuthenticationSession.get(req as any, vars.logger)
.then(function (authSession) {
authSession.register_request = undefined;
return U2FRegisterPost.default(req as any, res as any);
return U2FRegisterPost.default(vars)(req as any, res as any);
})
.then(function () { return BluebirdPromise.reject(new Error("It should fail")); })
.catch(function () {
@ -133,15 +123,11 @@ describe("test u2f routes: register", function () {
});
it("should return error message when no auth request has been initiated", function () {
const user_key_container = {};
const u2f_mock = U2FMock.U2FMock();
u2f_mock.checkRegistration.returns(BluebirdPromise.resolve());
mocks.u2f = u2f_mock;
return AuthenticationSession.get(req as any)
mocks.u2f.checkRegistrationStub.returns(BluebirdPromise.resolve());
return AuthenticationSession.get(req as any, vars.logger)
.then(function (authSession) {
authSession.register_request = undefined;
return U2FRegisterPost.default(req as any, res as any);
return U2FRegisterPost.default(vars)(req as any, res as any);
})
.then(function () { return BluebirdPromise.reject(new Error("It should fail")); })
.catch(function () {
@ -154,10 +140,10 @@ describe("test u2f routes: register", function () {
});
it("should return error message when identity has not been verified", function () {
return AuthenticationSession.get(req as any)
return AuthenticationSession.get(req as any, vars.logger)
.then(function (authSession) {
authSession.identity_check = undefined;
return U2FRegisterPost.default(req as any, res as any);
return U2FRegisterPost.default(vars)(req as any, res as any);
})
.then(function () { return BluebirdPromise.reject(new Error("It should fail")); })
.catch(function () {

View File

@ -4,36 +4,42 @@ import BluebirdPromise = require("bluebird");
import Assert = require("assert");
import U2FRegisterRequestGet = require("../../../../../src/lib/routes/secondfactor/u2f/register_request/get");
import AuthenticationSession = require("../../../../../src/lib/AuthenticationSession");
import { ServerVariablesHandler } from "../../../../../src/lib/ServerVariablesHandler";
import winston = require("winston");
import ExpressMock = require("../../../../mocks/express");
import { UserDataStoreStub } from "../../../../mocks/storage/UserDataStoreStub";
import U2FMock = require("../../../../mocks/u2f");
import ServerVariablesMock = require("../../../../mocks/ServerVariablesMock");
import U2f = require("u2f");
import { ServerVariablesMockBuilder, ServerVariablesMock } from "../../../../mocks/ServerVariablesMockBuilder";
import { ServerVariables } from "../../../../../src/lib/ServerVariables";
describe("test u2f routes: register_request", function () {
let req: ExpressMock.RequestMock;
let res: ExpressMock.ResponseMock;
let mocks: ServerVariablesMock.ServerVariablesMock;
let authSession: AuthenticationSession.AuthenticationSession;
let mocks: ServerVariablesMock;
let vars: ServerVariables;
beforeEach(function () {
req = ExpressMock.RequestMock();
req.app = {};
mocks = ServerVariablesMock.mock(req.app);
req.session = {};
AuthenticationSession.reset(req as any);
req.session = {
auth: {
userid: "user",
first_factor: true,
second_factor: false,
identity_check: {
challenge: "u2f-register",
userid: "user"
}
}
};
req.headers = {};
req.headers.host = "localhost";
const s = ServerVariablesMockBuilder.build();
mocks = s.mocks;
vars = s.variables;
const options = {
inMemoryOnly: true
};
mocks.userDataStore.saveU2FRegistrationStub.returns(BluebirdPromise.resolve({}));
mocks.userDataStore.retrieveU2FRegistrationStub.returns(BluebirdPromise.resolve({}));
@ -41,18 +47,6 @@ describe("test u2f routes: register_request", function () {
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.first_factor = true;
authSession.second_factor = false;
authSession.identity_check = {
challenge: "u2f-register",
userid: "user"
};
});
});
describe("test registration request", () => {
@ -60,12 +54,8 @@ describe("test u2f routes: register_request", function () {
const expectedRequest = {
test: "abc"
};
const user_key_container = {};
const u2f_mock = U2FMock.U2FMock();
u2f_mock.request.returns(BluebirdPromise.resolve(expectedRequest));
mocks.u2f = u2f_mock;
return U2FRegisterRequestGet.default(req as any, res as any)
mocks.u2f.requestStub.returns(BluebirdPromise.resolve(expectedRequest));
return U2FRegisterRequestGet.default(vars)(req as any, res as any)
.then(function () {
Assert.deepEqual(expectedRequest, res.json.getCall(0).args[0]);
});
@ -74,12 +64,9 @@ describe("test u2f routes: register_request", function () {
it("should return internal error on registration request", function () {
res.send = sinon.spy();
const user_key_container = {};
const u2f_mock = U2FMock.U2FMock();
u2f_mock.request.returns(BluebirdPromise.reject("Internal error"));
mocks.u2f = u2f_mock;
return U2FRegisterRequestGet.default(req as any, res as any)
.then(function() {
mocks.u2f.requestStub.returns(BluebirdPromise.reject("Internal error"));
return U2FRegisterRequestGet.default(vars)(req as any, res as any)
.then(function () {
Assert.equal(res.status.getCall(0).args[0], 200);
Assert.deepEqual(res.send.getCall(0).args[0], {
error: "Operation failed."
@ -88,8 +75,8 @@ describe("test u2f routes: register_request", function () {
});
it("should return forbidden if identity has not been verified", function () {
authSession.identity_check = undefined;
return U2FRegisterRequestGet.default(req as any, res as any)
req.session.auth.identity_check = undefined;
return U2FRegisterRequestGet.default(vars)(req as any, res as any)
.then(function () {
Assert.equal(403, res.status.getCall(0).args[0]);
});

View File

@ -4,27 +4,39 @@ import BluebirdPromise = require("bluebird");
import Assert = require("assert");
import U2FSignPost = require("../../../../../src/lib/routes/secondfactor/u2f/sign/post");
import AuthenticationSession = require("../../../../../src/lib/AuthenticationSession");
import { ServerVariablesHandler } from "../../../../../src/lib/ServerVariablesHandler";
import { ServerVariables } from "../../../../../src/lib/ServerVariables";
import winston = require("winston");
import { ServerVariablesMockBuilder, ServerVariablesMock } from "../../../../mocks/ServerVariablesMockBuilder";
import ExpressMock = require("../../../../mocks/express");
import ServerVariablesMock = require("../../../../mocks/ServerVariablesMock");
import U2FMock = require("../../../../mocks/u2f");
import U2f = require("u2f");
describe("test u2f routes: sign", function () {
let req: ExpressMock.RequestMock;
let res: ExpressMock.ResponseMock;
let authSession: AuthenticationSession.AuthenticationSession;
let mocks: ServerVariablesMock.ServerVariablesMock;
let mocks: ServerVariablesMock;
let vars: ServerVariables;
beforeEach(function () {
req = ExpressMock.RequestMock();
req.app = {};
mocks = ServerVariablesMock.mock(req.app);
req.session = {};
AuthenticationSession.reset(req as any);
const s = ServerVariablesMockBuilder.build();
mocks = s.mocks;
vars = s.variables;
req.session = {
auth: {
userid: "user",
first_factor: true,
second_factor: false,
identity_check: {
challenge: "u2f-register",
userid: "user"
}
}
};
req.headers = {};
req.headers.host = "localhost";
@ -36,18 +48,6 @@ describe("test u2f routes: sign", function () {
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.first_factor = true;
authSession.second_factor = false;
authSession.identity_check = {
challenge: "u2f-register",
userid: "user"
};
});
});
it("should return status code 204", function () {
@ -56,8 +56,7 @@ describe("test u2f routes: sign", function () {
publicKey: "pbk",
certificate: "cert"
};
const u2f_mock = U2FMock.U2FMock();
u2f_mock.checkSignature.returns(expectedStatus);
mocks.u2f.checkSignatureStub.returns(expectedStatus);
mocks.userDataStore.retrieveU2FRegistrationStub.returns(BluebirdPromise.resolve({
registration: {
@ -65,16 +64,15 @@ describe("test u2f routes: sign", function () {
}
}));
authSession.sign_request = {
req.session.auth.sign_request = {
appId: "app",
challenge: "challenge",
keyHandle: "key",
version: "U2F_V2"
};
mocks.u2f = u2f_mock;
return U2FSignPost.default(req as any, res as any)
return U2FSignPost.default(vars)(req as any, res as any)
.then(function () {
Assert(authSession.second_factor);
Assert(req.session.auth.second_factor);
});
});
@ -84,18 +82,15 @@ describe("test u2f routes: sign", function () {
publicKey: "PUBKEY"
}
}));
mocks.u2f.checkSignatureStub.returns({ errorCode: 500 });
const u2f_mock = U2FMock.U2FMock();
u2f_mock.checkSignature.returns({ errorCode: 500 });
authSession.sign_request = {
req.session.auth.sign_request = {
appId: "app",
challenge: "challenge",
keyHandle: "key",
version: "U2F_V2"
};
mocks.u2f = u2f_mock;
return U2FSignPost.default(req as any, res as any)
return U2FSignPost.default(vars)(req as any, res as any)
.then(function () {
Assert.equal(res.status.getCall(0).args[0], 200);
Assert.deepEqual(res.send.getCall(0).args[0],

View File

@ -3,37 +3,44 @@ import sinon = require("sinon");
import BluebirdPromise = require("bluebird");
import assert = require("assert");
import U2FSignRequestGet = require("../../../../../src/lib/routes/secondfactor/u2f/sign_request/get");
import AuthenticationSession = require("../../../../../src/lib/AuthenticationSession");
import { ServerVariablesHandler } from "../../../../../src/lib/ServerVariablesHandler";
import winston = require("winston");
import AuthenticationSessionHandler = require("../../../../../src/lib/AuthenticationSession");
import { AuthenticationSession } from "../../../../../types/AuthenticationSession";
import ExpressMock = require("../../../../mocks/express");
import { UserDataStoreStub } from "../../../../mocks/storage/UserDataStoreStub";
import ServerVariablesMock = require("../../../../mocks/ServerVariablesMock");
import U2FMock = require("../../../../mocks/u2f");
import U2f = require("u2f");
import { ServerVariablesMock, ServerVariablesMockBuilder } from "../../../../mocks/ServerVariablesMockBuilder";
import { ServerVariables } from "../../../../../src/lib/ServerVariables";
import { SignMessage } from "../../../../../../shared/SignMessage";
describe("test u2f routes: sign_request", function () {
let req: ExpressMock.RequestMock;
let res: ExpressMock.ResponseMock;
let mocks: ServerVariablesMock.ServerVariablesMock;
let authSession: AuthenticationSession.AuthenticationSession;
let mocks: ServerVariablesMock;
let vars: ServerVariables;
beforeEach(function () {
req = ExpressMock.RequestMock();
req.app = {};
mocks = ServerVariablesMock.mock(req.app);
req.session = {};
AuthenticationSession.reset(req as any);
req.session = {
auth: {
userid: "user",
first_factor: true,
second_factor: false,
identity_check: {
challenge: "u2f-register",
userid: "user"
}
}
};
req.headers = {};
req.headers.host = "localhost";
const s = ServerVariablesMockBuilder.build();
mocks = s.mocks;
vars = s.variables;
const options = {
inMemoryOnly: true
};
@ -42,18 +49,6 @@ describe("test u2f routes: sign_request", function () {
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.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 () {
@ -63,9 +58,7 @@ describe("test u2f routes: sign_request", function () {
certificate: "Certificate",
successful: true
};
const u2f_mock = U2FMock.U2FMock();
u2f_mock.request.returns(expectedRequest);
mocks.u2f.requestStub.returns(expectedRequest);
mocks.userDataStore.retrieveU2FRegistrationStub.returns(BluebirdPromise.resolve({
registration: {
publicKey: "PUBKEY",
@ -73,10 +66,9 @@ describe("test u2f routes: sign_request", function () {
}
}));
mocks.u2f = u2f_mock;
return U2FSignRequestGet.default(req as any, res as any)
return U2FSignRequestGet.default(vars)(req as any, res as any)
.then(function () {
assert.deepEqual(expectedRequest, authSession.sign_request);
assert.deepEqual(expectedRequest, req.session.auth.sign_request);
assert.deepEqual(expectedRequest, res.json.getCall(0).args[0].request);
});
});

View File

@ -1,7 +1,8 @@
import Assert = require("assert");
import VerifyGet = require("../../../src/lib/routes/verify/get");
import AuthenticationSession = require("../../../src/lib/AuthenticationSession");
import AuthenticationSessionHandler = require("../../../src/lib/AuthenticationSession");
import { AuthenticationSession } from "../../../types/AuthenticationSession";
import { AuthenticationMethodCalculator } from "../../../src/lib/AuthenticationMethodCalculator";
import { AuthenticationMethodsConfiguration } from "../../../src/lib/configuration/Configuration";
import Sinon = require("sinon");
@ -28,7 +29,7 @@ describe("test /verify endpoint", function () {
req.app = {
get: Sinon.stub().returns({ logger: winston })
};
AuthenticationSession.reset(req as any);
AuthenticationSessionHandler.reset(req as any);
req.headers = {};
req.headers.host = "secret.example.com";
const s = ServerVariablesMockBuilder.build();
@ -39,9 +40,9 @@ describe("test /verify endpoint", function () {
it("should be already authenticated", function () {
req.session = {};
mocks.accessController.isAccessAllowedMock.returns(true);
AuthenticationSession.reset(req as any);
return AuthenticationSession.get(req as any)
.then(function (authSession: AuthenticationSession.AuthenticationSession) {
AuthenticationSessionHandler.reset(req as any);
return AuthenticationSessionHandler.get(req as any, vars.logger)
.then(function (authSession) {
authSession.first_factor = true;
authSession.second_factor = true;
authSession.userid = "myuser";
@ -55,8 +56,8 @@ describe("test /verify endpoint", function () {
});
});
function test_session(_authSession: AuthenticationSession.AuthenticationSession, status_code: number) {
return AuthenticationSession.get(req as any)
function test_session(_authSession: AuthenticationSession, status_code: number) {
return AuthenticationSessionHandler.get(req as any, vars.logger)
.then(function (authSession) {
authSession = _authSession;
return VerifyGet.default(vars)(req as express.Request, res as any);
@ -66,15 +67,15 @@ describe("test /verify endpoint", function () {
});
}
function test_non_authenticated_401(authSession: AuthenticationSession.AuthenticationSession) {
function test_non_authenticated_401(authSession: AuthenticationSession) {
return test_session(authSession, 401);
}
function test_unauthorized_403(authSession: AuthenticationSession.AuthenticationSession) {
function test_unauthorized_403(authSession: AuthenticationSession) {
return test_session(authSession, 403);
}
function test_authorized(authSession: AuthenticationSession.AuthenticationSession) {
function test_authorized(authSession: AuthenticationSession) {
return test_session(authSession, 204);
}
@ -133,7 +134,7 @@ describe("test /verify endpoint", function () {
});
it("should not be authenticated when domain is not allowed for user", function () {
return AuthenticationSession.get(req as any)
return AuthenticationSessionHandler.get(req as any, vars.logger)
.then(function (authSession) {
authSession.first_factor = true;
authSession.second_factor = true;
@ -167,7 +168,7 @@ describe("test /verify endpoint", function () {
it("should be authenticated when first factor is validated and second factor is not", function () {
mocks.accessController.isAccessAllowedMock.returns(true);
return AuthenticationSession.get(req as any)
return AuthenticationSessionHandler.get(req as any, vars.logger)
.then(function (authSession) {
authSession.first_factor = true;
authSession.userid = "user1";
@ -181,7 +182,7 @@ describe("test /verify endpoint", function () {
it("should be rejected with 401 when first factor is not validated", function () {
mocks.accessController.isAccessAllowedMock.returns(true);
return AuthenticationSession.get(req as any)
return AuthenticationSessionHandler.get(req as any, vars.logger)
.then(function (authSession) {
authSession.first_factor = false;
return VerifyGet.default(vars)(req as express.Request, res as any);
@ -197,9 +198,9 @@ describe("test /verify endpoint", function () {
mocks.config.session.inactivity = 200000;
mocks.accessController.isAccessAllowedMock.returns(true);
const currentTime = new Date().getTime() - 1000;
AuthenticationSession.reset(req as any);
return AuthenticationSession.get(req as any)
.then(function (authSession: AuthenticationSession.AuthenticationSession) {
AuthenticationSessionHandler.reset(req as any);
return AuthenticationSessionHandler.get(req as any, vars.logger)
.then(function (authSession) {
authSession.first_factor = true;
authSession.second_factor = true;
authSession.userid = "myuser";
@ -208,7 +209,7 @@ describe("test /verify endpoint", function () {
return VerifyGet.default(vars)(req as express.Request, res as any);
})
.then(function () {
return AuthenticationSession.get(req as any);
return AuthenticationSessionHandler.get(req as any, vars.logger);
})
.then(function (authSession) {
Assert(authSession.last_activity_datetime > currentTime);
@ -219,9 +220,9 @@ describe("test /verify endpoint", function () {
mocks.config.session.inactivity = 1;
mocks.accessController.isAccessAllowedMock.returns(true);
const currentTime = new Date().getTime() - 1000;
AuthenticationSession.reset(req as any);
return AuthenticationSession.get(req as any)
.then(function (authSession: AuthenticationSession.AuthenticationSession) {
AuthenticationSessionHandler.reset(req as any);
return AuthenticationSessionHandler.get(req as any, vars.logger)
.then(function (authSession) {
authSession.first_factor = true;
authSession.second_factor = true;
authSession.userid = "myuser";
@ -230,7 +231,7 @@ describe("test /verify endpoint", function () {
return VerifyGet.default(vars)(req as express.Request, res as any);
})
.then(function () {
return AuthenticationSession.get(req as any);
return AuthenticationSessionHandler.get(req as any, vars.logger);
})
.then(function (authSession) {
Assert.equal(authSession.first_factor, false);

View File

@ -0,0 +1,17 @@
import U2f = require("u2f");
export interface AuthenticationSession {
userid: string;
first_factor: boolean;
second_factor: boolean;
last_activity_datetime: number;
identity_check?: {
challenge: string;
userid: string;
};
register_request?: U2f.Request;
sign_request?: U2f.Request;
email: string;
groups: string[];
redirect?: string;
}

4
shared/ErrorMessage.ts Normal file
View File

@ -0,0 +1,4 @@
export interface ErrorMessage {
error: string;
}

View File

@ -0,0 +1,4 @@
export interface RedirectionMessage {
redirect: string;
}

View File

@ -10,7 +10,7 @@ Feature: User is redirected when factors are already validated
Then I'm redirected to "https://auth.test.local:8080/secondfactor?redirect=https%3A%2F%2Fpublic.test.local%3A8080%2Fsecret.html"
@need-registered-user-john
Scenario: User who has validated second factor and access auth portal should be redirected to "Already logged in page"
Scenario: User who has validated second factor and access auth portal should be redirected to "Already logged in page" and redirected to default URL declared in configuration
When I visit "https://public.test.local:8080/secret.html"
And I'm redirected to "https://auth.test.local:8080/?redirect=https%3A%2F%2Fpublic.test.local%3A8080%2Fsecret.html"
And I login with user "john" and password "password"
@ -19,6 +19,8 @@ Feature: User is redirected when factors are already validated
And I'm redirected to "https://public.test.local:8080/secret.html"
And I visit "https://auth.test.local:8080"
Then I'm redirected to "https://auth.test.local:8080/loggedin"
And I sleep for 5 seconds
And I'm redirected to "https://home.test.local:8080/"
@need-registered-user-john
Scenario: User who has validated second factor and access auth portal with rediction param should be redirected to that URL

View File

@ -41,3 +41,11 @@ Feature: User is correctly redirected
And I use "Sec0" as TOTP token handle
And I click on "TOTP"
Then I'm redirected to "https://public.test.local:8080/secret.html"
@need-registered-user-john
Scenario: User is redirected to default URL defined in configuration when authentication is successful
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'm redirected to "https://home.test.local:8080/"