import assert from "node:assert/strict"; import { generateKeyPairSync, randomBytes, sign, } from "node:crypto"; import { chmod, mkdtemp, rm, symlink, writeFile } from "node:fs/promises"; import { tmpdir } from "node:os"; import { join } from "node:path"; import { createManagedProvisionerRequestVerifier, loadManagedProvisionerPublicKeyFile, MANAGED_PROVISIONER_HEADERS, managedProvisionerSigningPayload, ManagedProvisionerReplayCache, sha256RawBody, } from "../src/managed-provisioner-auth.mjs"; const serviceId = "nodedc-engine"; const keyId = "engine-edp-managed-provisioner-v1"; const audience = "nodedc-external-data-plane.managed-provisioning.v1"; const nowMs = Date.parse("2026-07-16T12:00:00.000Z"); const { privateKey, publicKey } = generateKeyPairSync("ed25519"); let nonceSequence = 0; const replayCache = new ManagedProvisionerReplayCache({ maxEntries: 100 }); const verify = createManagedProvisionerRequestVerifier({ publicKey, serviceId, keyId, audience, maxSkewMs: 60_000, replayCache, now: () => nowMs, }); const valid = signedRequest(); assert.deepEqual(verify(valid), { serviceId, keyId }); assert.throws(() => verify(valid), hasCode("managed_provisioner_request_replayed", 409)); const whitespaceTamper = signedRequest(); whitespaceTamper.rawBody = Buffer.from(`${whitespaceTamper.rawBody.toString("utf8")} `, "utf8"); assert.throws(() => verify(whitespaceTamper), hasCode("managed_provisioner_body_hash_mismatch", 401)); const methodTamper = signedRequest(); methodTamper.method = "POST"; assert.throws(() => verify(methodTamper), hasCode("managed_provisioner_signature_invalid", 401)); const pathTamper = signedRequest(); pathTamper.originalUrl = `${pathTamper.originalUrl}?unexpected=true`; assert.throws(() => verify(pathTamper), hasCode("managed_provisioner_signature_invalid", 401)); const audienceTamper = signedRequest(); setHeader(audienceTamper, MANAGED_PROVISIONER_HEADERS.audience, "other-audience"); assert.throws(() => verify(audienceTamper), hasCode("managed_provisioner_identity_mismatch", 401)); const serviceTamper = signedRequest(); setHeader(serviceTamper, MANAGED_PROVISIONER_HEADERS.serviceId, "other-engine"); assert.throws(() => verify(serviceTamper), hasCode("managed_provisioner_identity_mismatch", 401)); const keyTamper = signedRequest(); setHeader(keyTamper, MANAGED_PROVISIONER_HEADERS.keyId, "other-key-v1"); assert.throws(() => verify(keyTamper), hasCode("managed_provisioner_identity_mismatch", 401)); const forbiddenBearer = signedRequest(); forbiddenBearer.headers.authorization = "Bearer value-that-must-not-appear-in-errors"; forbiddenBearer.rawHeaders.push("Authorization", forbiddenBearer.headers.authorization); assert.throws( () => verify(forbiddenBearer), (error) => hasCode("managed_provisioner_authorization_header_forbidden", 401)(error) && !error.message.includes("value-that-must-not-appear-in-errors"), ); const stale = signedRequest({ timestamp: new Date(nowMs - 60_000).toISOString() }); assert.throws(() => verify(stale), hasCode("managed_provisioner_timestamp_outside_window", 401)); const future = signedRequest({ timestamp: new Date(nowMs + 60_000).toISOString() }); assert.throws(() => verify(future), hasCode("managed_provisioner_timestamp_outside_window", 401)); const invalidTimestamp = signedRequest(); setHeader(invalidTimestamp, MANAGED_PROVISIONER_HEADERS.timestamp, "2026-07-16T12:00:00Z"); assert.throws(() => verify(invalidTimestamp), hasCode("managed_provisioner_timestamp_invalid", 401)); const duplicateHeader = signedRequest(); duplicateHeader.rawHeaders.push(MANAGED_PROVISIONER_HEADERS.nonce, header(duplicateHeader, MANAGED_PROVISIONER_HEADERS.nonce)); assert.throws(() => verify(duplicateHeader), hasCode("managed_provisioner_header_invalid", 401)); const uncaptured = signedRequest(); uncaptured.rawBodyCaptured = false; uncaptured.headers["content-length"] = String(uncaptured.rawBody.length); assert.throws(() => verify(uncaptured), hasCode("managed_provisioner_raw_body_unavailable", 401)); const badSignature = signedRequest(); setHeader(badSignature, MANAGED_PROVISIONER_HEADERS.signature, randomBytes(64).toString("base64url")); assert.throws(() => verify(badSignature), hasCode("managed_provisioner_signature_invalid", 401)); const paddedSignature = signedRequest(); setHeader( paddedSignature, MANAGED_PROVISIONER_HEADERS.signature, `${header(paddedSignature, MANAGED_PROVISIONER_HEADERS.signature)}=`, ); assert.throws(() => verify(paddedSignature), hasCode("managed_provisioner_signature_invalid", 401)); const uppercaseHash = signedRequest(); setHeader( uppercaseHash, MANAGED_PROVISIONER_HEADERS.bodySha256, header(uppercaseHash, MANAGED_PROVISIONER_HEADERS.bodySha256).toUpperCase(), ); assert.throws(() => verify(uppercaseHash), hasCode("managed_provisioner_body_hash_invalid", 401)); const cache = new ManagedProvisionerReplayCache({ maxEntries: 1 }); cache.consume("first", nowMs + 1000, nowMs); assert.throws(() => cache.consume("second", nowMs + 1000, nowMs), hasCode("managed_provisioner_replay_cache_exhausted", 503)); assert.throws(() => cache.consume("first", nowMs + 1000, nowMs), hasCode("managed_provisioner_request_replayed", 409)); cache.consume("second", nowMs + 2000, nowMs + 1000); const directory = await mkdtemp(join(tmpdir(), "nodedc-edp-managed-auth-")); try { const publicKeyPath = join(directory, "engine-public-key.pem"); const rsaPublicKeyPath = join(directory, "rsa-public-key.pem"); const privateKeyPath = join(directory, "engine-private-key.pem"); const symlinkPath = join(directory, "engine-public-key-link.pem"); await writeFile(publicKeyPath, publicKey.export({ type: "spki", format: "pem" }), { mode: 0o600 }); assert.equal(loadManagedProvisionerPublicKeyFile(publicKeyPath).asymmetricKeyType, "ed25519"); assert.throws( () => loadManagedProvisionerPublicKeyFile("relative-public-key.pem"), /external_data_plane_managed_provisioner_public_key_file_must_be_absolute/, ); assert.throws( () => loadManagedProvisionerPublicKeyFile(join(directory, "missing.pem")), /external_data_plane_managed_provisioner_public_key_file_unreadable/, ); await symlink(publicKeyPath, symlinkPath); assert.throws( () => loadManagedProvisionerPublicKeyFile(symlinkPath), /external_data_plane_managed_provisioner_public_key_file_must_be_regular/, ); await chmod(publicKeyPath, 0o622); assert.throws( () => loadManagedProvisionerPublicKeyFile(publicKeyPath), /external_data_plane_managed_provisioner_public_key_file_permissions_invalid/, ); await chmod(publicKeyPath, 0o600); const { publicKey: rsaPublicKey } = generateKeyPairSync("rsa", { modulusLength: 2048 }); await writeFile(rsaPublicKeyPath, rsaPublicKey.export({ type: "spki", format: "pem" }), { mode: 0o600 }); assert.throws( () => loadManagedProvisionerPublicKeyFile(rsaPublicKeyPath), /external_data_plane_managed_provisioner_public_key_algorithm_invalid/, ); await writeFile(privateKeyPath, privateKey.export({ type: "pkcs8", format: "pem" }), { mode: 0o600 }); assert.throws( () => loadManagedProvisionerPublicKeyFile(privateKeyPath), /external_data_plane_managed_provisioner_public_key_file_format_invalid/, ); } finally { await rm(directory, { recursive: true, force: true }); } console.log("external-data-plane managed provisioner auth: ok"); function signedRequest({ method = "PUT", path = "/internal/data-plane/v1/writer-bindings/by-key/engine.test.positions", rawBody = Buffer.from('{"generation":1}', "utf8"), timestamp = new Date(nowMs).toISOString(), nonce = nextNonce(), } = {}) { const bodySha256 = sha256RawBody(rawBody); const signature = sign(null, Buffer.from(managedProvisionerSigningPayload({ audience, serviceId, keyId, method, path, timestamp, nonce, bodySha256, }), "utf8"), privateKey).toString("base64url"); const headers = { [MANAGED_PROVISIONER_HEADERS.serviceId]: serviceId, [MANAGED_PROVISIONER_HEADERS.keyId]: keyId, [MANAGED_PROVISIONER_HEADERS.audience]: audience, [MANAGED_PROVISIONER_HEADERS.timestamp]: timestamp, [MANAGED_PROVISIONER_HEADERS.nonce]: nonce, [MANAGED_PROVISIONER_HEADERS.bodySha256]: bodySha256, [MANAGED_PROVISIONER_HEADERS.signature]: signature, "content-length": String(rawBody.length), }; return { method, originalUrl: path, headers, rawHeaders: Object.entries(headers).flat(), rawBody, rawBodyCaptured: true, }; } function nextNonce() { nonceSequence += 1; return Buffer.from(`managed-auth-test-${String(nonceSequence).padStart(6, "0")}`).toString("base64url"); } function header(req, name) { return req.headers[name]; } function setHeader(req, name, value) { req.headers[name] = value; const index = req.rawHeaders.findIndex((candidate) => String(candidate).toLowerCase() === name); req.rawHeaders[index + 1] = value; } function hasCode(code, status) { return (error) => error?.code === code && error?.status === status; }