authelia/test/unitary/IdentityValidator.test.ts

243 lines
8.8 KiB
TypeScript

import sinon = require("sinon");
import IdentityValidator = require("../../src/lib/IdentityValidator");
import exceptions = require("../../src/lib/Exceptions");
import assert = require("assert");
import winston = require("winston");
import Promise = require("bluebird");
import express = require("express");
import BluebirdPromise = require("bluebird");
import ExpressMock = require("./mocks/express");
import UserDataStoreMock = require("./mocks/UserDataStore");
import NotifierMock = require("./mocks/Notifier");
import IdentityValidatorMock = require("./mocks/IdentityValidator");
describe("test identity check process", function () {
let req: ExpressMock.RequestMock;
let res: ExpressMock.ResponseMock;
let userDataStore: UserDataStoreMock.UserDataStore;
let notifier: NotifierMock.NotifierMock;
let app: express.Application;
let app_get: sinon.SinonStub;
let app_post: sinon.SinonStub;
let identityValidable: IdentityValidatorMock.IdentityValidableMock;
beforeEach(function () {
req = ExpressMock.RequestMock();
res = ExpressMock.ResponseMock();
userDataStore = UserDataStoreMock.UserDataStore();
userDataStore.issue_identity_check_token = sinon.stub();
userDataStore.issue_identity_check_token.returns(Promise.resolve());
userDataStore.consume_identity_check_token = sinon.stub();
userDataStore.consume_identity_check_token.returns(Promise.resolve({ userid: "user" }));
notifier = NotifierMock.NotifierMock();
notifier.notify = sinon.stub().returns(Promise.resolve());
req.headers = {};
req.session = {};
req.session.auth_session = {};
req.query = {};
req.app = {};
req.app.get = sinon.stub();
req.app.get.withArgs("logger").returns(winston);
req.app.get.withArgs("user data store").returns(userDataStore);
req.app.get.withArgs("notifier").returns(notifier);
app = express();
app_get = sinon.stub(app, "get");
app_post = sinon.stub(app, "post");
identityValidable = IdentityValidatorMock.IdentityValidableMock();
});
afterEach(function () {
app_get.restore();
app_post.restore();
});
it("should register a POST and GET endpoint", function () {
const endpoint = "/test";
const icheck_interface = {};
IdentityValidator.IdentityValidator.setup(app, endpoint, identityValidable, userDataStore as any, winston);
assert(app_get.calledOnce);
assert(app_get.calledWith(endpoint));
assert(app_post.calledOnce);
assert(app_post.calledWith(endpoint));
});
describe("test POST", test_post_handler);
describe("test GET", test_get_handler);
function test_post_handler() {
it("should send 403 if pre check rejects", function (done) {
const endpoint = "/protected";
identityValidable.preValidation.returns(Promise.reject("No access"));
IdentityValidator.IdentityValidator.setup(app, endpoint, identityValidable, userDataStore as any, winston);
res.send = sinon.spy(function () {
assert.equal(res.status.getCall(0).args[0], 403);
done();
});
const handler = app_post.getCall(0).args[1];
handler(req, res);
});
it("should send 400 if email is missing in provided identity", function (done) {
const endpoint = "/protected";
const identity = { userid: "abc" };
identityValidable.preValidation.returns(Promise.resolve(identity));
IdentityValidator.IdentityValidator.setup(app, endpoint, identityValidable, userDataStore as any, winston);
res.send = sinon.spy(function () {
assert.equal(res.status.getCall(0).args[0], 400);
done();
});
const handler = app_post.getCall(0).args[1];
handler(req, res);
});
it("should send 400 if userid is missing in provided identity", function (done) {
const endpoint = "/protected";
const identity = { email: "abc@example.com" };
identityValidable.preValidation.returns(Promise.resolve(identity));
IdentityValidator.IdentityValidator.setup(app, endpoint, identityValidable, userDataStore as any, winston);
res.send = sinon.spy(function () {
assert.equal(res.status.getCall(0).args[0], 400);
done();
});
const handler = app_post.getCall(0).args[1];
handler(req, res);
});
describe("should issue a token, send an email and return 204", () => {
function contains(str: string, pattern: string): boolean {
return str.indexOf(pattern) > -1;
}
it("with x-original-uri", function(done) {
const endpoint = "/protected";
const identity = { userid: "user", email: "abc@example.com" };
req.headers.host = "localhost";
req.headers["x-original-uri"] = "/auth/test";
identityValidable.preValidation.returns(Promise.resolve(identity));
IdentityValidator.IdentityValidator.setup(app, endpoint, identityValidable, userDataStore as any, winston);
res.send = sinon.spy(function () {
assert.equal(res.status.getCall(0).args[0], 204);
assert(notifier.notify.calledOnce);
console.log(notifier.notify.getCall(0).args[2]);
assert(contains(notifier.notify.getCall(0).args[2], "https://localhost/auth/test?identity_token="));
assert(userDataStore.issue_identity_check_token.calledOnce);
assert.equal(userDataStore.issue_identity_check_token.getCall(0).args[0], "user");
assert.equal(userDataStore.issue_identity_check_token.getCall(0).args[3], 240000);
done();
});
const handler = app_post.getCall(0).args[1];
handler(req, res);
});
it("without x-original-uri", function(done) {
const endpoint = "/protected";
const identity = { userid: "user", email: "abc@example.com" };
req.headers.host = "localhost";
identityValidable.preValidation.returns(Promise.resolve(identity));
IdentityValidator.IdentityValidator.setup(app, endpoint, identityValidable, userDataStore as any, winston);
res.send = sinon.spy(function () {
assert.equal(res.status.getCall(0).args[0], 204);
assert(notifier.notify.calledOnce);
assert(contains(notifier.notify.getCall(0).args[2], "https://localhost?identity_token="));
assert(userDataStore.issue_identity_check_token.calledOnce);
assert.equal(userDataStore.issue_identity_check_token.getCall(0).args[0], "user");
assert.equal(userDataStore.issue_identity_check_token.getCall(0).args[3], 240000);
done();
});
const handler = app_post.getCall(0).args[1];
handler(req, res);
});
});
}
function test_get_handler() {
it("should send 403 if no identity_token is provided", function (done) {
const endpoint = "/protected";
IdentityValidator.IdentityValidator.setup(app, endpoint, identityValidable, userDataStore as any, winston);
res.send = sinon.spy(function () {
assert.equal(res.status.getCall(0).args[0], 403);
done();
});
const handler = app_get.getCall(0).args[1];
handler(req, res);
});
it("should render template if identity_token is provided and still valid", function (done) {
req.query.identity_token = "token";
const endpoint = "/protected";
identityValidable.templateName.returns("template");
IdentityValidator.IdentityValidator.setup(app, endpoint, identityValidable, userDataStore as any, winston);
res.render = sinon.spy(function (template: string) {
assert.equal(template, "template");
done();
});
const handler = app_get.getCall(0).args[1];
handler(req, res);
});
it("should return 403 if identity_token is provided but invalid", function (done) {
req.query.identity_token = "token";
const endpoint = "/protected";
identityValidable.templateName.returns("template");
userDataStore.consume_identity_check_token
.returns(Promise.reject("Invalid token"));
IdentityValidator.IdentityValidator.setup(app, endpoint, identityValidable, userDataStore as any, winston);
res.send = sinon.spy(function (template: string) {
assert.equal(res.status.getCall(0).args[0], 403);
done();
});
const handler = app_get.getCall(0).args[1];
handler(req, res);
});
it("should set the identity_check session object even if session does not exist yet", function (done) {
req.query.identity_token = "token";
const endpoint = "/protected";
req.session = {};
identityValidable.templateName.returns("template");
IdentityValidator.IdentityValidator.setup(app, endpoint, identityValidable, userDataStore as any, winston);
res.render = sinon.spy(function (template: string) {
assert.equal(req.session.auth_session.identity_check.userid, "user");
assert.equal(template, "template");
done();
});
const handler = app_get.getCall(0).args[1];
handler(req, res);
});
}
});