authelia/server/test/IdentityCheckMiddleware.test.ts
Clement Michaud 563e2da323 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.
2017-10-31 07:27:23 +01:00

174 lines
6.9 KiB
TypeScript

import sinon = require("sinon");
import IdentityValidator = require("../src/lib/IdentityCheckMiddleware");
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 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";
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.session = {};
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", test_start_get_handler);
describe("test finish GET", test_finish_get_handler);
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", vars);
return callback(req as any, res as any, undefined)
.then(function () { return BluebirdPromise.reject("Should fail"); })
.catch(function () {
Assert.equal(res.status.getCall(0).args[0], 401);
});
});
it("should send 401 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 () { return BluebirdPromise.reject("Should fail"); })
.catch(function () {
Assert.equal(res.status.getCall(0).args[0], 401);
});
});
it("should send 401 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 () { return BluebirdPromise.reject(new Error("It should fail")); })
.catch(function (err: Error) {
Assert.equal(res.status.getCall(0).args[0], 401);
return BluebirdPromise.resolve();
});
});
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);
});
});
}
function test_finish_get_handler() {
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.equal(res.status.getCall(0).args[0], 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.equal(res.status.getCall(0).args[0], 401);
});
});
it("should set the identity_check session object even if session does not exist yet", function () {
req.query.identity_token = "token";
req.session = {};
let authSession: AuthenticationSession;
const callback = IdentityValidator.get_finish_validation(identityValidable, vars);
return AuthenticationSessionHandler.get(req as any, vars.logger)
.then(function (_authSession) {
authSession = _authSession;
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");
return BluebirdPromise.resolve();
});
});
}
});