@guardian/pan-domain-node
Version:
NodeJs implementation of Guardian pan-domain auth verification
115 lines (114 loc) • 7.1 kB
JavaScript
;
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
const api_1 = require("../src/api");
const panda_1 = require("../src/panda");
const fetch_public_key_1 = require("../src/fetch-public-key");
const fixtures_1 = require("./fixtures");
const utils_1 = require("../src/utils");
jest.mock('../src/fetch-public-key');
jest.useFakeTimers('modern');
describe('verifyUser', function () {
test("return invalid cookie if missing", () => {
expect(panda_1.verifyUser(undefined, "", new Date(0), api_1.guardianValidation).status).toBe(api_1.AuthenticationStatus.INVALID_COOKIE);
});
test("return invalid cookie for a malformed signature", () => {
const [data, signature] = fixtures_1.sampleCookie.split(".");
const testCookie = data + ".1234";
expect(panda_1.verifyUser(testCookie, fixtures_1.publicKey, new Date(0), api_1.guardianValidation).status).toBe(api_1.AuthenticationStatus.INVALID_COOKIE);
});
test("return expired", () => {
const someTimeInTheFuture = new Date(5678);
expect(someTimeInTheFuture.getTime()).toBe(5678);
expect(panda_1.verifyUser(fixtures_1.sampleCookie, fixtures_1.publicKey, someTimeInTheFuture, api_1.guardianValidation).status).toBe(api_1.AuthenticationStatus.EXPIRED);
});
test("return not authenticated if user fails validation function", () => {
expect(panda_1.verifyUser(fixtures_1.sampleCookieWithoutMultifactor, fixtures_1.publicKey, new Date(0), api_1.guardianValidation).status).toBe(api_1.AuthenticationStatus.NOT_AUTHORISED);
expect(panda_1.verifyUser(fixtures_1.sampleNonGuardianCookie, fixtures_1.publicKey, new Date(0), api_1.guardianValidation).status).toBe(api_1.AuthenticationStatus.NOT_AUTHORISED);
});
test("return authenticated", () => {
expect(panda_1.verifyUser(fixtures_1.sampleCookie, fixtures_1.publicKey, new Date(0), api_1.guardianValidation).status).toBe(api_1.AuthenticationStatus.AUTHORISED);
});
});
describe('createCookie', function () {
it('should return the same cookie based on the user details being provided', function () {
const user = {
firstName: "Test",
lastName: "User",
email: "test.user@guardian.co.uk",
authenticatingSystem: "test",
authenticatedIn: ["test"],
expires: 1234,
multifactor: true
};
const cookie = panda_1.createCookie(user, fixtures_1.privateKey);
expect(utils_1.decodeBase64(cookie)).toEqual(utils_1.decodeBase64(fixtures_1.sampleCookie));
expect(cookie).toEqual(fixtures_1.sampleCookie);
});
});
describe('panda class', function () {
beforeEach(() => {
fetch_public_key_1.fetchPublicKey.mockResolvedValue({ key: 'PUBLIC KEY', lastUpdated: new Date() });
});
describe('stop', () => {
it('stops auto refresh', () => {
const panda = new panda_1.PanDomainAuthentication('cookiename', 'region', 'bucket', 'keyfile', (u) => true);
expect(panda.keyUpdateTimer).not.toBeUndefined();
panda.stop();
expect(panda.keyUpdateTimer).toBeUndefined();
});
});
describe('getPublicKey', () => {
it('getsPublicKey immediately when last fetch is within the cache time', () => __awaiter(this, void 0, void 0, function* () {
const panda = new panda_1.PanDomainAuthentication('cookiename', 'region', 'bucket', 'keyfile', (u) => true);
const fetchesBeforeGet = fetch_public_key_1.fetchPublicKey.mock.calls.length;
yield expect(panda.getPublicKey()).resolves.toEqual('PUBLIC KEY');
const fetchesAfterGet = fetch_public_key_1.fetchPublicKey.mock.calls.length;
expect(fetchesAfterGet).toEqual(fetchesBeforeGet);
}));
it('getsPublicKey after refetching when last fetch is outside the cache time', () => __awaiter(this, void 0, void 0, function* () {
// cache time is 1 min
const fiveMinsAgo = new Date();
fiveMinsAgo.setMinutes(fiveMinsAgo.getMinutes() - 5);
fetch_public_key_1.fetchPublicKey.mockResolvedValue({ key: 'PUBLIC KEY', lastUpdated: fiveMinsAgo });
const panda = new panda_1.PanDomainAuthentication('cookiename', 'region', 'bucket', 'keyfile', (u) => true);
const fetchesBefore = fetch_public_key_1.fetchPublicKey.mock.calls.length;
yield expect(panda.getPublicKey()).resolves.toEqual('PUBLIC KEY');
fetch_public_key_1.fetchPublicKey.mockResolvedValue({ key: 'PUBLIC KEY 2', lastUpdated: fiveMinsAgo });
const fetchesAfter = fetch_public_key_1.fetchPublicKey.mock.calls.length;
yield expect(panda.getPublicKey()).resolves.toEqual('PUBLIC KEY 2');
expect(fetchesAfter).toEqual(fetchesBefore + 1);
}));
});
describe('verify', () => {
beforeEach(() => {
fetch_public_key_1.fetchPublicKey.mockResolvedValue({ key: fixtures_1.publicKey, lastUpdated: new Date() });
});
it('should return authenticated if valid', () => __awaiter(this, void 0, void 0, function* () {
jest.setSystemTime(100);
const panda = new panda_1.PanDomainAuthentication('cookiename', 'region', 'bucket', 'keyfile', (u) => true);
const { status } = yield panda.verify(`cookiename=${fixtures_1.sampleCookie}`);
expect(status).toBe(api_1.AuthenticationStatus.AUTHORISED);
}));
it('should return expired if expired', () => __awaiter(this, void 0, void 0, function* () {
jest.setSystemTime(10000);
const panda = new panda_1.PanDomainAuthentication('cookiename', 'region', 'bucket', 'keyfile', (u) => true);
const { status } = yield panda.verify(`cookiename=${fixtures_1.sampleCookie}`);
expect(status).toBe(api_1.AuthenticationStatus.EXPIRED);
}));
it('should return not authenticated if validation fails', () => __awaiter(this, void 0, void 0, function* () {
jest.setSystemTime(100);
const panda = new panda_1.PanDomainAuthentication('cookiename', 'region', 'bucket', 'keyfile', api_1.guardianValidation);
const { status } = yield panda.verify(`cookiename=${fixtures_1.sampleNonGuardianCookie}`);
expect(status).toBe(api_1.AuthenticationStatus.NOT_AUTHORISED);
}));
});
});