This is an automated email from the ASF dual-hosted git repository.
ricardozanini pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/incubator-kie-tools.git
The following commit(s) were added to refs/heads/main by this push:
new 9c4509180ba kie-tools#3308: [cors-proxy] CORS code-scanning issues
(#3327)
9c4509180ba is described below
commit 9c4509180ba82c24c1878c7281cce8f6b01e982b
Author: Fabrizio Antonangeli <[email protected]>
AuthorDate: Mon Dec 1 16:04:04 2025 +0100
kie-tools#3308: [cors-proxy] CORS code-scanning issues (#3327)
---
packages/cors-proxy-image/Containerfile | 4 +-
packages/cors-proxy-image/README.md | 10 +-
packages/cors-proxy-image/env/index.js | 8 +-
packages/cors-proxy-image/package.json | 2 +-
packages/cors-proxy/README.md | 16 +-
packages/cors-proxy/env/index.js | 10 +-
packages/cors-proxy/package.json | 4 +-
packages/cors-proxy/src/index.ts | 17 +-
packages/cors-proxy/src/proxy/ExpressCorsProxy.ts | 14 +-
packages/cors-proxy/src/proxy/server.ts | 14 +-
packages/cors-proxy/tests/index.test.ts | 106 +++++++++----
packages/cors-proxy/tests/server.test.ts | 175 +++++++++++++++++++++
packages/online-editor/package.json | 2 +-
.../server/config/index.js | 2 +-
.../server/server.js | 9 ++
packages/serverless-logic-web-tools/package.json | 4 +-
.../serverless-workflow-dev-ui-webapp/package.json | 4 +-
packages/sonataflow-deployment-webapp/package.json | 4 +-
packages/sonataflow-dev-app/README.md | 6 +-
.../sonataflow-dev-app/src/MockData/graphql.js | 2 +-
packages/sonataflow-dev-app/src/config/index.js | 2 +-
packages/sonataflow-dev-app/src/server.js | 9 ++
.../package.json | 4 +-
23 files changed, 352 insertions(+), 76 deletions(-)
diff --git a/packages/cors-proxy-image/Containerfile
b/packages/cors-proxy-image/Containerfile
index f54565738fe..84450e5b32c 100644
--- a/packages/cors-proxy-image/Containerfile
+++ b/packages/cors-proxy-image/Containerfile
@@ -18,7 +18,7 @@
FROM --platform=linux/amd64 registry.access.redhat.com/ubi9/ubi-minimal:9.5
ARG CORS_PROXY_DEFAULT_PORT=8080
-ARG CORS_PROXY_DEFAULT_ORIGIN=*
+ARG CORS_PROXY_DEFAULT_ALLOWED_ORIGINS=
ARG CORS_PROXY_DEFAULT_VERBOSE=false
ENV HOME /home/kie-sandbox
@@ -26,7 +26,7 @@ ENV NVM_DIR $HOME/.nvm
ENV NODE_VERSION v22.14.0
ENV CORS_PROXY_HTTP_PORT=$CORS_PROXY_DEFAULT_PORT
-ENV CORS_PROXY_ORIGIN=$CORS_PROXY_DEFAULT_ORIGIN
+ENV CORS_PROXY_ALLOWED_ORIGINS=$CORS_PROXY_DEFAULT_ALLOWED_ORIGINS
ENV CORS_PROXY_VERBOSE=$CORS_PROXY_DEFAULT_VERBOSE
RUN mkdir $HOME \
diff --git a/packages/cors-proxy-image/README.md
b/packages/cors-proxy-image/README.md
index fc900cb27ee..98f17ba6100 100644
--- a/packages/cors-proxy-image/README.md
+++ b/packages/cors-proxy-image/README.md
@@ -39,7 +39,7 @@ export CORS_PROXY_IMAGE__imageAccount=<account>
export CORS_PROXY_IMAGE__imageName=<image-name>
export CORS_PROXY_IMAGE__imageBuildTag=<image-tag>
export CORS_PROXY_IMAGE__imagePort=<port>
-export CORS_PROXY_IMAGE__imageOrigin=<origin>
+export CORS_PROXY_IMAGE__imageAllowedOrigins=<allowed-origins> #
Comma-separated list
export CORS_PROXY_IMAGE__imageVerbose=<verbose>
```
@@ -62,7 +62,13 @@ docker images
Start up a new container with:
```bash
-docker run -p 8080:8080 -i --rm docker.io/apache/incubator-kie-cors-proxy:main
+docker run -p 8080:8080 -i --rm -e
CORS_PROXY_ALLOWED_ORIGINS="http://localhost:9001"
docker.io/apache/incubator-kie-cors-proxy:main
+```
+
+Or in production:
+
+```bash
+docker run -p 8080:8080 -i --rm -e
CORS_PROXY_ALLOWED_ORIGINS="https://example.com,https://other.example.com"
docker.io/apache/incubator-kie-cors-proxy:main
```
The service will be up at http://localhost:8080
diff --git a/packages/cors-proxy-image/env/index.js
b/packages/cors-proxy-image/env/index.js
index 3370b84838f..411050ddea1 100644
--- a/packages/cors-proxy-image/env/index.js
+++ b/packages/cors-proxy-image/env/index.js
@@ -44,9 +44,9 @@ module.exports = composeEnv([rootEnv], {
default: corsProxyEnv.env.corsProxy.dev.port,
description: "HTTP port where the CORS proxy will run inside this
image.",
},
- CORS_PROXY_IMAGE__imageOrigin: {
- default: corsProxyEnv.env.corsProxy.dev.origin,
- description: "Origin to be used for the CORS proxy running inside this
image.",
+ CORS_PROXY_IMAGE__imageAllowedOrigins: {
+ default: corsProxyEnv.env.corsProxy.dev.allowedOrigins,
+ description: "Comma-separated list of allowed origins for the CORS proxy
running inside this image.",
},
CORS_PROXY_IMAGE__imageVerbose: {
default: false,
@@ -62,7 +62,7 @@ module.exports = composeEnv([rootEnv], {
name: getOrDefault(this.vars.CORS_PROXY_IMAGE__imageName),
buildTag: getOrDefault(this.vars.CORS_PROXY_IMAGE__imageBuildTag),
port: getOrDefault(this.vars.CORS_PROXY_IMAGE__imagePort),
- origin: getOrDefault(this.vars.CORS_PROXY_IMAGE__imageOrigin),
+ allowedOrigins:
getOrDefault(this.vars.CORS_PROXY_IMAGE__imageAllowedOrigins),
verbose: getOrDefault(this.vars.CORS_PROXY_IMAGE__imageVerbose),
},
},
diff --git a/packages/cors-proxy-image/package.json
b/packages/cors-proxy-image/package.json
index 5a1ce8ca09f..d518b2b0fab 100644
--- a/packages/cors-proxy-image/package.json
+++ b/packages/cors-proxy-image/package.json
@@ -19,7 +19,7 @@
"copy:cors-proxy-package": "run-script-os",
"copy:cors-proxy-package:linux:darwin": "cp -R
./node_modules/@kie-tools/cors-proxy/dist/ dist-dev/cors-proxy/",
"copy:cors-proxy-package:win32": "pnpm powershell \"Copy-Item -R
./node_modules/@kie-tools/cors-proxy/dist/ dist-dev/cors-proxy/\"",
- "docker:build": "kie-tools--image-builder build -r \"$(build-env
corsProxyImage.image.registry)\" -a \"$(build-env
corsProxyImage.image.account)\" -n \"$(build-env corsProxyImage.image.name)\"
-t \"$(build-env corsProxyImage.image.buildTag)\" --build-arg
\"CORS_PROXY_DEFAULT_HTTP_PORT=$(build-env corsProxyImage.image.port)\"
--build-arg \"CORS_PROXY_DEFAULT_ORIGIN=$(build-env
corsProxyImage.image.origin)\" --build-arg
\"CORS_PROXY_DEFAULT_VERBOSE=$(build-env corsProxyImage.image.verbose)\""
+ "docker:build": "kie-tools--image-builder build -r \"$(build-env
corsProxyImage.image.registry)\" -a \"$(build-env
corsProxyImage.image.account)\" -n \"$(build-env corsProxyImage.image.name)\"
-t \"$(build-env corsProxyImage.image.buildTag)\" --build-arg
\"CORS_PROXY_DEFAULT_PORT=$(build-env corsProxyImage.image.port)\" --build-arg
\"CORS_PROXY_DEFAULT_ALLOWED_ORIGINS=$(build-env
corsProxyImage.image.allowedOrigins)\" --build-arg
\"CORS_PROXY_DEFAULT_VERBOSE=$(build-env corsProxyImag [...]
},
"devDependencies": {
"@kie-tools/cors-proxy": "workspace:*",
diff --git a/packages/cors-proxy/README.md b/packages/cors-proxy/README.md
index 78c966bc170..9a4edc4d157 100644
--- a/packages/cors-proxy/README.md
+++ b/packages/cors-proxy/README.md
@@ -23,8 +23,8 @@ This package contains a `cors-proxy`, which is a simple
Node.js application inte
The `cors-proxy` can be configured via environment variables:
-- CORS_PROXY_HTTP_PORT: Sets the HTTP Port the proxy should listen to
-- CORS_PROXY_ORIGIN: Sets the value of the 'Access-Control-Allow-Origin'
header. Defaults to `*`.
+- CORS_PROXY_ALLOWED_ORIGINS: **Required** Comma-separated list of allowed
origins. Wildcard `*` is not allowed for security reasons.
+- CORS_PROXY_HTTP_PORT: Sets the HTTP Port the proxy should listen to.
Defaults to `8080`
- CORS_PROXY_VERBOSE: Allows the proxy to run in verbose mode... useful to
trace requests on development environments. Defaults to `false`
- CORS_PROXY_USE_HTTP_FOR_HOSTS: Comma-separated list of hosts that should use
the `http` protocol for proxied requests. Defaults to an empty list.
- HTTP_PROXY or HTTPS_PROXY: Url of a proxy that will be used to proxy the
requests `cors-proxy` is already proxying.
@@ -34,7 +34,7 @@ For example:
```bash
export CORS_PROXY_HTTP_PORT=8080
-export CORS_PROXY_ORIGIN=*
+export
CORS_PROXY_ALLOWED_ORIGINS="https://example.com,https://other.example.com"
export CORS_PROXY_VERBOSE=false
export CORS_PROXY_USE_HTTP_FOR_HOSTS="localhost:8080,localhost:8081"
```
@@ -56,14 +56,14 @@ node ./dist/index.js
# Running `cors-proxy` in dev mode.
```bash
-pnpm -F @kie-tools/cors-proxy start
+CORS_PROXY__allowedOrigins="http://localhost:9001" pnpm -F
@kie-tools/cors-proxy start
```
You can also use the following envs to configure `cors-proxy` when starting in
dev-mode:
```bash
+export CORS_PROXY__allowedOrigins="http://localhost:9001"
export CORS_PROXY__port=*
-export CORS_PROXY__origin=*
export CORS_PROXY__verbose=false
export CORS_PROXY__useHttpForHosts="localhost:8080,localhost:8081"
```
@@ -83,7 +83,7 @@ mitmweb --set listen_port=<PORT> --showhost
Now set the HTTPS_PROXY and NODE_EXTRA_CA_CERTS environment variables before
starting the `cors-proxy` service:
```bash
-export HTTPS_PROXY=http://localhost:<PORT
+export HTTPS_PROXY=http://localhost:<PORT>
export NODE_EXTRA_CA_CERTS=~/.mitmproxy/mitmproxy-ca-cert.pem
```
@@ -93,9 +93,9 @@ Set the rest of the environment variables and start the
`cors-proxy` service:
```bash
export CORS_PROXY__port=*
-export CORS_PROXY__origin=*
+export CORS_PROXY__allowedOrigins="http://localhost:9001"
-pnpm -F @kie-tools/cors-proxy start
+ pnpm -F @kie-tools/cors-proxy start
```
---
diff --git a/packages/cors-proxy/env/index.js b/packages/cors-proxy/env/index.js
index 41803812c85..c7ace6d1fed 100644
--- a/packages/cors-proxy/env/index.js
+++ b/packages/cors-proxy/env/index.js
@@ -21,14 +21,14 @@ const { varsWithName, composeEnv, getOrDefault } =
require("@kie-tools-scripts/b
module.exports = composeEnv([require("@kie-tools/root-env/env")], {
vars: varsWithName({
+ CORS_PROXY__allowedOrigins: {
+ default: "http://localhost:9001",
+ description: "Comma-separated list of allowed origins used to set on the
'Access-Control-Allow-Origin' header",
+ },
CORS_PROXY__port: {
default: 8080,
description: "HTTP Port the proxy should listen to",
},
- CORS_PROXY__origin: {
- default: "*",
- description: "Value to set on the 'Access-Control-Allow-Origin' header",
- },
CORS_PROXY__verbose: {
default: true,
description: "Allows the proxy to run in verbose mode... useful to trace
requests on development environments",
@@ -42,8 +42,8 @@ module.exports =
composeEnv([require("@kie-tools/root-env/env")], {
return {
corsProxy: {
dev: {
+ allowedOrigins: getOrDefault(this.vars.CORS_PROXY__allowedOrigins),
port: getOrDefault(this.vars.CORS_PROXY__port),
- origin: getOrDefault(this.vars.CORS_PROXY__origin),
verbose: getOrDefault(this.vars.CORS_PROXY__verbose),
useHttpForHosts: getOrDefault(this.vars.CORS_PROXY__useHttpForHosts),
},
diff --git a/packages/cors-proxy/package.json b/packages/cors-proxy/package.json
index 123090ca0bc..82cc1781adf 100644
--- a/packages/cors-proxy/package.json
+++ b/packages/cors-proxy/package.json
@@ -21,8 +21,8 @@
"build:prod": "pnpm lint && pnpm test && rimraf dist && webpack",
"lint": "run-script-if --bool \"$(build-env linters.run)\" --then
\"kie-tools--eslint ./src\"",
"start": "run-script-os",
- "start:darwin:linux": "pnpm build:dev && cross-env
CORS_PROXY_USE_HTTP_FOR_HOSTS=$(build-env corsProxy.dev.useHttpForHosts)
CORS_PROXY_HTTP_PORT=$(build-env corsProxy.dev.port)
CORS_PROXY_ORIGIN=$(build-env corsProxy.dev.origin)
CORS_PROXY_VERBOSE=$(build-env corsProxy.dev.verbose) node dist/index.js",
- "start:win32": "pnpm build:dev && pnpm powershell \"cross-env
CORS_PROXY_USE_HTTP_FOR_HOSTS=$(build-env corsProxy.dev.useHttpForHosts)
CORS_PROXY_HTTP_PORT=$(build-env corsProxy.dev.port)
CORS_PROXY_ORIGIN=$(build-env corsProxy.dev.origin)
CORS_PROXY_VERBOSE=$(build-env corsProxy.dev.verbose) node dist/index.js\"",
+ "start:darwin:linux": "pnpm build:dev && cross-env
CORS_PROXY_USE_HTTP_FOR_HOSTS=$(build-env corsProxy.dev.useHttpForHosts)
CORS_PROXY_HTTP_PORT=$(build-env corsProxy.dev.port)
CORS_PROXY_ALLOWED_ORIGINS=$(build-env corsProxy.dev.allowedOrigins)
CORS_PROXY_VERBOSE=$(build-env corsProxy.dev.verbose) node dist/index.js",
+ "start:win32": "pnpm build:dev && pnpm powershell \"cross-env
CORS_PROXY_USE_HTTP_FOR_HOSTS=$(build-env corsProxy.dev.useHttpForHosts)
CORS_PROXY_HTTP_PORT=$(build-env corsProxy.dev.port)
CORS_PROXY_ALLOWED_ORIGINS=$(build-env corsProxy.dev.allowedOrigins)
CORS_PROXY_VERBOSE=$(build-env corsProxy.dev.verbose) node dist/index.js\"",
"test": "run-script-if --ignore-errors \"$(build-env
tests.ignoreFailures)\" --bool \"$(build-env tests.run)\" --then \"jest
--silent --verbose --passWithNoTests\""
},
"dependencies": {
diff --git a/packages/cors-proxy/src/index.ts b/packages/cors-proxy/src/index.ts
index f3d273f45d2..6020b615b0e 100644
--- a/packages/cors-proxy/src/index.ts
+++ b/packages/cors-proxy/src/index.ts
@@ -27,10 +27,25 @@ function getPort(): number {
return 8080;
}
+function getAllowedOrigins(): string[] {
+ const origins = process.env.CORS_PROXY_ALLOWED_ORIGINS || "";
+ const originsList = origins.split(",").map((o) => o.trim());
+
+ if (originsList.some((o) => o === "")) {
+ throw new Error("Invalid origin: empty origins are not allowed in
CORS_PROXY_ALLOWED_ORIGINS.");
+ }
+
+ if (originsList.some((o) => o === "*")) {
+ throw new Error('Invalid origin: wildcard "*" is not allowed in
CORS_PROXY_ALLOWED_ORIGINS.');
+ }
+
+ return originsList;
+}
+
export const run = () => {
startServer({
+ allowedOrigins: getAllowedOrigins(),
port: getPort(),
- origin: process.env.CORS_PROXY_ORIGIN ?? "*",
verbose: process.env.CORS_PROXY_VERBOSE === "true",
hostsToUseHttp: (process.env.CORS_PROXY_USE_HTTP_FOR_HOSTS ||
undefined)?.split(",") ?? [],
});
diff --git a/packages/cors-proxy/src/proxy/ExpressCorsProxy.ts
b/packages/cors-proxy/src/proxy/ExpressCorsProxy.ts
index 6cede0a2a37..9ae560ab737 100644
--- a/packages/cors-proxy/src/proxy/ExpressCorsProxy.ts
+++ b/packages/cors-proxy/src/proxy/ExpressCorsProxy.ts
@@ -37,7 +37,7 @@ export class ExpressCorsProxy implements CorsProxy<Request,
Response> {
constructor(
private readonly args: {
- origin: string;
+ allowedOrigins: string[];
verbose: boolean;
hostsToUseHttp: string[];
}
@@ -46,7 +46,6 @@ export class ExpressCorsProxy implements CorsProxy<Request,
Response> {
this.logger.debug("");
this.logger.debug("Proxy Configuration:");
- this.logger.debug("* Accept Origin Header: ", `"${args.origin}"`);
this.logger.debug("* Verbose: ", args.verbose);
this.logger.debug("");
}
@@ -92,9 +91,6 @@ export class ExpressCorsProxy implements CorsProxy<Request,
Response> {
});
this.logger.debug("Proxy Response status: ", proxyResponse.status);
- // Setting up the headers to the original response...
- res.header("Access-Control-Allow-Origin", this.args.origin);
-
if (req.method == "OPTIONS") {
res.header("Access-Control-Allow-Methods",
info.corsConfig?.allowMethods.join(", ") ?? "*");
res.header("Access-Control-Allow-Headers",
info.corsConfig?.allowHeaders.join(", ") ?? "*");
@@ -105,6 +101,9 @@ export class ExpressCorsProxy implements CorsProxy<Request,
Response> {
}
proxyResponse.headers.forEach((value, header) => {
+ if (header.toLowerCase() === "access-control-allow-origin") {
+ return;
+ }
if (!info.corsConfig ||
info.corsConfig.exposeHeaders.includes(header)) {
res.setHeader(header, value);
}
@@ -140,7 +139,12 @@ export class ExpressCorsProxy implements
CorsProxy<Request, Response> {
}
private resolveRequestInfo(request: Request): ProxyRequestInfo {
+ const origin = request.header("origin");
const targetUrl: string = (request.headers[CorsProxyHeaderKeys.TARGET_URL]
as string) ?? request.url;
+ if (!origin || !this.args.allowedOrigins.includes(origin)) {
+ throw new Error(`Origin ${origin} is not allowed`);
+ }
+
if (!targetUrl || targetUrl == "/") {
throw new Error("Couldn't resolve the target URL...");
}
diff --git a/packages/cors-proxy/src/proxy/server.ts
b/packages/cors-proxy/src/proxy/server.ts
index 97de03fac2a..cb71c6e9cdb 100644
--- a/packages/cors-proxy/src/proxy/server.ts
+++ b/packages/cors-proxy/src/proxy/server.ts
@@ -23,8 +23,8 @@ import * as cors from "cors";
import { ExpressCorsProxy } from "./ExpressCorsProxy";
export type ServerArgs = {
+ allowedOrigins: string[];
port: number;
- origin: string;
verbose: boolean;
hostsToUseHttp: string[];
};
@@ -32,7 +32,7 @@ export type ServerArgs = {
export const startServer = (args: ServerArgs): void => {
console.log("Starting CORS proxy...");
console.log("====================================================");
- console.log(`Origin: ${args.origin}`);
+ console.log(`Allowed Origins: ${args.allowedOrigins.join(", ")}`);
console.log(`Port: ${args.port}`);
console.log(`Verbose: ${args.verbose}`);
console.log(`Hosts to proxy with HTTP: ${args.hostsToUseHttp}`);
@@ -44,7 +44,15 @@ export const startServer = (args: ServerArgs): void => {
const proxy = new ExpressCorsProxy(args);
- const corsHandler = cors({ origin: args.origin });
+ const corsHandler = cors({
+ origin: (origin, cb) => {
+ if (!origin || !args.allowedOrigins.includes(origin)) {
+ return cb(null, false);
+ }
+
+ return cb(null, origin);
+ },
+ });
app.use(corsHandler);
app.options("/", corsHandler); // enable pre-flight requests
diff --git a/packages/cors-proxy/tests/index.test.ts
b/packages/cors-proxy/tests/index.test.ts
index e1300eaedaa..393a5601236 100644
--- a/packages/cors-proxy/tests/index.test.ts
+++ b/packages/cors-proxy/tests/index.test.ts
@@ -17,6 +17,8 @@
* under the License.
*/
+process.env.CORS_PROXY_ALLOWED_ORIGINS = "http://localhost:9001";
+
import { startServer } from "../src/proxy";
import { run } from "../src";
@@ -28,8 +30,8 @@ jest.mock("../src/proxy", () => ({
function setEnv(env: Record<string, string>) {
process.env = {
- ...env,
...process.env,
+ ...env,
};
}
@@ -39,58 +41,104 @@ describe("index.ts test", () => {
jest.resetAllMocks();
});
- it("Default values", () => {
- run();
-
- expect(startServer).toHaveBeenCalledWith(
- expect.objectContaining({
- port: 8080,
- origin: "*",
- verbose: false,
- })
- );
- });
-
it("Custom port", () => {
setEnv({
CORS_PROXY_HTTP_PORT: "90",
+ CORS_PROXY_ALLOWED_ORIGINS: "http://example.com",
});
run();
expect(startServer).toHaveBeenCalledWith(
expect.objectContaining({
port: 90,
- origin: "*",
+ allowedOrigins: ["http://example.com"],
verbose: false,
})
);
});
- it("Custom origin", () => {
+ it("Verbose mode", () => {
setEnv({
- CORS_PROXY_ORIGIN: "http://localhost",
+ CORS_PROXY_ALLOWED_ORIGINS: "http://example.com",
+ CORS_PROXY_VERBOSE: "true",
});
run();
expect(startServer).toHaveBeenCalledWith(
expect.objectContaining({
port: 8080,
- origin: "http://localhost",
- verbose: false,
+ allowedOrigins: ["http://example.com"],
+ verbose: true,
})
);
});
- it("Verbose", () => {
- setEnv({
- CORS_PROXY_VERBOSE: "true",
+ describe("Allowed origins configuration", () => {
+ it("Single allowed origin", () => {
+ setEnv({
+ CORS_PROXY_ALLOWED_ORIGINS: "http://example.com",
+ });
+
+ run();
+ expect(startServer).toHaveBeenCalledWith(
+ expect.objectContaining({
+ port: 8080,
+ allowedOrigins: ["http://example.com"],
+ verbose: false,
+ })
+ );
+ });
+
+ it("Multiple allowed origins", () => {
+ setEnv({
+ CORS_PROXY_ALLOWED_ORIGINS:
"http://example.com,https://other.example.com,http://localhost:9001",
+ });
+
+ run();
+ expect(startServer).toHaveBeenCalledWith(
+ expect.objectContaining({
+ port: 8080,
+ allowedOrigins: ["http://example.com", "https://other.example.com",
"http://localhost:9001"],
+ verbose: false,
+ })
+ );
+ });
+
+ it("Should throw an error when allowed origins is not set", () => {
+ delete process.env.CORS_PROXY_ALLOWED_ORIGINS;
+
+ expect(() => {
+ run();
+ }).toThrow(new Error("Invalid origin: empty origins are not allowed in
CORS_PROXY_ALLOWED_ORIGINS."));
+ });
+
+ it("Should throw an error when allowed origins is empty", () => {
+ setEnv({
+ CORS_PROXY_ALLOWED_ORIGINS: "",
+ });
+
+ expect(() => {
+ run();
+ }).toThrow(new Error("Invalid origin: empty origins are not allowed in
CORS_PROXY_ALLOWED_ORIGINS."));
+ });
+
+ it("Should throw an error when wildcard '*' is in the list", () => {
+ setEnv({
+ CORS_PROXY_ALLOWED_ORIGINS: "http://example.com,*",
+ });
+
+ expect(() => {
+ run();
+ }).toThrow(new Error('Invalid origin: wildcard "*" is not allowed in
CORS_PROXY_ALLOWED_ORIGINS.'));
+ });
+
+ it("Should throw an error when there are empty origins in the list", () =>
{
+ setEnv({
+ CORS_PROXY_ALLOWED_ORIGINS:
"http://example.com,,https://other.example.com",
+ });
+
+ expect(() => {
+ run();
+ }).toThrow(new Error("Invalid origin: empty origins are not allowed in
CORS_PROXY_ALLOWED_ORIGINS."));
});
- run();
- expect(startServer).toHaveBeenCalledWith(
- expect.objectContaining({
- port: 8080,
- origin: "*",
- verbose: true,
- })
- );
});
});
diff --git a/packages/cors-proxy/tests/server.test.ts
b/packages/cors-proxy/tests/server.test.ts
new file mode 100644
index 00000000000..77b35c3cd9c
--- /dev/null
+++ b/packages/cors-proxy/tests/server.test.ts
@@ -0,0 +1,175 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+const originalCors = jest.requireActual("cors");
+const originalExpress = jest.requireActual("express");
+
+const corsMock = jest.fn((options?: any) => {
+ return originalCors(options);
+});
+
+jest.mock("node-fetch", () => jest.fn());
+jest.mock("cors", () => corsMock);
+jest.mock("express", () => () => {
+ const app = originalExpress();
+ app.listen = jest.fn(() => {});
+ return app;
+});
+
+import { ServerArgs, startServer } from "../src/proxy/server";
+
+describe("CORS handler logic test", () => {
+ beforeEach(() => {
+ jest.clearAllMocks();
+ });
+
+ describe("Single origin in allowedOrigins", () => {
+ it("should allow requests from origin http://localhost:9000", (done) => {
+ const args: ServerArgs = {
+ allowedOrigins: ["http://localhost:9000"],
+ port: 8080,
+ verbose: false,
+ hostsToUseHttp: [],
+ };
+
+ startServer(args);
+
+ const req: any = {
+ headers: {
+ origin: "http://localhost:9000",
+ },
+ method: "GET",
+ };
+
+ const res: any = {
+ statusCode: 200,
+ setHeader: jest.fn(),
+ getHeader: jest.fn(),
+ };
+
+ const next = function () {
+
expect(res.setHeader).toHaveBeenCalledWith("Access-Control-Allow-Origin",
"http://localhost:9000");
+ done();
+ };
+
+ const corsMiddleware = corsMock.mock.results[0].value;
+ corsMiddleware(req, res, next);
+ });
+
+ it("should not allow requests from non-allowed origin", (done) => {
+ const args: ServerArgs = {
+ allowedOrigins: ["http://localhost:9000"],
+ port: 8080,
+ verbose: false,
+ hostsToUseHttp: [],
+ };
+
+ startServer(args);
+
+ const req: any = {
+ headers: {
+ origin: "http://notvalid:8080",
+ },
+ method: "GET",
+ };
+
+ const res: any = {
+ statusCode: 200,
+ setHeader: jest.fn(),
+ getHeader: jest.fn(),
+ };
+
+ const next = function () {
+ expect(res.setHeader).not.toHaveBeenCalled();
+ done();
+ };
+
+ const corsMiddleware = corsMock.mock.results[0].value;
+ corsMiddleware(req, res, next);
+ });
+ });
+
+ describe("Multiple origins in allowedOrigins", () => {
+ it.each(["http://example.com", "http://staging.example.com"])(
+ 'should allow requests from %s allowed origin with allowedOrigins:
["http://example.com", "http://staging.example.com"]',
+ (origin, done) => {
+ const args: ServerArgs = {
+ allowedOrigins: ["http://example.com", "http://staging.example.com"],
+ port: 8080,
+ verbose: false,
+ hostsToUseHttp: [],
+ };
+
+ startServer(args);
+
+ const req: any = {
+ headers: {
+ origin,
+ },
+ method: "GET",
+ };
+
+ const res: any = {
+ statusCode: 200,
+ setHeader: jest.fn(),
+ getHeader: jest.fn(),
+ };
+
+ const next = function () {
+
expect(res.setHeader).toHaveBeenCalledWith("Access-Control-Allow-Origin",
origin);
+ done();
+ };
+
+ const corsMiddleware = corsMock.mock.results[0].value;
+ corsMiddleware(req, res, next);
+ }
+ );
+
+ it("should not allow requests from non-allowed origin", (done) => {
+ const args: ServerArgs = {
+ allowedOrigins: ["http://example.com", "http://staging.example.com"],
+ port: 8080,
+ verbose: false,
+ hostsToUseHttp: [],
+ };
+
+ startServer(args);
+
+ const req: any = {
+ headers: {
+ origin: "http://notvalid:9000",
+ },
+ method: "GET",
+ };
+
+ const res: any = {
+ statusCode: 200,
+ setHeader: jest.fn(),
+ getHeader: jest.fn(),
+ };
+
+ const next = function () {
+ expect(res.setHeader).not.toHaveBeenCalled();
+ done();
+ };
+
+ const corsMiddleware = corsMock.mock.results[0].value;
+ corsMiddleware(req, res, next);
+ });
+ });
+});
diff --git a/packages/online-editor/package.json
b/packages/online-editor/package.json
index 5d81cd629ad..7bdc0d5a7ec 100644
--- a/packages/online-editor/package.json
+++ b/packages/online-editor/package.json
@@ -19,7 +19,7 @@
"build:prod": "pnpm lint && pnpm test && rimraf dist && webpack && pnpm
test-e2e",
"lint": "run-script-if --bool \"$(build-env linters.run)\" --then
\"kie-tools--eslint ./src\"",
"start": "concurrently 'pnpm start:cors-proxy' 'pnpm
start:extended-services' 'pnpm start:kie-sandbox' 'pnpm
start:kie-sandbox-accelerator-quarkus'",
- "start:cors-proxy": "cross-env
CORS_PROXY__useHttpForHosts=\"localhost:$(build-env
kieSandboxAcceleratorQuarkus.dev.port)\" npm --prefix
./node_modules/@kie-tools/cors-proxy run start",
+ "start:cors-proxy": "cross-env
CORS_PROXY__origin=https://localhost:$(build-env onlineEditor.dev.port)
CORS_PROXY__useHttpForHosts=\"localhost:$(build-env
kieSandboxAcceleratorQuarkus.dev.port)\" npm --prefix
./node_modules/@kie-tools/cors-proxy run start",
"start:extended-services": "cross-env
EXTENDED_SERVICES_JAVA__host=\"0.0.0.0\" npm --prefix
./node_modules/@kie-tools/extended-services-java run start",
"start:kie-sandbox": "cross-env EXTENDED_SERVICES_JAVA__host=\"0.0.0.0\"
webpack serve --host 0.0.0.0 --env dev",
"start:kie-sandbox-accelerator-quarkus": "npm --prefix
./node_modules/@kie-tools/kie-sandbox-accelerator-quarkus run start",
diff --git
a/packages/runtime-tools-process-dev-ui-webapp/server/config/index.js
b/packages/runtime-tools-process-dev-ui-webapp/server/config/index.js
index d6ec683bf1a..e9c4db6bd6e 100644
--- a/packages/runtime-tools-process-dev-ui-webapp/server/config/index.js
+++ b/packages/runtime-tools-process-dev-ui-webapp/server/config/index.js
@@ -19,7 +19,7 @@
const commonConfig = {
env: process.env.NODE_ENV || "development",
port: parseInt(process.env.PORT, 10) || 4000,
- corsDomain: process.env.CORS_DOMAIN || "*",
+ corsDomain: process.env.CORS_DOMAIN,
};
module.exports = commonConfig;
diff --git a/packages/runtime-tools-process-dev-ui-webapp/server/server.js
b/packages/runtime-tools-process-dev-ui-webapp/server/server.js
index 8cc617e7799..4f674305510 100644
--- a/packages/runtime-tools-process-dev-ui-webapp/server/server.js
+++ b/packages/runtime-tools-process-dev-ui-webapp/server/server.js
@@ -53,6 +53,15 @@ function listen() {
console.log(`The server is running and listening at
http://localhost:${port}`);
});
}
+
+// validate corsDomain, required for CodeQL scan
+if (!config.corsDomain) {
+ throw new Error("Invalid CORS_DOMAIN: Please specify a domain.");
+}
+if (config.corsDomain.trim() === "*") {
+ throw new Error('Invalid CORS_DOMAIN: wildcard "*" is not allowed.');
+}
+
// parse application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: false }));
diff --git a/packages/serverless-logic-web-tools/package.json
b/packages/serverless-logic-web-tools/package.json
index 7595c6e111b..b5d7d8b5901 100644
--- a/packages/serverless-logic-web-tools/package.json
+++ b/packages/serverless-logic-web-tools/package.json
@@ -21,9 +21,9 @@
"cy:run": "cypress run --headed -b chrome --project e2e-tests --config
baseUrl=$(build-env serverlessLogicWebTools.dev.cypressUrl)",
"lint": "run-script-if --bool \"$(build-env linters.run)\" --then
\"kie-tools--eslint ./src\"",
"postreport": "jrm ./dist-tests-e2e/junit-transformed.xml
\"./dist-tests-e2e/junit-report*.xml\"",
- "start": "concurrently 'pnpm start:dev-webapp' 'pnpm
start:sonataflow-dev-app'",
+ "start": "concurrently --no-colors 'pnpm start:dev-webapp' 'pnpm
start:sonataflow-dev-app'",
"start:dev-webapp": "webpack serve --host 0.0.0.0 --env dev",
- "start:sonataflow-dev-app": "npm --prefix
./node_modules/@kie-tools/sonataflow-dev-app run start",
+ "start:sonataflow-dev-app": "CORS_DOMAIN=https://localhost:$(build-env
serverlessLogicWebTools.dev.port) npm --prefix
./node_modules/@kie-tools/sonataflow-dev-app run start",
"test": "run-script-if --ignore-errors \"$(build-env
tests.ignoreFailures)\" --bool \"$(build-env tests.run)\" --then \"jest
--silent --verbose --passWithNoTests\"",
"test-e2e": "run-script-if --ignore-errors \"$(build-env
endToEndTests.ignoreFailures)\" --bool \"$(build-env endToEndTests.run)\"
--then \"pnpm rimraf ./dist-tests-e2e\" \"pnpm start-server-and-test start
https-get://0.0.0.0:$(build-env serverlessLogicWebTools.dev.port) cy:run\"
\"pnpm postreport\""
},
diff --git a/packages/serverless-workflow-dev-ui-webapp/package.json
b/packages/serverless-workflow-dev-ui-webapp/package.json
index b4df4f85a68..a73031c7b76 100644
--- a/packages/serverless-workflow-dev-ui-webapp/package.json
+++ b/packages/serverless-workflow-dev-ui-webapp/package.json
@@ -22,9 +22,9 @@
"build:dev": "rimraf dist && webpack --env dev",
"build:prod": "pnpm lint && rimraf dist && webpack",
"lint": "run-script-if --bool \"$(build-env linters.run)\" --then
\"kie-tools--eslint ./src\"",
- "start": "concurrently 'pnpm start:dev-webapp' 'pnpm
start:sonataflow-dev-app'",
+ "start": "concurrently --no-colors 'pnpm start:dev-webapp' 'pnpm
start:sonataflow-dev-app'",
"start:dev-webapp": "webpack serve --host 0.0.0.0 --env dev",
- "start:sonataflow-dev-app": "npm --prefix
./node_modules/@kie-tools/sonataflow-dev-app run start",
+ "start:sonataflow-dev-app": "CORS_DOMAIN=http://localhost:$(build-env
runtimeToolsDevUiWebapp.dev.port) npm --prefix
./node_modules/@kie-tools/sonataflow-dev-app run start",
"test": "run-script-if --ignore-errors \"$(build-env
tests.ignoreFailures)\" --bool \"$(build-env tests.run)\" --then \"jest
--silent --verbose --passWithNoTests\""
},
"dependencies": {
diff --git a/packages/sonataflow-deployment-webapp/package.json
b/packages/sonataflow-deployment-webapp/package.json
index 725b064b7a8..8f60b11e782 100644
--- a/packages/sonataflow-deployment-webapp/package.json
+++ b/packages/sonataflow-deployment-webapp/package.json
@@ -18,9 +18,9 @@
"build:dev": "rimraf dist && webpack --env dev",
"build:prod": "pnpm lint && pnpm test && rimraf dist && webpack",
"lint": "run-script-if --bool \"$(build-env linters.run)\" --then
\"kie-tools--eslint ./src\"",
- "start": "concurrently 'pnpm start:dev-webapp' 'pnpm
start:sonataflow-dev-app'",
+ "start": "concurrently --no-colors 'pnpm start:dev-webapp' 'pnpm
start:sonataflow-dev-app'",
"start:dev-webapp": "webpack serve --host 0.0.0.0 --env dev",
- "start:sonataflow-dev-app": "npm --prefix
./node_modules/@kie-tools/sonataflow-dev-app run start",
+ "start:sonataflow-dev-app": "CORS_DOMAIN=http://localhost:$(build-env
sonataFlowDeploymentWebapp.dev.port) npm --prefix
./node_modules/@kie-tools/sonataflow-dev-app run start",
"test": "run-script-if --ignore-errors \"$(build-env
tests.ignoreFailures)\" --bool \"$(build-env tests.run)\" --then \"jest
--silent --verbose --passWithNoTests\""
},
"dependencies": {
diff --git a/packages/sonataflow-dev-app/README.md
b/packages/sonataflow-dev-app/README.md
index f790b0594fe..537d63da162 100644
--- a/packages/sonataflow-dev-app/README.md
+++ b/packages/sonataflow-dev-app/README.md
@@ -27,18 +27,20 @@ The SonataFlow Dev App is intended for development purposes
only. It provides mo
To run the development app, use the following command:
-`pnpm start`
+`CORS_DOMAIN=https://localhost:8080 pnpm start`
# Configuration
The `SonataFlow Dev App` can be configured via environment variables:
-- _SONATAFLOW_DEV_APP_DELAY_: Defines the server's response delay in
milliseconds
+- CORS_DOMAIN: (required) Defines the allowed origin for CORS, '\*' is not
allowed.
+- SONATAFLOW_DEV_APP_DELAY: Defines the server's response delay in
milliseconds.
For example:
```bash
$ export SONATAFLOW_DEV_APP_DELAY=500
+$ export CORS_DOMAIN=https://localhost:8080
```
### GraphQL Modifications
diff --git a/packages/sonataflow-dev-app/src/MockData/graphql.js
b/packages/sonataflow-dev-app/src/MockData/graphql.js
index 42d2b323399..226ae19526a 100644
--- a/packages/sonataflow-dev-app/src/MockData/graphql.js
+++ b/packages/sonataflow-dev-app/src/MockData/graphql.js
@@ -45,7 +45,7 @@ module.exports = {
endpoint: "http://localhost:4000/callback_state_timeouts",
serviceUrl: "http://localhost:4000",
source:
- '{\n "id": "callback_state_timeouts",\n "version": "1.0",\n "name":
"Callback State Timeouts Example",\n "description": "Simple process to show
the callback state timeout working",\n "start": "PrintStartMessage",\n
"events": [\n {\n "name": "callbackEvent",\n "source": "",\n
"type": "callback_event_type"\n }\n ],\n "functions": [\n {\n
"name": "systemOut",\n "type": "custom",\n "operation": "sysout"\n
}\n ],\n "states": [\n { [...]
+ '{\n "id": "callback_state_timeouts",\n "version": "1.0",\n "name":
"Callback State Timeouts Example",\n "description": "Simple process to show
the callback state timeout working",\n "start": "PrintStartMessage",\n
"events": [\n {\n "name": "callbackEvent",\n "source": "",\n
"type": "callback_event_type"\n }\n ],\n "functions": [\n {\n
"name": "systemOut",\n "type": "custom",\n "operation": "sysout"\n
}\n ],\n "states": [\n { [...]
error: null,
childProcessInstances: [],
nodes: [
diff --git a/packages/sonataflow-dev-app/src/config/index.js
b/packages/sonataflow-dev-app/src/config/index.js
index 8fe1dc33c35..29ec5efae46 100644
--- a/packages/sonataflow-dev-app/src/config/index.js
+++ b/packages/sonataflow-dev-app/src/config/index.js
@@ -19,7 +19,7 @@
const commonConfig = {
env: process.env.NODE_ENV || "development",
port: parseInt(process.env.PORT, 10) || 4000,
- corsDomain: process.env.CORS_DOMAIN || "*",
+ corsDomain: process.env.CORS_DOMAIN,
};
module.exports = commonConfig;
diff --git a/packages/sonataflow-dev-app/src/server.js
b/packages/sonataflow-dev-app/src/server.js
index cad9439830e..0690b9cc289 100644
--- a/packages/sonataflow-dev-app/src/server.js
+++ b/packages/sonataflow-dev-app/src/server.js
@@ -60,6 +60,15 @@ function listen() {
console.log(`The server is running and listening at
http://localhost:${port}`);
});
}
+
+// validate corsDomain, required for CodeQL scan
+if (!config.corsDomain) {
+ throw new Error("Invalid CORS_DOMAIN: Please specify a domain.");
+}
+if (config.corsDomain.trim() === "*") {
+ throw new Error('Invalid CORS_DOMAIN: wildcard "*" is not allowed.');
+}
+
// parse application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: false }));
diff --git a/packages/sonataflow-management-console-webapp/package.json
b/packages/sonataflow-management-console-webapp/package.json
index badcd382410..af39575481e 100644
--- a/packages/sonataflow-management-console-webapp/package.json
+++ b/packages/sonataflow-management-console-webapp/package.json
@@ -17,9 +17,9 @@
"build:dev": "rimraf dist && webpack --env dev",
"build:prod": "pnpm lint && pnpm test && rimraf dist && webpack",
"lint": "run-script-if --bool \"$(build-env linters.run)\" --then
\"kie-tools--eslint ./src\"",
- "start": "concurrently 'pnpm start:dev-webapp' 'pnpm
start:sonataflow-dev-app'",
+ "start": "concurrently --no-colors 'pnpm start:dev-webapp' 'pnpm
start:sonataflow-dev-app'",
"start:dev-webapp": "webpack serve --host 0.0.0.0 --env dev",
- "start:sonataflow-dev-app": "npm --prefix
./node_modules/@kie-tools/sonataflow-dev-app run start",
+ "start:sonataflow-dev-app": "CORS_DOMAIN=http://localhost:$(build-env
sonataflowManagementConsoleWebapp.port) npm --prefix
./node_modules/@kie-tools/sonataflow-dev-app run start",
"test": "run-script-if --ignore-errors \"$(build-env
tests.ignoreFailures)\" --bool \"$(build-env tests.run)\" --then \"jest
--silent --verbose --passWithNoTests\""
},
"dependencies": {
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]