realm-object-server
Version:
231 lines • 11.1 kB
JavaScript
"use strict";
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 auth = require("../auth");
const TestServer_1 = require("../TestServer");
const path = require("path");
const NodeRSA = require("node-rsa");
const uuid = require("uuid");
const jwt = require("jsonwebtoken");
const superagent = require("superagent");
const chai_1 = require("chai");
const util_1 = require("../shared/util");
describe("Custom Refresh Token integration", function () {
let publicKey;
let privateKey;
let server;
const signToken = (options = {}, signOptions = {}) => {
const payload = {
isAdmin: options.isAdmin || false,
sub: options.userId || uuid.v4(),
};
const validatedSignOptions = {
issuer: util_1.getValueOrDefault(signOptions.issuer, "myissuer"),
algorithm: util_1.getValueOrDefault(signOptions.algorightm, "RS256"),
expiresIn: util_1.getValueOrDefault(signOptions.expiresIn, 3600),
jwtid: uuid.v4(),
};
const audience = util_1.getValueOrDefault(signOptions.audience, "myapp");
if (audience) {
validatedSignOptions.audience = audience;
}
return jwt.sign(payload, util_1.getValueOrDefault(signOptions.privateKey, privateKey), validatedSignOptions);
};
const login = (payload, shouldSucceed = true) => __awaiter(this, void 0, void 0, function* () {
const promise = superagent.post(`${server.url}/auth`).send(payload);
if (shouldSucceed) {
const result = yield chai_1.assert.isFulfilled(promise);
return result;
}
const error = yield chai_1.assert.isRejected(promise);
return error;
});
const loginRefresh = (token, shouldSucceed = true) => __awaiter(this, void 0, void 0, function* () {
return login({
data: token,
path: "/~/foo",
provider: "realm"
}, shouldSucceed);
});
before(function () {
return __awaiter(this, void 0, void 0, function* () {
this.timeout(30000);
const key = new NodeRSA({ b: 2048 });
privateKey = key.exportKey("pkcs8-private-pem");
publicKey = key.exportKey("pkcs8-public-pem");
server = new TestServer_1.TestServer();
yield server.start({
authProviders: [
new auth.PasswordAuthProvider({ autoCreateAdminUser: true, iterations: 1 }),
new auth.AnonymousAuthProvider(),
],
https: true,
httpsKeyPath: path.join(__dirname, "..", "..", "fixtures", "https.key"),
httpsCertChainPath: path.join(__dirname, "..", "..", "fixtures", "https.crt"),
logLevel: "off",
refreshTokenValidators: [{
algorithms: ["RS256"],
audience: "myapp",
issuer: "myissuer",
publicKey,
isAdminQuery: { path: "$.isAdmin", value: true }
}, {
publicKey,
issuer: "defaults",
}]
});
});
});
after(function () {
return __awaiter(this, void 0, void 0, function* () {
if (server) {
yield server.shutdown();
}
});
});
describe("/auth", function () {
it("authenticates non-existing user", () => __awaiter(this, void 0, void 0, function* () {
const userId = uuid.v4();
const token = signToken({ userId });
const response = yield loginRefresh(token);
const accessToken = response.body.access_token;
chai_1.assert.isString(accessToken.token);
chai_1.assert.equal(accessToken.token_data.identity, userId);
chai_1.assert.equal(accessToken.token_data.path, `/${userId}/foo`);
}));
it("authenticates an existing user", () => __awaiter(this, void 0, void 0, function* () {
const anonResponse = yield login({ provider: "anonymous" });
const userId = anonResponse.body.refresh_token.token_data.identity;
const token = signToken({ userId });
const customResponse = yield loginRefresh(token);
const accessToken = customResponse.body.access_token;
chai_1.assert.isString(accessToken.token);
chai_1.assert.equal(accessToken.token_data.identity, userId);
}));
it("authenticates an admin user", () => __awaiter(this, void 0, void 0, function* () {
const token = signToken({ isAdmin: true });
const response = yield login({
provider: "realm",
data: token,
path: "/this-is-in-root"
});
const accessToken = response.body.access_token;
chai_1.assert.deepEqual(accessToken.token_data.access, ["download", "upload", "manage"]);
}));
});
describe("invalid options", function () {
it("rejects mismatching issuers", () => __awaiter(this, void 0, void 0, function* () {
const token = signToken({}, { issuer: "rogueIssuer" });
const error = yield loginRefresh(token, false);
chai_1.assert.equal(error.status, 401);
}));
it("rejects mismatching audience", () => __awaiter(this, void 0, void 0, function* () {
const token = signToken({}, { audience: "some-other-app" });
const error = yield loginRefresh(token, false);
chai_1.assert.equal(error.status, 401);
}));
it("rejects invalid private key", () => __awaiter(this, void 0, void 0, function* () {
const token = signToken({}, { privateKey: new NodeRSA({ b: 2048 }).exportKey("pkcs8-private-pem") });
const error = yield loginRefresh(token, false);
chai_1.assert.equal(error.status, 401);
}));
it("rejects expired tokens", () => __awaiter(this, void 0, void 0, function* () {
const token = signToken({}, { expiresIn: -1 });
const error = yield loginRefresh(token, false);
chai_1.assert.equal(error.status, 401);
}));
});
describe("/revoke", function () {
it("revokes a token", () => __awaiter(this, void 0, void 0, function* () {
const userId = uuid.v4();
const token = signToken({ userId });
yield loginRefresh(token);
yield chai_1.assert.isFulfilled(superagent.post(`${server.url}/auth/revoke`)
.set({
Authorization: token
})
.send({
token,
}));
yield loginRefresh(token, false);
const newToken = signToken({ userId });
yield loginRefresh(newToken);
}));
});
describe("permissions", function () {
const getPermissions = (token) => __awaiter(this, void 0, void 0, function* () {
const response = yield chai_1.assert.isFulfilled(superagent.get(`${server.url}/permissions`)
.set({ Authorization: token }).send());
return response.body.permissions;
});
it("can see granted permissions", () => __awaiter(this, void 0, void 0, function* () {
const token = signToken();
const permissions = yield getPermissions(token);
chai_1.assert.equal(permissions.length, 1);
yield loginRefresh(token);
const newPermissions = yield getPermissions(token);
chai_1.assert.equal(newPermissions.length, 2);
chai_1.assert.isOk(newPermissions.find(p => p.path.endsWith("/foo")));
}));
it("can grant permissions", () => __awaiter(this, void 0, void 0, function* () {
const grantorId = uuid.v4();
const grantorToken = signToken({ userId: grantorId });
yield loginRefresh(grantorToken);
const granteeId = uuid.v4();
const granteeToken = signToken({ userId: granteeId });
yield loginRefresh(granteeToken);
let granteePerms = yield getPermissions(granteeToken);
chai_1.assert.equal(granteePerms.length, 2);
yield chai_1.assert.isFulfilled(superagent.post(`${server.url}/permissions/apply`)
.set({ Authorization: grantorToken })
.send({
realmPath: `/${grantorId}/foo`,
accessLevel: "write",
condition: {
userId: granteeId
}
}));
granteePerms = yield getPermissions(granteeToken);
chai_1.assert.equal(granteePerms.length, 3);
const grantorFooPermission = granteePerms.find(p => p.path === `/${grantorId}/foo`);
chai_1.assert.isOk(grantorFooPermission);
chai_1.assert.equal(grantorFooPermission.accessLevel, "write");
}));
});
describe("defaults", function () {
const testLogin = (options) => __awaiter(this, void 0, void 0, function* () {
const userId = uuid.v4();
const token = signToken({ userId }, Object.assign({ issuer: "defaults" }, options));
const response = yield loginRefresh(token);
chai_1.assert.equal(response.body.access_token.token_data.identity, userId);
return response.body.access_token.token_data;
});
it("accepts RS512 tokens", () => __awaiter(this, void 0, void 0, function* () {
yield testLogin({ algorightm: "RS512" });
}));
it("accepts missing audience", () => __awaiter(this, void 0, void 0, function* () {
yield testLogin({ audience: null });
}));
it("accepts random audience", () => __awaiter(this, void 0, void 0, function* () {
yield testLogin({ audience: "my-shady-app" });
}));
it("cannot login an admin", () => __awaiter(this, void 0, void 0, function* () {
const userId = uuid.v4();
const token = signToken({ userId, isAdmin: true }, { issuer: "defaults" });
const error = yield login({
provider: "realm",
data: token,
path: "/this-is-in-root"
}, false);
chai_1.assert.equal(error.status, 403);
}));
});
});
//# sourceMappingURL=custom-refresh-integration-tests.spec.js.map