realm-object-server
Version:
255 lines • 16.2 kB
JavaScript
;
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
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) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
const chai_1 = require("chai");
const chai = require("chai");
chai.use(require("chai-as-promised"));
const JwtAuthProvider_1 = require("./JwtAuthProvider");
const errors = require("../../errors");
const TestServer_1 = require("../../TestServer");
const jwt = require("jsonwebtoken");
const uuid = require("uuid");
const privateKey = "-----BEGIN RSA PRIVATE KEY-----\nMIIEowIBAAKCAQEAsPJV7FJ5iOgkI6B9o+sE/aNHAzfXDNt059CPQathgUvdbpja\nnfRkNmYhmx7Bfa8ybPFxJZTs53KoLXuAN3uRuxFPL6Ki9320JRxlA/zLN7OKklY+\nM3ftQcvqYuyLvUHwDEG33p5gHngUP7MH+67xLWUGSRq2oi6261LwloCceiyzv4UY\nbxOTvgMC7RYTAcIRfreJTSuww4deffSCtaqdbyJLW3G4qUMfEAF5dwxZzx3hSyg9\nmCyimzdsD5s7TjpQq+mdHudj5mFvN07y11A0ZqP6KyWQX7JETLJZTJgelqpynqmn\nNzdGgnxwGkM8h2LlOCXk+z3OpSzXvwfw4AXoJwIDAQABAoIBADa7vzhKiq1+oS8k\nBbkeiXyrdNvZ+ftQJulN6gI2MQL9pJEBVx5k6lqpXNvOt6tY9hAc3xLw7hbpsHvh\nJ9gBsSJcSFJDzIUhrQeNsPF60KF6N/LsGnFxN0KTAP14jgEM1GP2MBn8g17pZdoO\nVvnTM2cHSNp0GOox6QMBtMnZHo3rojibBSsqaB8g+LhikBiOccwwr92l5y2AmSpt\nAPTXHhKgnRBeYpQQHh28F8aNmAdXonyRSisSz+zE4UgMwCYTlf7BCahuCRUahtZ3\n0fT43T9sASdRJVbGZDMtTioGK58xqQYJywJajY0NEqMWBhoCeMMcrAX2ex8g9Pu9\nSGgnPwECgYEA2hMKuUJLFZl3zVyr84yAWmK7pPAfF3mi6ehz+IVXVQIqvi5RVQXf\nhyTSY9RwoMTuWRw2neUd7FQ4tSoOMrVdr/m2F5FNoDWJ+c2nihjA8FDU83H0krb2\n5tdiEYc4pxWPH6FjCGkTQCuXI6ilYl+96z0zxXbWM4OEISrwUf3MI/8CgYEAz7g7\nXBDnxPFPTX17MLGwTx7IA7Pb1+G8xNyL6bxykG9ogKL6+Ox/cvhj89vsXAiS0UXu\nGpfRjauOZemd5wVRDzBlHsqF8bgR5yfNSd70D9nian7E72paCheK28hZVX3ogV03\nDJF0cVS9s0lMgt4w9q1KBtVlXqWmCNr74xvQm9kCgYEAzr6GyCQlcxDQF43oJzno\n5cf9Bd3wXB0haojKia5AoYMwaqUWzniG9mTeYW6iaIjLPwgUb5UrzUX7jSWV2FVB\nwPgIvkcvRNf9OyrRz4awRCUd/r7mk8GKSkef3eZIu38g9WfXr72OVqP84f2c7aq/\nLyoSzv5fDO9+cMN4mwL2apkCgYAP0aj7nvH3pqTycs7x62ZQ8DgtSAJDE5brqxwg\npdBXvZRIz6CrWl9uYwpBpQsAC0sbEudKMSutTVZf3oW+9UGyFW5uBOBkgy8h2n8g\n1BDkMCS1FYhr7z6CLD7P9BcRkrAlQfMSSvWCOADmaXuhL8is0I+lq5S3u4fEfuDV\n7+VYKQKBgH3khvydRwCb28E8U5C1Ut8ueBqIhsfdwLv0rtcNeZJGb1U08UVEQDYl\nvvU3yPjW2x4HYzdsRMhk+IjQLGCR5NyIyptecmxartTcF6XGr7Ukw2o/zEIYo0WH\nAkUxZEzQjVktfdc8oSyIGmdv5XCXmxuZb1MhmqXu3ipAmV8lK5vM\n-----END RSA PRIVATE KEY-----";
describe("JwtAuthProvider", () => {
let provider;
let server;
function signToken(params = {}) {
const payload = {};
if (params.isAdmin) {
payload[params.isAdminFieldName || "isAdmin"] = params.isAdmin;
}
if (params.userId !== null) {
payload[params.userIdFieldName || "userId"] = params.userId || uuid.v4();
}
return jwt.sign(payload, privateKey, {
expiresIn: params.expiresIn || "1d",
algorithm: params.algorithm || "RS256",
notBefore: params.notBefore || 0,
});
}
function createServer(params = {}) {
return __awaiter(this, void 0, void 0, function* () {
server = new TestServer_1.TestServer();
const providerConfig = {
publicKey: "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsPJV7FJ5iOgkI6B9o+sE\n/aNHAzfXDNt059CPQathgUvdbpjanfRkNmYhmx7Bfa8ybPFxJZTs53KoLXuAN3uR\nuxFPL6Ki9320JRxlA/zLN7OKklY+M3ftQcvqYuyLvUHwDEG33p5gHngUP7MH+67x\nLWUGSRq2oi6261LwloCceiyzv4UYbxOTvgMC7RYTAcIRfreJTSuww4deffSCtaqd\nbyJLW3G4qUMfEAF5dwxZzx3hSyg9mCyimzdsD5s7TjpQq+mdHudj5mFvN07y11A0\nZqP6KyWQX7JETLJZTJgelqpynqmnNzdGgnxwGkM8h2LlOCXk+z3OpSzXvwfw4AXo\nJwIDAQAB\n-----END PUBLIC KEY-----"
};
Object.assign(providerConfig, params);
provider = new JwtAuthProvider_1.JwtAuthProvider(providerConfig);
yield server.start({
authProviders: [provider],
});
});
}
function stopServer() {
return __awaiter(this, void 0, void 0, function* () {
if (server) {
yield server.shutdown();
}
});
}
describe("authenticateOrCreateUser", () => {
before(() => createServer());
after(() => stopServer());
describe("without data param", () => {
it("should return a MissingParameters exception", () => __awaiter(this, void 0, void 0, function* () {
yield chai_1.assert.isRejected(provider.authenticateOrCreateUser({}), errors.realm.MissingParameters);
}));
});
describe("with expired access token", () => {
it("should return an InvalidCredentials exception", () => __awaiter(this, void 0, void 0, function* () {
const token = signToken({ expiresIn: "-1d" });
yield chai_1.assert.isRejected(provider.authenticateOrCreateUser({ data: token }), errors.realm.InvalidCredentials);
}));
});
describe("with invalid signature access token", () => {
it("should return an InvalidCredentials exception", () => __awaiter(this, void 0, void 0, function* () {
const token = signToken();
const mangledToken = token.slice(0, token.length - 5);
yield chai_1.assert.isRejected(provider.authenticateOrCreateUser({ data: mangledToken }), errors.realm.InvalidCredentials);
}));
});
describe("with invalid algorithm access token", () => {
it("should return an InvalidCredentials exception", () => __awaiter(this, void 0, void 0, function* () {
const token = signToken({ algorithm: "RS512" });
yield chai_1.assert.isRejected(provider.authenticateOrCreateUser({ data: token }), errors.realm.InvalidCredentials);
}));
});
describe("with no userId in payload", () => {
it("should return an InvalidCredentials exception", () => __awaiter(this, void 0, void 0, function* () {
const token = signToken({ userId: null });
yield chai_1.assert.isRejected(provider.authenticateOrCreateUser({ data: token }), errors.realm.InvalidCredentials);
}));
});
describe("on first request", () => {
it("should return a user", () => __awaiter(this, void 0, void 0, function* () {
const token = signToken();
const user = yield chai_1.assert.isFulfilled(provider.authenticateOrCreateUser({ data: token }));
chai_1.assert.isTrue(user.created);
chai_1.assert.isDefined(user.userId);
chai_1.assert.isFalse(user.isAdmin);
chai_1.assert.equal(user.accounts[0].provider, "jwt");
chai_1.assert.equal(user.accounts[0].providerId, user.userId);
}));
});
describe("on subsequent requests", () => {
it("should return a user", () => __awaiter(this, void 0, void 0, function* () {
const token = signToken();
const user = yield chai_1.assert.isFulfilled(provider.authenticateOrCreateUser({ data: token }));
const secondUser = yield chai_1.assert.isFulfilled(provider.authenticateOrCreateUser({ data: token }));
chai_1.assert.equal(user.userId, secondUser.userId);
chai_1.assert.equal(user.accounts[0].providerId, secondUser.accounts[0].providerId);
}));
});
describe("when user is admin", () => {
it("should set the admin flag", () => __awaiter(this, void 0, void 0, function* () {
const token = signToken({ isAdmin: true });
const user = yield chai_1.assert.isFulfilled(provider.authenticateOrCreateUser({ data: token }));
chai_1.assert.isTrue(user.created);
chai_1.assert.isDefined(user.userId);
chai_1.assert.isTrue(user.isAdmin);
chai_1.assert.equal(user.accounts[0].provider, "jwt");
chai_1.assert.equal(user.accounts[0].providerId, user.userId);
}));
});
describe("when user is promoted to admin", () => {
it("should update isAdmin", () => __awaiter(this, void 0, void 0, function* () {
const userId = uuid.v4();
const userToken = signToken({ userId });
const user = yield chai_1.assert.isFulfilled(provider.authenticateOrCreateUser({ data: userToken }));
chai_1.assert.isTrue(user.created);
chai_1.assert.isDefined(user.userId);
chai_1.assert.isFalse(user.isAdmin);
const adminToken = signToken({ userId, isAdmin: true });
const promotedUser = yield chai_1.assert.isFulfilled(provider.authenticateOrCreateUser({ data: adminToken }));
chai_1.assert.equal(user.userId, promotedUser.userId);
chai_1.assert.isTrue(promotedUser.isAdmin);
}));
});
describe("when admin user is demoted", () => {
it("should update isAdmin", () => __awaiter(this, void 0, void 0, function* () {
const userId = uuid.v4();
const adminToken = signToken({ userId, isAdmin: true });
const adminUser = yield chai_1.assert.isFulfilled(provider.authenticateOrCreateUser({ data: adminToken }));
chai_1.assert.isTrue(adminUser.created);
chai_1.assert.isDefined(adminUser.userId);
chai_1.assert.isTrue(adminUser.isAdmin);
const userToken = signToken({ userId });
const demotedUser = yield chai_1.assert.isFulfilled(provider.authenticateOrCreateUser({ data: userToken }));
chai_1.assert.equal(adminUser.userId, demotedUser.userId);
chai_1.assert.isFalse(demotedUser.isAdmin);
}));
});
});
describe("authenticateOrCreateUser with overriden fields", () => {
const userIdFieldName = "http://my-domain.com/userId";
describe("when userId field is overriden", () => {
before(() => createServer({
userIdFieldName,
}));
after(() => stopServer());
it("should log in successfully", () => __awaiter(this, void 0, void 0, function* () {
const userId = uuid.v4();
const token = signToken({ userIdFieldName, userId });
const user = yield chai_1.assert.isFulfilled(provider.authenticateOrCreateUser({ data: token }));
chai_1.assert.isTrue(user.created);
chai_1.assert.equal(user.userId, userId);
chai_1.assert.isFalse(user.isAdmin);
chai_1.assert.equal(user.accounts[0].provider, "jwt");
chai_1.assert.equal(user.accounts[0].providerId, user.userId);
}));
});
describe("when isAdmin field is overriden", () => {
const isAdminFieldName = "http://my-domain.com/is_admin";
function test(apiName, params) {
before(() => createServer(Object.assign({ userIdFieldName }, params)));
after(() => stopServer());
it(`should log in successfully (${apiName})`, () => __awaiter(this, void 0, void 0, function* () {
const userId = uuid.v4();
const token = signToken({ userIdFieldName, isAdminFieldName, userId, isAdmin: true });
const user = yield chai_1.assert.isFulfilled(provider.authenticateOrCreateUser({ data: token }));
chai_1.assert.isTrue(user.created);
chai_1.assert.equal(user.userId, userId);
chai_1.assert.isTrue(user.isAdmin);
chai_1.assert.equal(user.accounts[0].provider, "jwt");
chai_1.assert.equal(user.accounts[0].providerId, user.userId);
}));
}
test("legacy", { isAdminFieldName, isAdminValue: true });
test("JSONPath", { isAdminQuery: { path: `$["${isAdminFieldName}"]`, value: true } });
});
describe("when requiredAttributes is provided", () => {
function test(apiName, params) {
before(() => createServer({
requiredAttributes: Object.assign({}, params)
}));
after(() => stopServer());
it(`should not log in (${apiName})`, () => __awaiter(this, void 0, void 0, function* () {
const userToken = signToken();
yield chai_1.assert.isRejected(provider.authenticateOrCreateUser({ data: userToken }), errors.realm.InvalidCredentials);
}));
}
test("legacy", { requiredAttributes: { organization: "realm" } });
test("JSONPath", { requiredClaims: { ["$.organization"]: "realm" } });
});
describe("when name is overriden", () => {
before(() => createServer({
providerName: "foo"
}));
after(() => stopServer());
it("should log in", () => __awaiter(this, void 0, void 0, function* () {
const userToken = signToken();
const user = yield chai_1.assert.isFulfilled(provider.authenticateOrCreateUser({ data: userToken }));
chai_1.assert.isDefined(user.userId);
chai_1.assert.equal(user.accounts[0].provider, "foo");
chai_1.assert.equal(user.accounts[0].providerId, user.userId);
}));
});
describe("when charactersToEscape provided", () => {
before(() => createServer({
charactersToEscape: ["|", "@"]
}));
after(() => stopServer());
const testEscaping = (userId, expectedId) => __awaiter(this, void 0, void 0, function* () {
const token = signToken({ userId });
const user = yield chai_1.assert.isFulfilled(provider.authenticateOrCreateUser({ data: token }));
chai_1.assert.isTrue(user.created);
chai_1.assert.equal(user.userId, expectedId);
chai_1.assert.isFalse(user.isAdmin);
chai_1.assert.equal(user.accounts[0].provider, "jwt");
chai_1.assert.equal(user.accounts[0].providerId, user.userId);
});
it("should escape the userId", () => __awaiter(this, void 0, void 0, function* () {
const userId = uuid.v4();
yield testEscaping(`something|${userId}`, `something_${userId}`);
}));
it("should escape all occurrences of the characters", () => __awaiter(this, void 0, void 0, function* () {
const userId = uuid.v4();
yield testEscaping(`something|${userId}|something|else`, `something_${userId}_something_else`);
}));
it("should escape a combination of escapeable characters", () => __awaiter(this, void 0, void 0, function* () {
const userId = uuid.v4();
yield testEscaping(`something|${userId}@foo|bar`, `something_${userId}_foo_bar`);
}));
});
describe("clockTolerance", () => {
before(() => createServer({
clockTolerance: 30
}));
after(stopServer);
it("should verify the token when nbf is in the future, but within clockTolerance", () => __awaiter(this, void 0, void 0, function* () {
const token = signToken({
notBefore: "15s"
});
yield chai_1.assert.isFulfilled(provider.authenticateOrCreateUser({ data: token }));
}));
});
});
});
//# sourceMappingURL=JwtAuthProvider.spec.js.map