2017-05-17 04:17:46 +07:00
|
|
|
|
2017-07-20 02:06:12 +07:00
|
|
|
import Sinon = require("sinon");
|
|
|
|
import BluebirdPromise = require("bluebird");
|
2017-09-03 06:25:43 +07:00
|
|
|
import Assert = require("assert");
|
2017-07-20 02:06:12 +07:00
|
|
|
|
2017-10-07 05:09:42 +07:00
|
|
|
import { AuthenticationRegulator } from "../src/lib/AuthenticationRegulator";
|
2017-05-21 03:55:37 +07:00
|
|
|
import MockDate = require("mockdate");
|
2017-10-07 05:09:42 +07:00
|
|
|
import exceptions = require("../src/lib/Exceptions");
|
2017-09-03 06:25:43 +07:00
|
|
|
import { UserDataStoreStub } from "./mocks/storage/UserDataStoreStub";
|
2017-05-17 04:17:46 +07:00
|
|
|
|
2017-07-20 02:06:12 +07:00
|
|
|
describe("test authentication regulator", function () {
|
2017-09-03 06:25:43 +07:00
|
|
|
const USER1 = "USER1";
|
|
|
|
const USER2 = "USER2";
|
|
|
|
let userDataStoreStub: UserDataStoreStub;
|
2017-07-20 02:06:12 +07:00
|
|
|
|
|
|
|
beforeEach(function () {
|
2017-09-03 06:25:43 +07:00
|
|
|
userDataStoreStub = new UserDataStoreStub();
|
|
|
|
const dataStore: { [userId: string]: { userId: string, date: Date, isAuthenticationSuccessful: boolean }[] } = {
|
|
|
|
[USER1]: [],
|
|
|
|
[USER2]: []
|
|
|
|
};
|
2017-07-20 02:06:12 +07:00
|
|
|
|
2017-09-03 06:25:43 +07:00
|
|
|
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);
|
|
|
|
});
|
2017-07-20 02:06:12 +07:00
|
|
|
});
|
|
|
|
|
2017-09-03 06:25:43 +07:00
|
|
|
afterEach(function () {
|
|
|
|
MockDate.reset();
|
|
|
|
});
|
2017-07-20 02:06:12 +07:00
|
|
|
|
2017-09-03 06:25:43 +07:00
|
|
|
function markAuthenticationAt(regulator: AuthenticationRegulator, user: string, time: string, success: boolean) {
|
|
|
|
MockDate.set(time);
|
|
|
|
return regulator.mark(user, success);
|
|
|
|
}
|
2017-07-20 02:06:12 +07:00
|
|
|
|
2017-09-03 06:25:43 +07:00
|
|
|
it("should mark 2 authentication and regulate (accept)", function () {
|
|
|
|
const regulator = new AuthenticationRegulator(userDataStoreStub, 3, 10, 10);
|
2017-05-17 04:17:46 +07:00
|
|
|
|
2017-09-03 06:25:43 +07:00
|
|
|
return regulator.mark(USER1, false)
|
2017-07-20 02:06:12 +07:00
|
|
|
.then(function () {
|
2017-09-03 06:25:43 +07:00
|
|
|
return regulator.mark(USER1, true);
|
2017-07-20 02:06:12 +07:00
|
|
|
})
|
|
|
|
.then(function () {
|
2017-09-03 06:25:43 +07:00
|
|
|
return regulator.regulate(USER1);
|
2017-07-20 02:06:12 +07:00
|
|
|
});
|
2017-05-17 04:17:46 +07:00
|
|
|
});
|
|
|
|
|
2017-09-03 06:25:43 +07:00
|
|
|
it("should mark 3 authentications and regulate (reject)", function () {
|
|
|
|
const regulator = new AuthenticationRegulator(userDataStoreStub, 3, 10, 10);
|
|
|
|
|
|
|
|
return regulator.mark(USER1, false)
|
|
|
|
.then(function () {
|
|
|
|
return regulator.mark(USER1, false);
|
2017-07-20 02:06:12 +07:00
|
|
|
})
|
|
|
|
.then(function () {
|
2017-09-03 06:25:43 +07:00
|
|
|
return regulator.mark(USER1, false);
|
2017-07-20 02:06:12 +07:00
|
|
|
})
|
|
|
|
.then(function () {
|
2017-09-03 06:25:43 +07:00
|
|
|
return regulator.regulate(USER1);
|
2017-07-20 02:06:12 +07:00
|
|
|
})
|
2017-09-03 06:25:43 +07:00
|
|
|
.then(function () { return BluebirdPromise.reject(new Error("should not be here!")); })
|
2017-07-20 02:06:12 +07:00
|
|
|
.catch(exceptions.AuthenticationRegulationError, function () {
|
2017-09-03 06:25:43 +07:00
|
|
|
return BluebirdPromise.resolve();
|
2017-07-20 02:06:12 +07:00
|
|
|
});
|
2017-05-17 04:17:46 +07:00
|
|
|
});
|
|
|
|
|
2017-09-03 06:25:43 +07:00
|
|
|
it("should mark 1 failed, 1 successful and 1 failed authentications within minimum time and regulate (accept)", function () {
|
|
|
|
const regulator = new AuthenticationRegulator(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: AuthenticationRegulator, 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 AuthenticationRegulator(userDataStoreStub, 3, 60, 60);
|
|
|
|
const regulator2 = new AuthenticationRegulator(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: AuthenticationRegulator, 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 AuthenticationRegulator(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 AuthenticationRegulator(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);
|
2017-07-20 02:06:12 +07:00
|
|
|
})
|
|
|
|
.then(function () {
|
2017-09-03 06:25:43 +07:00
|
|
|
return markAuthenticationAt(regulator, USER1, "1/2/2000 00:00:15", false);
|
2017-07-20 02:06:12 +07:00
|
|
|
})
|
|
|
|
.then(function () {
|
2017-09-03 06:25:43 +07:00
|
|
|
return markAuthenticationAt(regulator, USER1, "1/2/2000 00:00:25", false);
|
2017-07-20 02:06:12 +07:00
|
|
|
})
|
|
|
|
.then(function () {
|
2017-09-03 06:25:43 +07:00
|
|
|
MockDate.set("1/2/2000 00:00:26");
|
|
|
|
return regulator.regulate(USER1);
|
2017-07-20 02:06:12 +07:00
|
|
|
});
|
2017-05-17 04:17:46 +07:00
|
|
|
});
|
2017-07-20 02:06:12 +07:00
|
|
|
});
|