mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-23 23:22:32 +00:00
fix: address review feedback
This commit is contained in:
committed by
Peter Steinberger
parent
b02b2c3a0b
commit
74270762ff
@@ -320,7 +320,6 @@ function buildPluginRequestStages(params: {
|
||||
return [];
|
||||
}
|
||||
let pluginGatewayAuthSatisfied = false;
|
||||
let pluginRequestAuth: AuthorizedGatewayHttpRequest | undefined;
|
||||
let pluginRequestOperatorScopes: string[] | undefined;
|
||||
return [
|
||||
{
|
||||
@@ -350,7 +349,6 @@ function buildPluginRequestStages(params: {
|
||||
return true;
|
||||
}
|
||||
pluginGatewayAuthSatisfied = true;
|
||||
pluginRequestAuth = requestAuth;
|
||||
pluginRequestOperatorScopes = resolvePluginRouteRuntimeOperatorScopes(
|
||||
params.req,
|
||||
requestAuth,
|
||||
@@ -366,7 +364,6 @@ function buildPluginRequestStages(params: {
|
||||
return (
|
||||
params.handlePluginRequest?.(params.req, params.res, pathContext, {
|
||||
gatewayAuthSatisfied: pluginGatewayAuthSatisfied,
|
||||
gatewayRequestAuth: pluginRequestAuth,
|
||||
gatewayRequestOperatorScopes: pluginRequestOperatorScopes,
|
||||
}) ?? false
|
||||
);
|
||||
|
||||
@@ -320,6 +320,64 @@ describe("gateway plugin HTTP auth boundary", () => {
|
||||
expect(writeAllowedResults).toEqual([false]);
|
||||
});
|
||||
|
||||
test("keeps write runtime scopes for shared-secret bearer gateway-auth plugin routes", async () => {
|
||||
const observedRuntimeScopes: string[][] = [];
|
||||
const writeAllowedResults: boolean[] = [];
|
||||
const handlePluginRequest = createGatewayPluginRequestHandler({
|
||||
registry: createTestRegistry({
|
||||
httpRoutes: [
|
||||
{
|
||||
pluginId: "runtime-scope-bearer",
|
||||
source: "runtime-scope-bearer",
|
||||
path: "/secure-hook",
|
||||
auth: "gateway",
|
||||
match: "exact",
|
||||
handler: async (_req: IncomingMessage, res: ServerResponse) => {
|
||||
const runtimeScopes =
|
||||
getPluginRuntimeGatewayRequestScope()?.client?.connect?.scopes?.slice() ?? [];
|
||||
observedRuntimeScopes.push(runtimeScopes);
|
||||
const writeAuth = authorizeOperatorScopesForMethod("node.invoke", runtimeScopes);
|
||||
writeAllowedResults.push(writeAuth.allowed);
|
||||
res.statusCode = 200;
|
||||
res.end("ok");
|
||||
return true;
|
||||
},
|
||||
},
|
||||
],
|
||||
}),
|
||||
log: { warn: vi.fn() } as Parameters<typeof createGatewayPluginRequestHandler>[0]["log"],
|
||||
});
|
||||
|
||||
await withGatewayServer({
|
||||
prefix: "openclaw-plugin-http-runtime-scope-bearer-test-",
|
||||
resolvedAuth: AUTH_TOKEN,
|
||||
overrides: {
|
||||
handlePluginRequest,
|
||||
shouldEnforcePluginGatewayAuth: (pathContext) => pathContext.pathname === "/secure-hook",
|
||||
},
|
||||
run: async (server) => {
|
||||
const response = createResponse();
|
||||
await dispatchRequest(
|
||||
server,
|
||||
createRequest({
|
||||
path: "/secure-hook",
|
||||
authorization: "Bearer test-token",
|
||||
headers: {
|
||||
"x-openclaw-scopes": "operator.read",
|
||||
},
|
||||
}),
|
||||
response.res,
|
||||
);
|
||||
|
||||
expect(response.res.statusCode).toBe(200);
|
||||
expect(response.getBody()).toBe("ok");
|
||||
},
|
||||
});
|
||||
|
||||
expect(observedRuntimeScopes).toEqual([["operator.write"]]);
|
||||
expect(writeAllowedResults).toEqual([true]);
|
||||
});
|
||||
|
||||
test("allows unauthenticated Mattermost slash callback routes while keeping other channel routes protected", async () => {
|
||||
const handlePluginRequest = vi.fn(async (req: IncomingMessage, res: ServerResponse) => {
|
||||
const pathname = new URL(req.url ?? "/", "http://localhost").pathname;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { IncomingMessage, ServerResponse } from "node:http";
|
||||
import type { IncomingMessage } from "node:http";
|
||||
import { A2UI_PATH, CANVAS_HOST_PATH, CANVAS_WS_PATH } from "../../canvas-host/a2ui.js";
|
||||
import { safeEqualSecret } from "../../security/secret-equal.js";
|
||||
import type { AuthRateLimiter } from "../auth-rate-limit.js";
|
||||
@@ -8,7 +8,6 @@ import {
|
||||
type ResolvedGatewayAuth,
|
||||
} from "../auth.js";
|
||||
import { CANVAS_CAPABILITY_TTL_MS } from "../canvas-capability.js";
|
||||
import { authorizeGatewayBearerRequestOrReply } from "../http-auth-helpers.js";
|
||||
import { getBearerToken, resolveHttpBrowserOriginPolicy } from "../http-utils.js";
|
||||
import { GATEWAY_CLIENT_MODES, normalizeGatewayClientMode } from "../protocol/client-info.js";
|
||||
import type { GatewayWsClient } from "./ws-types.js";
|
||||
@@ -101,14 +100,3 @@ export async function authorizeCanvasRequest(params: {
|
||||
}
|
||||
return lastAuthFailure ?? { ok: false, reason: "unauthorized" };
|
||||
}
|
||||
|
||||
export async function enforcePluginRouteGatewayAuth(params: {
|
||||
req: IncomingMessage;
|
||||
res: ServerResponse;
|
||||
auth: ResolvedGatewayAuth;
|
||||
trustedProxies: string[];
|
||||
allowRealIpFallback: boolean;
|
||||
rateLimiter?: AuthRateLimiter;
|
||||
}): Promise<boolean> {
|
||||
return await authorizeGatewayBearerRequestOrReply(params);
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ import type { createSubsystemLogger } from "../../logging/subsystem.js";
|
||||
import type { PluginRegistry } from "../../plugins/registry.js";
|
||||
import { resolveActivePluginHttpRouteRegistry } from "../../plugins/runtime.js";
|
||||
import { withPluginRuntimeGatewayRequestScope } from "../../plugins/runtime/gateway-request-scope.js";
|
||||
import type { AuthorizedGatewayHttpRequest } from "../http-utils.js";
|
||||
import { GATEWAY_CLIENT_IDS, GATEWAY_CLIENT_MODES } from "../protocol/client-info.js";
|
||||
import { PROTOCOL_VERSION } from "../protocol/index.js";
|
||||
import type { GatewayRequestOptions } from "../server-methods/types.js";
|
||||
@@ -48,7 +47,6 @@ function createPluginRouteRuntimeClient(
|
||||
|
||||
export type PluginRouteDispatchContext = {
|
||||
gatewayAuthSatisfied?: boolean;
|
||||
gatewayRequestAuth?: AuthorizedGatewayHttpRequest;
|
||||
gatewayRequestOperatorScopes?: readonly string[];
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user