authelia/server/test/regulation/Regulator.test.ts
Clement Michaud b9fa786df6 Refactor endpoints to get server variables as input parameters
This refactoring aims to ease testability and clean up a lot of soft touchy
typings in test code.

This is the first step of this refactoring introducing the concept and
implementing missing interfaces and stubs. At the end of the day,
ServerVariablesHandler should completely disappear and every variable should
be injected in the endpoint handler builder itself.
2017-10-31 07:26:53 +01:00

186 lines
6.5 KiB
TypeScript

import Sinon = require("sinon");
import BluebirdPromise = require("bluebird");
import Assert = require("assert");
import { Regulator } from "../../src/lib/regulation/Regulator";
import MockDate = require("mockdate");
import exceptions = require("../../src/lib/Exceptions");
import { UserDataStoreStub } from "../mocks/storage/UserDataStoreStub";
describe("test authentication regulator", function () {
const USER1 = "USER1";
const USER2 = "USER2";
let userDataStoreStub: UserDataStoreStub;
beforeEach(function () {
userDataStoreStub = new UserDataStoreStub();
const dataStore: { [userId: string]: { userId: string, date: Date, isAuthenticationSuccessful: boolean }[] } = {
[USER1]: [],
[USER2]: []
};
userDataStoreStub.saveAuthenticationTraceStub.callsFake(function (userId, isAuthenticationSuccessful) {
dataStore[userId].unshift({
userId: userId,
date: new Date(),
isAuthenticationSuccessful: isAuthenticationSuccessful,
});
return BluebirdPromise.resolve();
});
userDataStoreStub.retrieveLatestAuthenticationTracesStub.callsFake(function (userId, count) {
const ret = (dataStore[userId].length <= count) ? dataStore[userId] : dataStore[userId].slice(0, 3);
return BluebirdPromise.resolve(ret);
});
});
afterEach(function () {
MockDate.reset();
});
function markAuthenticationAt(regulator: Regulator, user: string, time: string, success: boolean) {
MockDate.set(time);
return regulator.mark(user, success);
}
it("should mark 2 authentication and regulate (accept)", function () {
const regulator = new Regulator(userDataStoreStub, 3, 10, 10);
return regulator.mark(USER1, false)
.then(function () {
return regulator.mark(USER1, true);
})
.then(function () {
return regulator.regulate(USER1);
});
});
it("should mark 3 authentications and regulate (reject)", function () {
const regulator = new Regulator(userDataStoreStub, 3, 10, 10);
return regulator.mark(USER1, false)
.then(function () {
return regulator.mark(USER1, false);
})
.then(function () {
return regulator.mark(USER1, false);
})
.then(function () {
return regulator.regulate(USER1);
})
.then(function () { return BluebirdPromise.reject(new Error("should not be here!")); })
.catch(exceptions.AuthenticationRegulationError, function () {
return BluebirdPromise.resolve();
});
});
it("should mark 1 failed, 1 successful and 1 failed authentications within minimum time and regulate (accept)", function () {
const regulator = new Regulator(userDataStoreStub, 3, 60, 30);
return markAuthenticationAt(regulator, USER1, "1/2/2000 00:00:00", false)
.then(function () {
return markAuthenticationAt(regulator, USER1, "1/2/2000 00:00:10", true);
})
.then(function () {
return markAuthenticationAt(regulator, USER1, "1/2/2000 00:00:20", false);
})
.then(function () {
return regulator.regulate(USER1);
})
.then(function () {
return markAuthenticationAt(regulator, USER1, "1/2/2000 00:00:30", false);
})
.then(function () {
return regulator.regulate(USER1);
})
.then(function () {
return markAuthenticationAt(regulator, USER1, "1/2/2000 00:00:39", false);
})
.then(function () {
return regulator.regulate(USER1);
})
.then(function () {
return BluebirdPromise.reject(new Error("should not be here!"));
},
function () {
return BluebirdPromise.resolve();
});
});
it("should regulate user if number of failures is greater than 3 in allowed time lapse", function () {
function markAuthentications(regulator: Regulator, user: string) {
return markAuthenticationAt(regulator, user, "1/2/2000 00:00:00", false)
.then(function () {
return markAuthenticationAt(regulator, user, "1/2/2000 00:00:45", false);
})
.then(function () {
return markAuthenticationAt(regulator, user, "1/2/2000 00:01:05", false);
})
.then(function () {
return regulator.regulate(user);
});
}
const regulator1 = new Regulator(userDataStoreStub, 3, 60, 60);
const regulator2 = new Regulator(userDataStoreStub, 3, 2 * 60, 60);
const p1 = markAuthentications(regulator1, USER1);
const p2 = markAuthentications(regulator2, USER2);
return BluebirdPromise.join(p1, p2)
.then(function () {
return BluebirdPromise.reject(new Error("should not be here..."));
}, function () {
Assert(p1.isFulfilled());
Assert(p2.isRejected());
});
});
it("should user wait after regulation to authenticate again", function () {
function markAuthentications(regulator: Regulator, user: string) {
return markAuthenticationAt(regulator, user, "1/2/2000 00:00:00", false)
.then(function () {
return markAuthenticationAt(regulator, user, "1/2/2000 00:00:10", false);
})
.then(function () {
return markAuthenticationAt(regulator, user, "1/2/2000 00:00:15", false);
})
.then(function () {
return markAuthenticationAt(regulator, user, "1/2/2000 00:00:25", false);
})
.then(function () {
MockDate.set("1/2/2000 00:00:54");
return regulator.regulate(user);
})
.then(function () {
return BluebirdPromise.reject(new Error("should fail at this time"));
}, function () {
MockDate.set("1/2/2000 00:00:56");
return regulator.regulate(user);
});
}
const regulator = new Regulator(userDataStoreStub, 4, 30, 30);
return markAuthentications(regulator, USER1);
});
it("should disable regulation when max_retries is set to 0", function () {
const maxRetries = 0;
const regulator = new Regulator(userDataStoreStub, maxRetries, 60, 30);
return markAuthenticationAt(regulator, USER1, "1/2/2000 00:00:00", false)
.then(function () {
return markAuthenticationAt(regulator, USER1, "1/2/2000 00:00:10", false);
})
.then(function () {
return markAuthenticationAt(regulator, USER1, "1/2/2000 00:00:15", false);
})
.then(function () {
return markAuthenticationAt(regulator, USER1, "1/2/2000 00:00:25", false);
})
.then(function () {
MockDate.set("1/2/2000 00:00:26");
return regulator.regulate(USER1);
});
});
});