authelia/server/test/IdentityCheckMiddleware.tes...

201 lines
7.0 KiB
TypeScript

import sinon = require("sinon");
import IdentityValidator = require("../src/lib/IdentityCheckMiddleware");
import { AuthenticationSessionHandler }
from "../src/lib/AuthenticationSessionHandler";
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 express = require("express");
import BluebirdPromise = require("bluebird");
import ExpressMock = require("./mocks/express");
import NotifierMock = require("./mocks/Notifier");
import IdentityValidatorMock = require("./mocks/IdentityValidator");
import { RequestLoggerStub } from "./mocks/RequestLoggerStub";
import { ServerVariablesMock, ServerVariablesMockBuilder }
from "./mocks/ServerVariablesMockBuilder";
import { PRE_VALIDATION_TEMPLATE }
from "../src/lib/IdentityCheckPreValidationTemplate";
describe("test identity check process", function () {
let req: ExpressMock.RequestMock;
let res: ExpressMock.ResponseMock;
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();
req.headers = {};
req.originalUrl = "/non-api/xxx";
req.session = {};
req.query = {};
req.app = {};
mocks.notifier.notifyStub.returns(BluebirdPromise.resolve());
mocks.userDataStore.produceIdentityValidationTokenStub
.returns(Promise.resolve());
mocks.userDataStore.consumeIdentityValidationTokenStub
.returns(Promise.resolve({ userId: "user" }));
app = express();
app_get = sinon.stub(app, "get");
app_post = sinon.stub(app, "post");
});
afterEach(function () {
app_get.restore();
app_post.restore();
});
describe("test start GET", function () {
it("should redirect to error 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", vars);
return callback(req as any, res as any, undefined)
.then(function () { return BluebirdPromise.reject("Should fail"); })
.catch(function () {
Assert(res.redirect.calledWith("/error/401"));
});
});
// In that case we answer with 200 to avoid user enumeration.
it("should send 200 if email is missing in provided identity", function () {
const identity = { userid: "abc" };
identityValidable.preValidationInit
.returns(BluebirdPromise.resolve(identity));
const callback = IdentityValidator
.get_start_validation(identityValidable, "/endpoint", vars);
return callback(req as any, res as any, undefined)
.then(function () {
Assert(identityValidable.preValidationResponse.called);
});
});
// In that case we answer with 200 to avoid user enumeration.
it("should send 200 if userid is missing in provided identity",
function () {
const endpoint = "/protected";
const identity = { email: "abc@example.com" };
identityValidable.preValidationInit
.returns(BluebirdPromise.resolve(identity));
const callback = IdentityValidator
.get_start_validation(identityValidable, "/endpoint", vars);
return callback(req as any, res as any, undefined)
.then(function () {
Assert(identityValidable.preValidationResponse.called);
});
});
it("should issue a token, send an email and return 204", function () {
const endpoint = "/protected";
const identity = { userid: "user", email: "abc@example.com" };
req.get = sinon.stub().withArgs("Host").returns("localhost");
identityValidable.preValidationInit
.returns(BluebirdPromise.resolve(identity));
const callback = IdentityValidator
.get_start_validation(identityValidable, "/finish_endpoint", vars);
return callback(req as any, res as any, undefined)
.then(function () {
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);
});
});
});
describe("test finish GET", function () {
it("should send 401 if no identity_token is provided", function () {
const callback = IdentityValidator
.get_finish_validation(identityValidable, vars);
return callback(req as any, res as any, undefined)
.then(function () {
return BluebirdPromise.reject("Should fail");
})
.catch(function () {
Assert(res.redirect.calledWith("/error/401"));
});
});
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, vars);
return callback(req as any, res as any, undefined);
});
it("should return 401 if identity_token is provided but invalid",
function () {
req.query.identity_token = "token";
mocks.userDataStore.consumeIdentityValidationTokenStub
.returns(BluebirdPromise.reject(new Error("Invalid token")));
const callback = IdentityValidator
.get_finish_validation(identityValidable, vars);
return callback(req as any, res as any, undefined)
.then(function () {
return BluebirdPromise.reject("Should fail");
})
.catch(function () {
Assert(res.redirect.calledWith("/error/401"));
});
});
it("should set the identity_check session object even if session does \
not exist yet", function () {
req.query.identity_token = "token";
req.session = {};
const authSession =
AuthenticationSessionHandler.get(req as any, vars.logger);
const callback = IdentityValidator
.get_finish_validation(identityValidable, vars);
return callback(req as any, res as any, undefined)
.then(function () {
return BluebirdPromise.reject("Should fail");
})
.catch(function () {
Assert.equal(authSession.identity_check.userid, "user");
});
});
});
});