Files
NODEDC_DESIGN_GUIDELINE/apps/device-manager/server/device-manager-auth.test.mjs
T

128 lines
4.3 KiB
JavaScript

import assert from "node:assert/strict";
import test from "node:test";
import { createDeviceManagerAuth } from "./device-manager-auth.mjs";
const internalToken = "launcher-internal-token-must-stay-server-side";
const launcherSessionId = "launcher-session-id-must-stay-server-side";
test("Launcher handoff becomes an opaque Device Manager session and trusted actor", async () => {
const calls = [];
const auth = createDeviceManagerAuth({
env: productionEnv(),
fetchImpl: async (url, init) => {
calls.push({ url: String(url), init });
return jsonResponse(200, {
ok: true,
launcherSessionId,
user: {
id: "user_root",
email: "root@example.test",
name: "DC SUDO",
groups: ["nodedc:superadmin", "nodedc:device-core:admin"],
},
});
},
});
const response = mockResponse();
await auth.handleHandoff(
{ method: "GET", headers: {} },
response,
new URL("https://device.example.test/auth/nodedc/handoff?token=handoff-secret&next_path=%2F"),
);
assert.equal(response.statusCode, 302);
assert.equal(calls.length, 1);
assert.equal(calls[0].init.headers.Authorization, `Bearer ${internalToken}`);
assert.deepEqual(JSON.parse(calls[0].init.body), {
token: "handoff-secret",
serviceSlug: "device-core",
});
const cookie = String(response.getHeader("set-cookie")).split(";", 1)[0];
assert.match(cookie, /^nodedc_device_manager_session=[A-Za-z0-9_-]{40,}$/);
assert.equal(cookie.includes("user_root"), false);
assert.equal(cookie.includes(launcherSessionId), false);
const request = { method: "GET", headers: { cookie, accept: "application/json" } };
const authorized = await auth.authorize(
request,
mockResponse(),
new URL("https://device.example.test/api/device-manager/session"),
);
assert.equal(authorized, false);
const context = auth.currentContext(request);
assert.equal(context.actor.userRef, "user:user_root");
assert.equal(context.actor.hubRole, "owner");
assert.deepEqual(context.actor.ownerScopes, [{
scopeKind: "personal",
ownerRef: "user:user_root",
displayName: "DC SUDO",
}]);
assert.deepEqual(context.actor.groupRefs, [
"group:nodedc:device-core:admin",
"group:nodedc:superadmin",
]);
assert.equal(JSON.stringify(context).includes(launcherSessionId), false);
assert.equal(JSON.stringify(context).includes(internalToken), false);
});
test("invalid identity and explicit Device Core block never produce an actor", async () => {
for (const user of [
{ id: "?", groups: ["nodedc:device-core:admin"] },
{ id: "valid-user", groups: ["nodedc:superadmin", "nodedc:device-core:blocked"] },
]) {
const auth = createDeviceManagerAuth({
env: productionEnv(),
fetchImpl: async () => jsonResponse(200, {
ok: true,
launcherSessionId,
user,
}),
});
const handoff = mockResponse();
await auth.handleHandoff(
{ method: "GET", headers: {} },
handoff,
new URL("https://device.example.test/auth/nodedc/handoff?token=handoff-secret"),
);
const cookie = String(handoff.getHeader("set-cookie")).split(";", 1)[0];
const request = { method: "GET", headers: { cookie, accept: "application/json" } };
const response = mockResponse();
assert.equal(await auth.authorize(
request,
response,
new URL("https://device.example.test/api/device-manager/session"),
), true);
assert.equal(response.statusCode, 403);
}
});
function productionEnv() {
return {
NODE_ENV: "production",
NODEDC_DEVICE_MANAGER_AUTH_REQUIRED: "true",
NODEDC_DEVICE_MANAGER_COOKIE_SECURE: "false",
NODEDC_LAUNCHER_BASE_URL: "https://launcher.example.test",
NODEDC_LAUNCHER_INTERNAL_URL: "http://launcher.internal.test",
NODEDC_INTERNAL_ACCESS_TOKEN: internalToken,
};
}
function mockResponse() {
const headers = new Map();
return {
statusCode: 200,
body: "",
setHeader(name, value) { headers.set(String(name).toLowerCase(), value); },
getHeader(name) { return headers.get(String(name).toLowerCase()); },
end(body = "") { this.body = String(body); },
};
}
function jsonResponse(status, body) {
return new Response(JSON.stringify(body), {
status,
headers: { "content-type": "application/json" },
});
}