mirror of https://github.com/openclaw/openclaw.git
refactor: share browser auth test helpers
This commit is contained in:
parent
03c2814124
commit
389de66b25
|
|
@ -30,6 +30,11 @@ const TEST_OPERATOR_CLIENT = {
|
|||
mode: GATEWAY_CLIENT_MODES.TEST,
|
||||
};
|
||||
const ALLOWED_BROWSER_ORIGIN = "https://control.example.com";
|
||||
const TRUSTED_PROXY_BROWSER_HEADERS = {
|
||||
"x-forwarded-for": "203.0.113.50",
|
||||
"x-forwarded-proto": "https",
|
||||
"x-forwarded-user": "operator@example.com",
|
||||
};
|
||||
|
||||
const originForPort = (port: number) => `http://127.0.0.1:${port}`;
|
||||
|
||||
|
|
@ -75,120 +80,73 @@ async function createSignedDevice(params: {
|
|||
};
|
||||
}
|
||||
|
||||
describe("gateway auth browser hardening", () => {
|
||||
test("rejects trusted-proxy browser connects from origins outside the allowlist", async () => {
|
||||
const { writeConfigFile } = await import("../config/config.js");
|
||||
await writeConfigFile({
|
||||
gateway: {
|
||||
auth: {
|
||||
mode: "trusted-proxy",
|
||||
trustedProxy: {
|
||||
userHeader: "x-forwarded-user",
|
||||
requiredHeaders: ["x-forwarded-proto"],
|
||||
},
|
||||
},
|
||||
trustedProxies: ["127.0.0.1"],
|
||||
controlUi: {
|
||||
allowedOrigins: [ALLOWED_BROWSER_ORIGIN],
|
||||
async function writeTrustedProxyBrowserAuthConfig() {
|
||||
const { writeConfigFile } = await import("../config/config.js");
|
||||
await writeConfigFile({
|
||||
gateway: {
|
||||
auth: {
|
||||
mode: "trusted-proxy",
|
||||
trustedProxy: {
|
||||
userHeader: "x-forwarded-user",
|
||||
requiredHeaders: ["x-forwarded-proto"],
|
||||
},
|
||||
},
|
||||
});
|
||||
trustedProxies: ["127.0.0.1"],
|
||||
controlUi: {
|
||||
allowedOrigins: [ALLOWED_BROWSER_ORIGIN],
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
await withGatewayServer(async ({ port }) => {
|
||||
const ws = await openWs(port, {
|
||||
origin: "https://evil.example",
|
||||
"x-forwarded-for": "203.0.113.50",
|
||||
"x-forwarded-proto": "https",
|
||||
"x-forwarded-user": "operator@example.com",
|
||||
async function withTrustedProxyBrowserWs(origin: string, run: (ws: WebSocket) => Promise<void>) {
|
||||
await writeTrustedProxyBrowserAuthConfig();
|
||||
await withGatewayServer(async ({ port }) => {
|
||||
const ws = await openWs(port, {
|
||||
origin,
|
||||
...TRUSTED_PROXY_BROWSER_HEADERS,
|
||||
});
|
||||
try {
|
||||
await run(ws);
|
||||
} finally {
|
||||
ws.close();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
describe("gateway auth browser hardening", () => {
|
||||
test("rejects trusted-proxy browser connects from origins outside the allowlist", async () => {
|
||||
await withTrustedProxyBrowserWs("https://evil.example", async (ws) => {
|
||||
const res = await connectReq(ws, {
|
||||
client: TEST_OPERATOR_CLIENT,
|
||||
device: null,
|
||||
});
|
||||
try {
|
||||
const res = await connectReq(ws, {
|
||||
client: TEST_OPERATOR_CLIENT,
|
||||
device: null,
|
||||
});
|
||||
expect(res.ok).toBe(false);
|
||||
expect(res.error?.message ?? "").toContain("origin not allowed");
|
||||
} finally {
|
||||
ws.close();
|
||||
}
|
||||
expect(res.ok).toBe(false);
|
||||
expect(res.error?.message ?? "").toContain("origin not allowed");
|
||||
});
|
||||
});
|
||||
|
||||
test("accepts trusted-proxy browser connects from allowed origins", async () => {
|
||||
const { writeConfigFile } = await import("../config/config.js");
|
||||
await writeConfigFile({
|
||||
gateway: {
|
||||
auth: {
|
||||
mode: "trusted-proxy",
|
||||
trustedProxy: {
|
||||
userHeader: "x-forwarded-user",
|
||||
requiredHeaders: ["x-forwarded-proto"],
|
||||
},
|
||||
},
|
||||
trustedProxies: ["127.0.0.1"],
|
||||
controlUi: {
|
||||
allowedOrigins: [ALLOWED_BROWSER_ORIGIN],
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await withGatewayServer(async ({ port }) => {
|
||||
const ws = await openWs(port, {
|
||||
origin: ALLOWED_BROWSER_ORIGIN,
|
||||
"x-forwarded-for": "203.0.113.50",
|
||||
"x-forwarded-proto": "https",
|
||||
"x-forwarded-user": "operator@example.com",
|
||||
await withTrustedProxyBrowserWs(ALLOWED_BROWSER_ORIGIN, async (ws) => {
|
||||
const payload = await connectOk(ws, {
|
||||
client: TEST_OPERATOR_CLIENT,
|
||||
device: null,
|
||||
});
|
||||
try {
|
||||
const payload = await connectOk(ws, {
|
||||
client: TEST_OPERATOR_CLIENT,
|
||||
device: null,
|
||||
});
|
||||
expect(payload.type).toBe("hello-ok");
|
||||
} finally {
|
||||
ws.close();
|
||||
}
|
||||
expect(payload.type).toBe("hello-ok");
|
||||
});
|
||||
});
|
||||
|
||||
test("preserves scopes for trusted-proxy non-control-ui browser sessions", async () => {
|
||||
const { writeConfigFile } = await import("../config/config.js");
|
||||
await writeConfigFile({
|
||||
gateway: {
|
||||
auth: {
|
||||
mode: "trusted-proxy",
|
||||
trustedProxy: {
|
||||
userHeader: "x-forwarded-user",
|
||||
requiredHeaders: ["x-forwarded-proto"],
|
||||
},
|
||||
},
|
||||
trustedProxies: ["127.0.0.1"],
|
||||
controlUi: {
|
||||
allowedOrigins: [ALLOWED_BROWSER_ORIGIN],
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await withGatewayServer(async ({ port }) => {
|
||||
const ws = await openWs(port, {
|
||||
origin: ALLOWED_BROWSER_ORIGIN,
|
||||
"x-forwarded-for": "203.0.113.50",
|
||||
"x-forwarded-proto": "https",
|
||||
"x-forwarded-user": "operator@example.com",
|
||||
await withTrustedProxyBrowserWs(ALLOWED_BROWSER_ORIGIN, async (ws) => {
|
||||
const payload = await connectOk(ws, {
|
||||
client: TEST_OPERATOR_CLIENT,
|
||||
device: null,
|
||||
scopes: ["operator.read"],
|
||||
});
|
||||
try {
|
||||
const payload = await connectOk(ws, {
|
||||
client: TEST_OPERATOR_CLIENT,
|
||||
device: null,
|
||||
scopes: ["operator.read"],
|
||||
});
|
||||
expect(payload.type).toBe("hello-ok");
|
||||
expect(payload.type).toBe("hello-ok");
|
||||
|
||||
const status = await rpcReq(ws, "status");
|
||||
expect(status.ok).toBe(true);
|
||||
} finally {
|
||||
ws.close();
|
||||
}
|
||||
const status = await rpcReq(ws, "status");
|
||||
expect(status.ok).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue