Skip to content

Commit e564e30

Browse files
IDDOC-58368 (#9)
* getting ready for 2.0 upgrade testing * updating dependencies * fixing default ops * removing 400 error * package file * undoing previous commit * updating dependencies * making SQL uppercase * removing local dev stuff * updating gitignore file * updating package version * updating to 1.0
1 parent b730567 commit e564e30

File tree

5 files changed

+1035
-549
lines changed

5 files changed

+1035
-549
lines changed

.gitignore

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,4 +101,8 @@ dist
101101
.dynamodb/
102102

103103
# TernJS port file
104-
.tern-port
104+
.tern-port
105+
106+
# Local Development
107+
localDevelopment
108+
docker-compose.yaml

config/permitted-routes.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"GET" : ["*"],
3+
"POST": ["*/filter", "*/count"]
4+
}

index.js

Lines changed: 41 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,8 @@ const bodyParser = require("body-parser");
33
const { createProxyMiddleware } = require("http-proxy-middleware");
44

55
const mysql = require("mysql");
6-
const { Pool, Client } = require("pg");
7-
8-
const { parse } = require("graphql");
6+
const Pool = require("pg-pool");
7+
const fs = require("fs");
98

109
// Create Express Server
1110
const app = express();
@@ -35,6 +34,10 @@ const config = {
3534
ENV: process.env.ENV || "NA",
3635
};
3736

37+
if (fs.existsSync("./config/permitted-routes.json")) {
38+
config.PERMITTED_ROUTES = JSON.parse(fs.readFileSync("./config/permitted-routes.json"));
39+
}
40+
3841
// #endregion
3942

4043
// #region LOGGING
@@ -155,11 +158,11 @@ async function fetchAPIKeysInfo(key) {
155158
if (process.env.DB_TYPE === "mysql") {
156159
params = [key];
157160
query =
158-
"select * from prefect_api_keys where api_key=? and CURDATE() < key_expr_dt";
161+
"SELECT * FROM prefect_api_keys WHERE api_key=? AND CURDATE() < key_expr_dt";
159162
} else {
160163
params = [key];
161164
query =
162-
"select * from prefect_api_keys where api_key=$1 and CURRENT_TIMESTAMP < key_expr_dt";
165+
"SELECT * FROM prefect_api_keys WHERE api_key=$1 AND CURRENT_TIMESTAMP < key_expr_dt";
163166
}
164167

165168
dbConn.query(query, params, (error, results) => {
@@ -177,49 +180,41 @@ async function fetchAPIKeysInfo(key) {
177180
});
178181
}
179182

180-
const isMutationBlocked = (op, acl) => {
181-
// If public access is allowed, no need to check ACL
182-
if (config.ALLOW_PUBLIC_ACCESS) {
183+
const checkRoutes = (url, routes) => {
184+
if (!routes || !routes.length) {
183185
return false;
184186
}
185187

186-
if (op && op.query) {
187-
const parsedQuery = parse(op.query);
188-
const operationType = parsedQuery.definitions[0].operation;
189-
// Operation Names are symbolic and currently Prefect CLI does not
190-
// use them. So use the Selection Fields to determine the operation type
191-
// const operationName = parsedQuery.definitions[0].name
192-
// ? parsedQuery.definitions[0].name.value
193-
// : parsedQuery.definitions[0].selectionSet.selections[0].name.value;
194-
const operationName =
195-
parsedQuery.definitions[0].selectionSet.selections[0].name.value;
196-
197-
if (
198-
acl.ops &&
199-
(acl.ops.includes(`${operationType}/*`) ||
200-
acl.ops.includes(`${operationType}/${operationName}`))
201-
) {
202-
// Do not block
203-
console.log(`ALLOWED ${operationType} Op Name: `, operationName);
204-
if (operationType === "mutation") {
205-
console.warn(
206-
`PREFECT_AUDIT_TRAIL: ${operationType} ${operationName} allowed for ${acl.user_id}`,
207-
op
208-
);
209-
}
210-
return false;
211-
} else {
212-
// Block
213-
console.warn(
214-
`PREFECT_AUDIT_TRAIL: BLOCKED ${operationType} ${operationName} for ${acl.user_id}`,
215-
op
216-
);
188+
regexRoutes = routes.map(route => route.replace(/\*/g, "[^ ]*"));
189+
190+
for (let i = 0; i < regexRoutes.length; i++) {
191+
const match = url.match(regexRoutes[i]);
192+
193+
if (match) {
217194
return true;
218195
}
219-
} else {
196+
}
197+
198+
return false;
199+
};
200+
201+
const allowPassthrough = (url, method, acl) => {
202+
// check config for public access
203+
if (config.ALLOW_PUBLIC_ACCESS) {
204+
return true;
205+
}
206+
207+
// check permitted routes
208+
if (config.PERMITTED_ROUTES && config.PERMITTED_ROUTES[method]?.length && checkRoutes(url, config.PERMITTED_ROUTES[method])) {
220209
return true;
221210
}
222-
return true;
211+
212+
// check acl
213+
if (checkRoutes(url, acl?.ops)) {
214+
return true;
215+
}
216+
217+
return false;
223218
};
224219
// #endregion
225220

@@ -253,16 +248,16 @@ app.use(async (req, res, next) => {
253248
} else {
254249
acl = {
255250
user_id: "Anonymous",
256-
ops: ["mutation/none", "query/*"],
251+
ops: [],
257252
};
258253
}
259254
}
260255
console.log("ACL: ", acl);
261256
req.acl = acl;
262257
}
263258

264-
if (!req.acl && !config.ALLOW_PUBLIC_ACCESS) {
265-
res.status(401).send("Unauthorized");
259+
if (!allowPassthrough(req.url, req.method, req.acl)) {
260+
return res.status(401).send("Unauthorized");
266261
} else {
267262
next();
268263
}
@@ -297,9 +292,6 @@ app.use(
297292
console.log("URL", req.url);
298293
console.log("Headers:", req.headers);
299294
console.log("Body:", req.body);
300-
if (!req.body || !Object.keys(req.body).length) {
301-
return res.status(400).send("Invalid Request");
302-
}
303295

304296
if (
305297
req.url === "/" &&
@@ -331,43 +323,13 @@ app.use(
331323
});
332324
} else {
333325
// Proxy request to end point
334-
const contentType = proxyReq.getHeader("Content-Type");
335326
const writeBody = (bodyData) => {
336327
proxyReq.setHeader("Content-Length", Buffer.byteLength(bodyData));
337328
proxyReq.write(bodyData);
338329
};
339330

340-
if (contentType.includes("application/json")) {
341-
let ops = req.body;
342-
let filteredOps = [];
343-
344-
if (Array.isArray(ops)) {
345-
for (let op of ops) {
346-
if (isMutationBlocked(op, req.acl)) {
347-
// console.log("Mutation filtered");
348-
} else {
349-
filteredOps.push(op);
350-
}
351-
}
352-
if (filteredOps.length > 0) {
353-
writeBody(JSON.stringify(filteredOps));
354-
} else if (filteredOps.length === 1) {
355-
writeBody(JSON.stringify(filteredOps[0]));
356-
} else {
357-
return res.status(401).send("Unauthorized");
358-
}
359-
} else {
360-
let op = ops;
361-
if (isMutationBlocked(op, req.acl)) {
362-
// console.log("Mutation filtered");
363-
return res.status(401).send("Unauthorized");
364-
}
365-
writeBody(JSON.stringify(ops));
366-
}
367-
}
368-
369-
if (contentType === "application/x-www-form-urlencoded") {
370-
writeBody(querystring.stringify(req.body));
331+
if (req.body) {
332+
writeBody(JSON.stringify(req.body));
371333
}
372334
}
373335
},

0 commit comments

Comments
 (0)