From 51dbb8fad40c4321358afeb584e17cec4f91d575 Mon Sep 17 00:00:00 2001 From: Ankush Jain Date: Mon, 5 Aug 2024 02:00:31 -0700 Subject: [PATCH 01/12] CRUD for pre-script --- .../com/akto/action/testing/ScriptAction.java | 73 +++++++++++ apps/dashboard/src/main/resources/struts.xml | 67 ++++++++++ .../src/apps/dashboard/pages/testing/api.js | 21 +++ .../pages/testing/user_config/UserConfig.jsx | 51 +++++++- .../dao/testing/config/TestScriptsDao.java | 21 +++ .../akto/dto/testing/config/TestScript.java | 122 ++++++++++++++++++ 6 files changed, 352 insertions(+), 3 deletions(-) create mode 100644 apps/dashboard/src/main/java/com/akto/action/testing/ScriptAction.java create mode 100644 libs/dao/src/main/java/com/akto/dao/testing/config/TestScriptsDao.java create mode 100644 libs/dao/src/main/java/com/akto/dto/testing/config/TestScript.java diff --git a/apps/dashboard/src/main/java/com/akto/action/testing/ScriptAction.java b/apps/dashboard/src/main/java/com/akto/action/testing/ScriptAction.java new file mode 100644 index 0000000000..dee6cf923f --- /dev/null +++ b/apps/dashboard/src/main/java/com/akto/action/testing/ScriptAction.java @@ -0,0 +1,73 @@ +package com.akto.action.testing; + +import java.util.UUID; + +import org.apache.commons.lang3.NotImplementedException; +import org.bson.conversions.Bson; + +import com.akto.action.UserAction; +import com.akto.dao.context.Context; +import com.akto.dao.testing.config.TestScriptsDao; +import com.akto.dto.testing.config.TestScript; +import com.mongodb.BasicDBObject; +import com.mongodb.client.model.Filters; +import com.mongodb.client.model.Updates; +import com.opensymphony.xwork2.Action; + +public class ScriptAction extends UserAction { + + @Override + public String execute() throws Exception { + throw new NotImplementedException(); + } + + private TestScript testScript; + + public String addScript() { + if (this.testScript == null || this.testScript.getJavascript() == null) { + return Action.ERROR.toUpperCase(); + } + + TestScriptsDao.instance.insertOne( + new TestScript( + UUID.randomUUID().toString(), + this.testScript.getJavascript(), + TestScript.Type.PRE_REQUEST, + getSUser().getLogin(), + Context.now() + ) + ); + + return Action.SUCCESS.toUpperCase(); + } + + public String fetchScript() { + this.testScript = TestScriptsDao.instance.findOne(new BasicDBObject()); + return Action.SUCCESS.toUpperCase(); + } + + public String updateScript() { + + if (this.testScript == null || this.testScript.getJavascript() == null) { + return Action.ERROR.toUpperCase(); + } + + Bson filterQ = Filters.eq("_id", testScript.getId()); + Bson updateQ = + Updates.combine( + Updates.set(TestScript.JAVASCRIPT, this.testScript.getJavascript()), + Updates.set(TestScript.AUTHOR, getSUser().getLogin()), + Updates.set(TestScript.LAST_UPDATED_AT, Context.now()) + ); + TestScriptsDao.instance.updateOne(filterQ, updateQ); + return Action.SUCCESS.toUpperCase(); + } + + public TestScript getTestScript() { + return testScript; + } + + public void setTestScript(TestScript testScript) { + this.testScript = testScript; + } +} diff --git a/apps/dashboard/src/main/resources/struts.xml b/apps/dashboard/src/main/resources/struts.xml index 88e79f7ada..c9839cda83 100644 --- a/apps/dashboard/src/main/resources/struts.xml +++ b/apps/dashboard/src/main/resources/struts.xml @@ -6028,6 +6028,73 @@ + + + + + USER_CONFIG + READ_WRITE + + + + 403 + false + ^actionErrors.* + + + + + 422 + false + ^actionErrors.* + + + + + + + + USER_CONFIG + READ_WRITE + + + + 403 + false + ^actionErrors.* + + + + + 422 + false + ^actionErrors.* + + + + + + + + USER_CONFIG + READ_WRITE + + + + 403 + false + ^actionErrors.* + + + + + 422 + false + ^actionErrors.* + + + + diff --git a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/testing/api.js b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/testing/api.js index f89449581b..8df9de1eb4 100644 --- a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/testing/api.js +++ b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/testing/api.js @@ -406,4 +406,25 @@ export default { data: {reportId, organizationName, reportDate, reportUrl} }) }, + fetchScript() { + return request({ + url: '/api/fetchScript', + method: 'post', + data: {} + }) + }, + addScript({javascript}) { + return request({ + url: '/api/addScript', + method: 'post', + data: {testScript:{javascript}} + }) + }, + updateScript(id) { + return request({ + url: '/api/updateScript', + method: 'post', + data: {testScript:{id, javascript}} + }) + } } \ No newline at end of file diff --git a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/testing/user_config/UserConfig.jsx b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/testing/user_config/UserConfig.jsx index 66c7872da2..72cbe319c5 100644 --- a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/testing/user_config/UserConfig.jsx +++ b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/testing/user_config/UserConfig.jsx @@ -1,4 +1,4 @@ -import { Box, Button, Collapsible, Divider, LegacyCard, LegacyStack, Text } from "@shopify/polaris" +import { TextField, Button, Collapsible, Divider, LegacyCard, LegacyStack, Text } from "@shopify/polaris" import { ChevronRightMinor, ChevronDownMinor } from '@shopify/polaris-icons'; import { useState } from "react"; import api from "../api" @@ -20,9 +20,14 @@ function UserConfig() { const [isLoading, setIsLoading] = useState(true) const [hardcodedOpen, setHardcodedOpen] = useState(true); const [initialLimit, setInitialLimit] = useState(0); + const [preRequestScript, setPreRequestScript] = useState({javascript: ""}); const handleToggleHardcodedOpen = () => setHardcodedOpen((prev) => !prev) + const handlePreRequestScriptChange = (value) => { + setPreRequestScript({...preRequestScript, javascript: value}) + } + async function fetchAuthMechanismData() { setIsLoading(true) const authMechanismDataResponse = await api.fetchAuthMechanismData() @@ -36,6 +41,12 @@ function UserConfig() { await settingRequests.fetchAdminSettings().then((resp)=> { setInitialLimit(resp.accountSettings.globalRateLimit); }) + + await api.fetchScript().then((resp)=> { + if (resp) { + setPreRequestScript(resp.testScript) + } + }); setIsLoading(false) } @@ -43,6 +54,14 @@ function UserConfig() { fetchAuthMechanismData() }, []) + async function addOrUpdateScript() { + if (preRequestScript.id) { + api.updateScript(preRequestScript) + } else { + api.addScript(preRequestScript) + } + } + async function handleStopAllTests() { await api.stopAllTests() setToastConfig({ isActive: true, isError: false, message: "All tests stopped!" }) @@ -121,7 +140,6 @@ function UserConfig() {
- Allowed requests / min: ) - const components = [, rateLimit] + const preRequestScriptComponent = ( + {addOrUpdateScript()} + } + + }> + + +
+ + +
+
+ + +
+ ) + + const components = [, rateLimit, preRequestScriptComponent] return ( isLoading ? diff --git a/libs/dao/src/main/java/com/akto/dao/testing/config/TestScriptsDao.java b/libs/dao/src/main/java/com/akto/dao/testing/config/TestScriptsDao.java new file mode 100644 index 0000000000..00957bc671 --- /dev/null +++ b/libs/dao/src/main/java/com/akto/dao/testing/config/TestScriptsDao.java @@ -0,0 +1,21 @@ +package com.akto.dao.testing.config; + +import com.akto.dao.*; +import com.akto.dto.testing.config.TestScript; + +public class TestScriptsDao extends AccountsContextDao { + + public static final TestScriptsDao instance = new TestScriptsDao(); + + private TestScriptsDao() {} + + @Override + public String getCollName() { + return "test_collection_properties"; + } + + @Override + public Class getClassT() { + return TestScript.class; + } +} diff --git a/libs/dao/src/main/java/com/akto/dto/testing/config/TestScript.java b/libs/dao/src/main/java/com/akto/dto/testing/config/TestScript.java new file mode 100644 index 0000000000..391829043c --- /dev/null +++ b/libs/dao/src/main/java/com/akto/dto/testing/config/TestScript.java @@ -0,0 +1,122 @@ +package com.akto.dto.testing.config; +import java.util.Objects; + +import org.bson.codecs.pojo.annotations.BsonId; + +import com.akto.dao.context.Context; + +public class TestScript { + + + public enum Type { + PRE_TEST, PRE_REQUEST, POST_REQUEST, POST_TEST + } + + public static final String ID = "_id"; + @BsonId + private String id; + + public static final String JAVASCRIPT = "javascript"; + private String javascript; + + private Type type; + + public static final String AUTHOR = "author"; + private String author; + + private int lastCreatedAt; + + public static final String LAST_UPDATED_AT = "lastUpdatedAt"; + private int lastUpdatedAt; + + + public TestScript() { + } + + public TestScript(String id, String javascript, Type type, String author, int lastUpdatedAt) { + this.id = id; + this.javascript = javascript; + this.type = type; + this.author = author; + this.lastCreatedAt = Context.now(); + this.lastUpdatedAt = lastUpdatedAt; + } + + public String getJavascript() { + return this.javascript; + } + + public void setJavascript(String javascript) { + this.javascript = javascript; + } + + public Type getType() { + return this.type; + } + + public void setType(Type type) { + this.type = type; + } + + public String getAuthor() { + return this.author; + } + + public void setAuthor(String author) { + this.author = author; + } + + public int getLastCreatedAt() { + return this.lastCreatedAt; + } + + public void setLastCreatedAt(int lastCreatedAt) { + this.lastCreatedAt = lastCreatedAt; + } + + public int getLastUpdatedAt() { + return this.lastUpdatedAt; + } + + public void setLastUpdatedAt(int lastUpdatedAt) { + this.lastUpdatedAt = lastUpdatedAt; + } + + public String getId() { + return this.id; + } + + public void setId(String id) { + this.id = id; + } + + @Override + public boolean equals(Object o) { + if (o == this) + return true; + if (!(o instanceof TestScript)) { + return false; + } + TestScript testScript = (TestScript) o; + return Objects.equals(javascript, testScript.javascript) && Objects.equals(type, testScript.type) && Objects.equals(author, testScript.author) && lastCreatedAt == testScript.lastCreatedAt && lastUpdatedAt == testScript.lastUpdatedAt; + } + + @Override + public int hashCode() { + return Objects.hash(javascript, type, author, lastCreatedAt, lastUpdatedAt); + } + + @Override + public String toString() { + return "{" + + " id='" + getId() + "'" + + ", javascript='" + getJavascript() + "'" + + ", type='" + getType() + "'" + + ", author='" + getAuthor() + "'" + + ", lastCreatedAt='" + getLastCreatedAt() + "'" + + ", lastUpdatedAt='" + getLastUpdatedAt() + "'" + + "}"; + } + + +} From 073f77c1b955ee96c7485f6ba55f36eb801b0a93 Mon Sep 17 00:00:00 2001 From: ayushaga14 Date: Mon, 5 Aug 2024 17:41:07 +0530 Subject: [PATCH 02/12] add hash calculator --- .../dao/testing/config/TestScriptsDao.java | 5 +++ .../java/com/akto/testing/ApiExecutor.java | 32 +++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/libs/dao/src/main/java/com/akto/dao/testing/config/TestScriptsDao.java b/libs/dao/src/main/java/com/akto/dao/testing/config/TestScriptsDao.java index 00957bc671..103a64a667 100644 --- a/libs/dao/src/main/java/com/akto/dao/testing/config/TestScriptsDao.java +++ b/libs/dao/src/main/java/com/akto/dao/testing/config/TestScriptsDao.java @@ -2,6 +2,7 @@ import com.akto.dao.*; import com.akto.dto.testing.config.TestScript; +import com.mongodb.BasicDBObject; public class TestScriptsDao extends AccountsContextDao { @@ -9,6 +10,10 @@ public class TestScriptsDao extends AccountsContextDao { private TestScriptsDao() {} + public TestScript fetchTestScript() { + return TestScriptsDao.instance.findOne(new BasicDBObject()); + } + @Override public String getCollName() { return "test_collection_properties"; diff --git a/libs/utils/src/main/java/com/akto/testing/ApiExecutor.java b/libs/utils/src/main/java/com/akto/testing/ApiExecutor.java index d5975b3fae..2112478e19 100644 --- a/libs/utils/src/main/java/com/akto/testing/ApiExecutor.java +++ b/libs/utils/src/main/java/com/akto/testing/ApiExecutor.java @@ -1,10 +1,12 @@ package com.akto.testing; import com.akto.dao.context.Context; +import com.akto.dao.testing.config.TestScriptsDao; import com.akto.dto.OriginalHttpRequest; import com.akto.dto.OriginalHttpResponse; import com.akto.dto.testing.TestingRunConfig; import com.akto.dto.testing.TestingRunResult; +import com.akto.dto.testing.config.TestScript; import com.akto.dto.testing.rate_limit.RateLimitHandler; import com.akto.dto.type.URLMethods; import com.akto.log.LoggerMaker; @@ -22,8 +24,15 @@ import java.net.URI; import java.net.URISyntaxException; import java.net.URL; +import java.nio.file.Files; +import java.nio.file.Paths; import java.util.*; +import javax.script.Invocable; +import javax.script.ScriptContext; +import javax.script.ScriptEngine; +import javax.script.ScriptEngineManager; + public class ApiExecutor { private static final LoggerMaker loggerMaker = new LoggerMaker(ApiExecutor.class); @@ -243,6 +252,8 @@ public static OriginalHttpResponse sendRequest(OriginalHttpRequest request, bool builder = builder.url(request.getFullUrlWithParams()); + calculateHash(); + OriginalHttpResponse response = null; switch (method) { case GET: @@ -315,6 +326,27 @@ public void writeTo(BufferedSink sink) throws IOException { } + private static String calculateHash() { + try { + TestScript testScript = TestScriptsDao.instance.fetchTestScript(); + if (testScript == null) { + return null; + } + ScriptEngineManager manager = new ScriptEngineManager(); + ScriptEngine engine = manager.getEngineByName("nashorn"); + + String script = testScript.getJavascript(); + engine.eval(script); + + Invocable invocable = (Invocable) engine; + String hmac = (String) invocable.invokeFunction("calculateHMACSHA256"); + + return hmac; + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } private static OriginalHttpResponse sendWithRequestBody(OriginalHttpRequest request, Request.Builder builder, boolean followRedirects, boolean debug, List testLogs, boolean skipSSRFCheck, String requestProtocol) throws Exception { From 30e45713c1b47484cd940b1e299d8ad5fa41660e Mon Sep 17 00:00:00 2001 From: ayushaga14 Date: Tue, 6 Aug 2024 12:04:51 +0530 Subject: [PATCH 03/12] modify calc hash func --- .../src/main/java/com/akto/testing/ApiExecutor.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/libs/utils/src/main/java/com/akto/testing/ApiExecutor.java b/libs/utils/src/main/java/com/akto/testing/ApiExecutor.java index 2112478e19..0ffb0b00ce 100644 --- a/libs/utils/src/main/java/com/akto/testing/ApiExecutor.java +++ b/libs/utils/src/main/java/com/akto/testing/ApiExecutor.java @@ -252,7 +252,7 @@ public static OriginalHttpResponse sendRequest(OriginalHttpRequest request, bool builder = builder.url(request.getFullUrlWithParams()); - calculateHash(); + calculateHash(request); OriginalHttpResponse response = null; switch (method) { @@ -326,12 +326,15 @@ public void writeTo(BufferedSink sink) throws IOException { } - private static String calculateHash() { + private static String calculateHash(OriginalHttpRequest originalHttpRequest) { try { TestScript testScript = TestScriptsDao.instance.fetchTestScript(); if (testScript == null) { return null; } + String req = originalHttpRequest.getBody(); + String url = originalHttpRequest.getFullUrlWithParams(); + String method = originalHttpRequest.getMethod(); ScriptEngineManager manager = new ScriptEngineManager(); ScriptEngine engine = manager.getEngineByName("nashorn"); @@ -339,7 +342,8 @@ private static String calculateHash() { engine.eval(script); Invocable invocable = (Invocable) engine; - String hmac = (String) invocable.invokeFunction("calculateHMACSHA256"); + // todo: check what all fields should be going from request as message + String hmac = (String) invocable.invokeFunction("calculateHMACSHA256", req + url + method); return hmac; } catch (Exception e) { From 30d5ebd5a64c1a32175f3d702630ad6270273074 Mon Sep 17 00:00:00 2001 From: ayushaga14 Date: Wed, 7 Aug 2024 16:18:59 +0530 Subject: [PATCH 04/12] create message param for hash func --- .../com/akto/dto/OriginalHttpRequest.java | 14 ++ .../java/com/akto/testing/ApiExecutor.java | 125 +++++++++++++++--- 2 files changed, 122 insertions(+), 17 deletions(-) diff --git a/libs/dao/src/main/java/com/akto/dto/OriginalHttpRequest.java b/libs/dao/src/main/java/com/akto/dto/OriginalHttpRequest.java index b9de1c4901..0425dbc6eb 100644 --- a/libs/dao/src/main/java/com/akto/dto/OriginalHttpRequest.java +++ b/libs/dao/src/main/java/com/akto/dto/OriginalHttpRequest.java @@ -4,6 +4,7 @@ import com.akto.util.HttpRequestResponseUtils; import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSONObject; +import com.ctc.wstx.shaded.msv_core.util.Uri; import com.fasterxml.jackson.databind.ObjectMapper; import com.google.gson.Gson; import com.mongodb.BasicDBObject; @@ -223,6 +224,19 @@ public String getFullUrlIncludingDomain() throws Exception { return url; } + public String getUrlPath() throws Exception { + if (!url.startsWith("http")) { + return url; + } else { + try { + URI uri = new URI(url); + return uri.getPath(); + } catch (Exception e) { + return url; + } + } + } + public String getFullUrlWithParams() { return getFullUrlWithParams(this.url, this.queryParams); } diff --git a/libs/utils/src/main/java/com/akto/testing/ApiExecutor.java b/libs/utils/src/main/java/com/akto/testing/ApiExecutor.java index 0ffb0b00ce..e886d417c2 100644 --- a/libs/utils/src/main/java/com/akto/testing/ApiExecutor.java +++ b/libs/utils/src/main/java/com/akto/testing/ApiExecutor.java @@ -8,17 +8,19 @@ import com.akto.dto.testing.TestingRunResult; import com.akto.dto.testing.config.TestScript; import com.akto.dto.testing.rate_limit.RateLimitHandler; +import com.akto.dto.type.RequestTemplate; import com.akto.dto.type.URLMethods; import com.akto.log.LoggerMaker; import com.akto.log.LoggerMaker.LogDb; import com.akto.util.Constants; import com.akto.util.HttpRequestResponseUtils; import com.akto.util.grpc.ProtoBufUtils; +import com.mongodb.BasicDBObject; + import kotlin.Pair; import okhttp3.*; import okio.BufferedSink; import org.apache.commons.lang3.StringUtils; - import java.io.IOException; import java.io.InputStream; import java.net.URI; @@ -38,6 +40,11 @@ public class ApiExecutor { // Load only first 1 MiB of response body into memory. private static final int MAX_RESPONSE_SIZE = 1024*1024; + + private static int lastTestScriptFetched = 0; + private static TestScript testScript = null; + private static ScriptEngineManager manager = new ScriptEngineManager(); + private static ScriptEngine engine = manager.getEngineByName("nashorn"); private static OriginalHttpResponse common(Request request, boolean followRedirects, boolean debug, List testLogs, boolean skipSSRFCheck, String requestProtocol) throws Exception { @@ -252,7 +259,7 @@ public static OriginalHttpResponse sendRequest(OriginalHttpRequest request, bool builder = builder.url(request.getFullUrlWithParams()); - calculateHash(request); + calculateHashAndAddAuth(request); OriginalHttpResponse response = null; switch (method) { @@ -326,32 +333,116 @@ public void writeTo(BufferedSink sink) throws IOException { } - private static String calculateHash(OriginalHttpRequest originalHttpRequest) { + private static void calculateHashAndAddAuth(OriginalHttpRequest originalHttpRequest) { + String script; try { - TestScript testScript = TestScriptsDao.instance.fetchTestScript(); - if (testScript == null) { - return null; + if (Context.now() - lastTestScriptFetched > 5 * 60) { + testScript = TestScriptsDao.instance.fetchTestScript(); + lastTestScriptFetched = Context.now(); + if (testScript != null && testScript.getJavascript() != null) { + script = testScript.getJavascript(); + engine.eval(script); + } } - String req = originalHttpRequest.getBody(); - String url = originalHttpRequest.getFullUrlWithParams(); - String method = originalHttpRequest.getMethod(); - ScriptEngineManager manager = new ScriptEngineManager(); - ScriptEngine engine = manager.getEngineByName("nashorn"); + if (testScript == null || testScript.getJavascript() == null) { + return; + } + String message = originalHttpRequest.getMethod(); + String reqPayload = originalHttpRequest.getBody(); + String urlPath = originalHttpRequest.getPath(); + String queryParamStr = getQueryParam(originalHttpRequest); + String headerStr = getHeaderStr(originalHttpRequest); - String script = testScript.getJavascript(); - engine.eval(script); + message = message + ":" + urlPath + ":" + queryParamStr + ":" + headerStr + ":" + reqPayload; Invocable invocable = (Invocable) engine; - // todo: check what all fields should be going from request as message - String hmac = (String) invocable.invokeFunction("calculateHMACSHA256", req + url + method); + String hmac = (String) invocable.invokeFunction("calculateHMACSHA256", message); - return hmac; + String hmacBase64 = Base64.getEncoder().encodeToString(hmac.getBytes()); + addAuthHeaderWithHash(originalHttpRequest, hmacBase64); } catch (Exception e) { + loggerMaker.errorAndAddToDb("error calculating hash " + e.getMessage() + " payload " + originalHttpRequest.getUrl()); e.printStackTrace(); - return null; + return; + } + } + + private static void addAuthHeaderWithHash(OriginalHttpRequest request, String authHashVal) { + Map> m = request.getHeaders(); + if (m.get("authorization") == null || m.get("authorization").size() == 0) { + return; + } + String existingVal = m.get("authorization").get(0); + if (!existingVal.contains("Signature")) { + return; + } + List val = new ArrayList<>(); + val.add(replaceSignature(existingVal, authHashVal)); + m.put("authorization", val); + loggerMaker.infoAndAddToDb("modified auth header with hash for url " + request.getUrl()); + } + + public static String replaceSignature(String input, String newSignature) { + String signaturePrefix = "Signature="; + int startIndex = input.indexOf(signaturePrefix); + if (startIndex == -1) { + // If the "Signature=" part is not found, return the original string + return input; + } + + int endIndex = input.indexOf(",", startIndex); + if (endIndex == -1) { + // If there is no comma after "Signature=", replace till the end of the string + endIndex = input.length(); + } + + StringBuilder result = new StringBuilder(); + result.append(input.substring(0, startIndex + signaturePrefix.length())); + result.append(newSignature); + result.append(input.substring(endIndex)); + + return result.toString(); + } + + private static String getQueryParam(OriginalHttpRequest originalHttpRequest) { + String url = originalHttpRequest.getFullUrlWithParams(); + BasicDBObject qpObj = RequestTemplate.getQueryJSON(url); + String qp = ""; + TreeMap m = new TreeMap<>(); + for (String key: qpObj.keySet()) { + m.put(key, qpObj.getString(key).trim()); + } + + for (String key: m.keySet()) { + qp = qp + key + "=" + m.get(key) + "&"; + } + if (qp.length() > 0) { + return qp.substring(0, qp.length() - 1); } + return qp; } + private static String getHeaderStr(OriginalHttpRequest request) { + String headerStr = ""; + Map> m = request.getHeaders(); + for (String key: m.keySet()) { + if (!(key.equalsIgnoreCase("channel") || key.equalsIgnoreCase("client_key") || + key.equalsIgnoreCase("idempotent_request_key") || key.equalsIgnoreCase("product") || + key.equalsIgnoreCase("orbipay_payments") || key.equalsIgnoreCase("requestor") || + key.equalsIgnoreCase("requestor_type") || key.equalsIgnoreCase("timestamp"))) { + continue; + } + List val = m.get(key); + if (val == null || val.size() == 0) { + continue; + } + headerStr = headerStr + key + "=" + val.get(0) + "&"; + } + if (headerStr.length() > 0) { + return headerStr.substring(0, headerStr.length() - 1); + } + return headerStr; + } private static OriginalHttpResponse sendWithRequestBody(OriginalHttpRequest request, Request.Builder builder, boolean followRedirects, boolean debug, List testLogs, boolean skipSSRFCheck, String requestProtocol) throws Exception { Map> headers = request.getHeaders(); From 29e2f7f8b0028f8f93a2184d03b2d9482056dc20 Mon Sep 17 00:00:00 2001 From: ayushaga14 Date: Tue, 13 Aug 2024 19:56:56 +0530 Subject: [PATCH 05/12] extract out hash logic out of testing module --- .../src/apps/dashboard/pages/testing/api.js | 2 +- .../pages/testing/user_config/UserConfig.jsx | 2 +- .../java/com/akto/testing/ApiExecutor.java | 121 ++++-------------- 3 files changed, 28 insertions(+), 97 deletions(-) diff --git a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/testing/api.js b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/testing/api.js index 8df9de1eb4..03aeedae79 100644 --- a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/testing/api.js +++ b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/testing/api.js @@ -420,7 +420,7 @@ export default { data: {testScript:{javascript}} }) }, - updateScript(id) { + updateScript(id, javascript) { return request({ url: '/api/updateScript', method: 'post', diff --git a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/testing/user_config/UserConfig.jsx b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/testing/user_config/UserConfig.jsx index 72cbe319c5..e7c30c1e8b 100644 --- a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/testing/user_config/UserConfig.jsx +++ b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/testing/user_config/UserConfig.jsx @@ -56,7 +56,7 @@ function UserConfig() { async function addOrUpdateScript() { if (preRequestScript.id) { - api.updateScript(preRequestScript) + api.updateScript(preRequestScript.id, preRequestScript.javascript) } else { api.addScript(preRequestScript) } diff --git a/libs/utils/src/main/java/com/akto/testing/ApiExecutor.java b/libs/utils/src/main/java/com/akto/testing/ApiExecutor.java index e886d417c2..0900f86de6 100644 --- a/libs/utils/src/main/java/com/akto/testing/ApiExecutor.java +++ b/libs/utils/src/main/java/com/akto/testing/ApiExecutor.java @@ -34,6 +34,7 @@ import javax.script.ScriptContext; import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; +import javax.script.SimpleScriptContext; public class ApiExecutor { private static final LoggerMaker loggerMaker = new LoggerMaker(ApiExecutor.class); @@ -334,116 +335,46 @@ public void writeTo(BufferedSink sink) throws IOException { } private static void calculateHashAndAddAuth(OriginalHttpRequest originalHttpRequest) { - String script; try { + String script; if (Context.now() - lastTestScriptFetched > 5 * 60) { testScript = TestScriptsDao.instance.fetchTestScript(); lastTestScriptFetched = Context.now(); - if (testScript != null && testScript.getJavascript() != null) { - script = testScript.getJavascript(); - engine.eval(script); - } } - if (testScript == null || testScript.getJavascript() == null) { + if (testScript != null && testScript.getJavascript() != null) { + script = testScript.getJavascript(); + } else { + loggerMaker.infoAndAddToDb("returning from calculateHashAndAddAuth, no test script present"); return; } - String message = originalHttpRequest.getMethod(); - String reqPayload = originalHttpRequest.getBody(); - String urlPath = originalHttpRequest.getPath(); - String queryParamStr = getQueryParam(originalHttpRequest); - String headerStr = getHeaderStr(originalHttpRequest); - - message = message + ":" + urlPath + ":" + queryParamStr + ":" + headerStr + ":" + reqPayload; - Invocable invocable = (Invocable) engine; - String hmac = (String) invocable.invokeFunction("calculateHMACSHA256", message); + SimpleScriptContext sctx = ((SimpleScriptContext) engine.get("context")); + sctx.setAttribute("method", originalHttpRequest.getMethod(), ScriptContext.ENGINE_SCOPE); + sctx.setAttribute("headers", originalHttpRequest.getHeaders(), ScriptContext.ENGINE_SCOPE); + sctx.setAttribute("url", originalHttpRequest.getPath(), ScriptContext.ENGINE_SCOPE); + sctx.setAttribute("payload", originalHttpRequest.getBody(), ScriptContext.ENGINE_SCOPE); + sctx.setAttribute("queryParams", originalHttpRequest.getFullUrlWithParams(), ScriptContext.ENGINE_SCOPE); + engine.eval(script); + + String method = (String) sctx.getAttribute("method"); + Map> headers = (Map) sctx.getAttribute("headers"); + String url = (String) sctx.getAttribute("url"); + String payload = (String) sctx.getAttribute("payload"); + String queryParams = (String) sctx.getAttribute("queryParams"); + + originalHttpRequest.setBody(payload); + originalHttpRequest.setMethod(method); + originalHttpRequest.setUrl(url); + originalHttpRequest.setHeaders(headers); + originalHttpRequest.setQueryParams(queryParams); - String hmacBase64 = Base64.getEncoder().encodeToString(hmac.getBytes()); - addAuthHeaderWithHash(originalHttpRequest, hmacBase64); } catch (Exception e) { - loggerMaker.errorAndAddToDb("error calculating hash " + e.getMessage() + " payload " + originalHttpRequest.getUrl()); + loggerMaker.errorAndAddToDb("error in calculateHashAndAddAuth " + e.getMessage() + " url " + originalHttpRequest.getUrl()); e.printStackTrace(); return; } } - private static void addAuthHeaderWithHash(OriginalHttpRequest request, String authHashVal) { - Map> m = request.getHeaders(); - if (m.get("authorization") == null || m.get("authorization").size() == 0) { - return; - } - String existingVal = m.get("authorization").get(0); - if (!existingVal.contains("Signature")) { - return; - } - List val = new ArrayList<>(); - val.add(replaceSignature(existingVal, authHashVal)); - m.put("authorization", val); - loggerMaker.infoAndAddToDb("modified auth header with hash for url " + request.getUrl()); - } - - public static String replaceSignature(String input, String newSignature) { - String signaturePrefix = "Signature="; - int startIndex = input.indexOf(signaturePrefix); - if (startIndex == -1) { - // If the "Signature=" part is not found, return the original string - return input; - } - - int endIndex = input.indexOf(",", startIndex); - if (endIndex == -1) { - // If there is no comma after "Signature=", replace till the end of the string - endIndex = input.length(); - } - - StringBuilder result = new StringBuilder(); - result.append(input.substring(0, startIndex + signaturePrefix.length())); - result.append(newSignature); - result.append(input.substring(endIndex)); - - return result.toString(); - } - - private static String getQueryParam(OriginalHttpRequest originalHttpRequest) { - String url = originalHttpRequest.getFullUrlWithParams(); - BasicDBObject qpObj = RequestTemplate.getQueryJSON(url); - String qp = ""; - TreeMap m = new TreeMap<>(); - for (String key: qpObj.keySet()) { - m.put(key, qpObj.getString(key).trim()); - } - - for (String key: m.keySet()) { - qp = qp + key + "=" + m.get(key) + "&"; - } - if (qp.length() > 0) { - return qp.substring(0, qp.length() - 1); - } - return qp; - } - - private static String getHeaderStr(OriginalHttpRequest request) { - String headerStr = ""; - Map> m = request.getHeaders(); - for (String key: m.keySet()) { - if (!(key.equalsIgnoreCase("channel") || key.equalsIgnoreCase("client_key") || - key.equalsIgnoreCase("idempotent_request_key") || key.equalsIgnoreCase("product") || - key.equalsIgnoreCase("orbipay_payments") || key.equalsIgnoreCase("requestor") || - key.equalsIgnoreCase("requestor_type") || key.equalsIgnoreCase("timestamp"))) { - continue; - } - List val = m.get(key); - if (val == null || val.size() == 0) { - continue; - } - headerStr = headerStr + key + "=" + val.get(0) + "&"; - } - if (headerStr.length() > 0) { - return headerStr.substring(0, headerStr.length() - 1); - } - return headerStr; - } - private static OriginalHttpResponse sendWithRequestBody(OriginalHttpRequest request, Request.Builder builder, boolean followRedirects, boolean debug, List testLogs, boolean skipSSRFCheck, String requestProtocol) throws Exception { Map> headers = request.getHeaders(); if (headers == null) { From 6c679aa1f184e8c09b1a52698a618a04d858a3e1 Mon Sep 17 00:00:00 2001 From: ayushaga14 Date: Wed, 14 Aug 2024 11:30:27 +0530 Subject: [PATCH 06/12] fix --- .../src/main/java/com/akto/testing/ApiExecutor.java | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/libs/utils/src/main/java/com/akto/testing/ApiExecutor.java b/libs/utils/src/main/java/com/akto/testing/ApiExecutor.java index 0900f86de6..fa7ed03a25 100644 --- a/libs/utils/src/main/java/com/akto/testing/ApiExecutor.java +++ b/libs/utils/src/main/java/com/akto/testing/ApiExecutor.java @@ -8,14 +8,12 @@ import com.akto.dto.testing.TestingRunResult; import com.akto.dto.testing.config.TestScript; import com.akto.dto.testing.rate_limit.RateLimitHandler; -import com.akto.dto.type.RequestTemplate; import com.akto.dto.type.URLMethods; import com.akto.log.LoggerMaker; import com.akto.log.LoggerMaker.LogDb; import com.akto.util.Constants; import com.akto.util.HttpRequestResponseUtils; import com.akto.util.grpc.ProtoBufUtils; -import com.mongodb.BasicDBObject; import kotlin.Pair; import okhttp3.*; @@ -26,11 +24,8 @@ import java.net.URI; import java.net.URISyntaxException; import java.net.URL; -import java.nio.file.Files; -import java.nio.file.Paths; import java.util.*; -import javax.script.Invocable; import javax.script.ScriptContext; import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; @@ -44,8 +39,6 @@ public class ApiExecutor { private static int lastTestScriptFetched = 0; private static TestScript testScript = null; - private static ScriptEngineManager manager = new ScriptEngineManager(); - private static ScriptEngine engine = manager.getEngineByName("nashorn"); private static OriginalHttpResponse common(Request request, boolean followRedirects, boolean debug, List testLogs, boolean skipSSRFCheck, String requestProtocol) throws Exception { @@ -348,12 +341,15 @@ private static void calculateHashAndAddAuth(OriginalHttpRequest originalHttpRequ return; } + ScriptEngineManager manager = new ScriptEngineManager(); + ScriptEngine engine = manager.getEngineByName("nashorn"); + SimpleScriptContext sctx = ((SimpleScriptContext) engine.get("context")); sctx.setAttribute("method", originalHttpRequest.getMethod(), ScriptContext.ENGINE_SCOPE); sctx.setAttribute("headers", originalHttpRequest.getHeaders(), ScriptContext.ENGINE_SCOPE); sctx.setAttribute("url", originalHttpRequest.getPath(), ScriptContext.ENGINE_SCOPE); sctx.setAttribute("payload", originalHttpRequest.getBody(), ScriptContext.ENGINE_SCOPE); - sctx.setAttribute("queryParams", originalHttpRequest.getFullUrlWithParams(), ScriptContext.ENGINE_SCOPE); + sctx.setAttribute("queryParams", originalHttpRequest.getQueryParams(), ScriptContext.ENGINE_SCOPE); engine.eval(script); String method = (String) sctx.getAttribute("method"); From 911049a2680b4fa4a5871d3a400f4a2b7231a643 Mon Sep 17 00:00:00 2001 From: ayushaga14 Date: Wed, 14 Aug 2024 14:16:09 +0530 Subject: [PATCH 07/12] add behing stigg --- .../java/com/akto/action/testing/ScriptAction.java | 9 +++++++++ apps/dashboard/src/main/resources/struts.xml | 13 ++++++++++--- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/apps/dashboard/src/main/java/com/akto/action/testing/ScriptAction.java b/apps/dashboard/src/main/java/com/akto/action/testing/ScriptAction.java index dee6cf923f..da9eff7fe9 100644 --- a/apps/dashboard/src/main/java/com/akto/action/testing/ScriptAction.java +++ b/apps/dashboard/src/main/java/com/akto/action/testing/ScriptAction.java @@ -9,6 +9,7 @@ import com.akto.dao.context.Context; import com.akto.dao.testing.config.TestScriptsDao; import com.akto.dto.testing.config.TestScript; +import com.akto.util.DashboardMode; import com.mongodb.BasicDBObject; import com.mongodb.client.model.Filters; import com.mongodb.client.model.Updates; @@ -24,6 +25,10 @@ public String execute() throws Exception { private TestScript testScript; public String addScript() { + + if (!DashboardMode.isSaasDeployment()) { + return Action.ERROR.toUpperCase(); + } if (this.testScript == null || this.testScript.getJavascript() == null) { return Action.ERROR.toUpperCase(); } @@ -48,6 +53,10 @@ public String fetchScript() { public String updateScript() { + if (!DashboardMode.isSaasDeployment()) { + return Action.ERROR.toUpperCase(); + } + if (this.testScript == null || this.testScript.getJavascript() == null) { return Action.ERROR.toUpperCase(); } diff --git a/apps/dashboard/src/main/resources/struts.xml b/apps/dashboard/src/main/resources/struts.xml index c9839cda83..5d35f6fe82 100644 --- a/apps/dashboard/src/main/resources/struts.xml +++ b/apps/dashboard/src/main/resources/struts.xml @@ -6032,9 +6032,12 @@ - USER_CONFIG + USER_ACTIONS READ_WRITE + + TEST_PRE_SCRIPT + 403 @@ -6053,8 +6056,9 @@ + - USER_CONFIG + USER_ACTIONS READ_WRITE @@ -6076,9 +6080,12 @@ - USER_CONFIG + USER_ACTIONS READ_WRITE + + TEST_PRE_SCRIPT + 403 From a94413f86ede63a3f080a340ea6988a1fe7b52d8 Mon Sep 17 00:00:00 2001 From: ayushaga14 Date: Wed, 14 Aug 2024 16:34:33 +0530 Subject: [PATCH 08/12] handle headers type conversion --- .../java/com/akto/testing/ApiExecutor.java | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/libs/utils/src/main/java/com/akto/testing/ApiExecutor.java b/libs/utils/src/main/java/com/akto/testing/ApiExecutor.java index fa7ed03a25..b05f94fea9 100644 --- a/libs/utils/src/main/java/com/akto/testing/ApiExecutor.java +++ b/libs/utils/src/main/java/com/akto/testing/ApiExecutor.java @@ -30,6 +30,7 @@ import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; import javax.script.SimpleScriptContext; +import jdk.nashorn.api.scripting.ScriptObjectMirror; public class ApiExecutor { private static final LoggerMaker loggerMaker = new LoggerMaker(ApiExecutor.class); @@ -353,15 +354,29 @@ private static void calculateHashAndAddAuth(OriginalHttpRequest originalHttpRequ engine.eval(script); String method = (String) sctx.getAttribute("method"); - Map> headers = (Map) sctx.getAttribute("headers"); + Map headers = (Map) sctx.getAttribute("headers"); String url = (String) sctx.getAttribute("url"); String payload = (String) sctx.getAttribute("payload"); String queryParams = (String) sctx.getAttribute("queryParams"); + Map> hs = new HashMap<>(); + for (String key: headers.keySet()) { + try { + ScriptObjectMirror scm = ((ScriptObjectMirror) headers.get(key)); + List val = new ArrayList<>(); + for (int i = 0; i < scm.size(); i++) { + val.add((String) scm.get(Integer.toString(i))); + } + hs.put(key, val); + } catch (Exception e) { + hs.put(key, (List) headers.get(key)); + } + } + originalHttpRequest.setBody(payload); originalHttpRequest.setMethod(method); originalHttpRequest.setUrl(url); - originalHttpRequest.setHeaders(headers); + originalHttpRequest.setHeaders(hs); originalHttpRequest.setQueryParams(queryParams); } catch (Exception e) { From dc571d49e41ada5f8e794bb72a2b2614a1dd0ff4 Mon Sep 17 00:00:00 2001 From: ayushaga14 Date: Wed, 14 Aug 2024 17:03:21 +0530 Subject: [PATCH 09/12] add check for custom auth header --- .../akto/test_editor/auth/AuthValidator.java | 22 +++++++++++-------- .../testing/yaml_tests/YamlTestTemplate.java | 4 ++-- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/apps/testing/src/main/java/com/akto/test_editor/auth/AuthValidator.java b/apps/testing/src/main/java/com/akto/test_editor/auth/AuthValidator.java index 30a9b00586..9f121e03d1 100644 --- a/apps/testing/src/main/java/com/akto/test_editor/auth/AuthValidator.java +++ b/apps/testing/src/main/java/com/akto/test_editor/auth/AuthValidator.java @@ -20,13 +20,13 @@ public class AuthValidator { - public static boolean validate(Auth auth, RawApi rawApi, AuthMechanism authMechanism) { + public static boolean validate(Auth auth, RawApi rawApi, AuthMechanism authMechanism, List customAuthTypes) { if (auth == null) { return true; } - List headerKeys = getHeaders(auth, authMechanism); + List headerKeys = getHeaders(auth, authMechanism, customAuthTypes); auth.setHeaders(headerKeys); @@ -48,7 +48,7 @@ public static boolean validate(Auth auth, RawApi rawApi, AuthMechanism authMecha return true; } - public static List getHeaders(Auth auth, AuthMechanism authMechanism) { + public static List getHeaders(Auth auth, AuthMechanism authMechanism, List customAuthTypes) { if (auth != null && auth.getHeaders() != null && auth.getHeaders().size() > 0) { return auth.getHeaders(); @@ -56,14 +56,18 @@ public static List getHeaders(Auth auth, AuthMechanism authMechanism) { List headerKeys = new ArrayList<>(); - if (authMechanism == null || authMechanism.getAuthParams() == null || authMechanism.getAuthParams().size() == 0) { - return null; + if (authMechanism != null && authMechanism.getAuthParams() != null && authMechanism.getAuthParams().size() > 0) { + for (AuthParam authParam: authMechanism.getAuthParams()) { + String key = authParam.getKey(); + if (key == null) continue; + headerKeys.add(key.toLowerCase()); + } } - for (AuthParam authParam: authMechanism.getAuthParams()) { - String key = authParam.getKey(); - if (key == null) continue; - headerKeys.add(key.toLowerCase()); + if (customAuthTypes != null) { + for(CustomAuthType customAuthType: customAuthTypes) { + headerKeys.addAll(customAuthType.getHeaderKeys()); + } } return headerKeys; diff --git a/apps/testing/src/main/java/com/akto/testing/yaml_tests/YamlTestTemplate.java b/apps/testing/src/main/java/com/akto/testing/yaml_tests/YamlTestTemplate.java index 62f34c1efc..a27d60fd2c 100644 --- a/apps/testing/src/main/java/com/akto/testing/yaml_tests/YamlTestTemplate.java +++ b/apps/testing/src/main/java/com/akto/testing/yaml_tests/YamlTestTemplate.java @@ -92,14 +92,14 @@ public Set requireConfig(){ @Override public ValidationResult filter() { // loggerMaker.infoAndAddToDb("filter started" + logId, LogDb.TESTING); - List authHeaders = AuthValidator.getHeaders(this.auth, this.authMechanism); + List authHeaders = AuthValidator.getHeaders(this.auth, this.authMechanism, this.customAuthTypes); // loggerMaker.infoAndAddToDb("found authHeaders " + authHeaders + " " + logId, LogDb.TESTING); if (authHeaders != null && authHeaders.size() > 0) { this.varMap.put("auth_headers", authHeaders); } if (this.auth != null && this.auth.getAuthenticated() != null) { // loggerMaker.infoAndAddToDb("validating auth, authenticated value is " + this.auth.getAuthenticated() + " " + logId, LogDb.TESTING); - boolean validAuthHeaders = AuthValidator.validate(this.auth, this.rawApi, this.authMechanism); + boolean validAuthHeaders = AuthValidator.validate(this.auth, this.rawApi, this.authMechanism, this.customAuthTypes); if (!validAuthHeaders) { ValidationResult validationResult = new ValidationResult(false, "No valid auth headers"); // loggerMaker.infoAndAddToDb("invalid auth, skipping filter " + logId, LogDb.TESTING); From 9a75a74117ee509c5c021fd2f025c311c755b637 Mon Sep 17 00:00:00 2001 From: ayushaga14 Date: Wed, 14 Aug 2024 17:21:25 +0530 Subject: [PATCH 10/12] fix --- .../main/java/com/akto/test_editor/auth/AuthValidator.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/testing/src/main/java/com/akto/test_editor/auth/AuthValidator.java b/apps/testing/src/main/java/com/akto/test_editor/auth/AuthValidator.java index 9f121e03d1..dd9f260565 100644 --- a/apps/testing/src/main/java/com/akto/test_editor/auth/AuthValidator.java +++ b/apps/testing/src/main/java/com/akto/test_editor/auth/AuthValidator.java @@ -41,11 +41,11 @@ public static boolean validate(Auth auth, RawApi rawApi, AuthMechanism authMecha for (String header: headerKeys) { contains = headers.containsKey(header) || CookieTransformer.isKeyPresentInCookie(cookieList, header); res = auth.getAuthenticated() && contains; - if (!res) { - return res; + if (res) { + return true; } } - return true; + return false; } public static List getHeaders(Auth auth, AuthMechanism authMechanism, List customAuthTypes) { From cc4aab604d8d1dfa6578be9d10d4d286a45837d9 Mon Sep 17 00:00:00 2001 From: ayushaga14 Date: Fri, 23 Aug 2024 12:51:49 +0530 Subject: [PATCH 11/12] trigger script in testing context --- .../akto/action/test_editor/SaveTestEditorAction.java | 4 +++- .../src/main/java/com/akto/testing/ApiExecutor.java | 9 +++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/apps/dashboard/src/main/java/com/akto/action/test_editor/SaveTestEditorAction.java b/apps/dashboard/src/main/java/com/akto/action/test_editor/SaveTestEditorAction.java index aa2292b61b..b45a083aa6 100644 --- a/apps/dashboard/src/main/java/com/akto/action/test_editor/SaveTestEditorAction.java +++ b/apps/dashboard/src/main/java/com/akto/action/test_editor/SaveTestEditorAction.java @@ -29,6 +29,7 @@ import com.akto.dto.testing.GenericTestResult; import com.akto.dto.testing.MultiExecTestResult; import com.akto.dto.testing.TestResult; +import com.akto.dto.testing.TestingRunConfig; import com.akto.dto.testing.TestResult.Confidence; import com.akto.dto.testing.TestingRunResult; import com.akto.dto.testing.WorkflowNodeDetails; @@ -329,7 +330,8 @@ public String runTestForGivenTemplate() { List testLogs = new ArrayList<>(); int lastSampleIndex = sampleDataList.get(0).getSamples().size() - 1; - testingRunResult = executor.runTestNew(infoKey, null, testingUtil, null, testConfig, null, true, testLogs); + TestingRunConfig testingRunConfig = new TestingRunConfig(); + testingRunResult = executor.runTestNew(infoKey, null, testingUtil, null, testConfig, testingRunConfig, true, testLogs); if (testingRunResult == null) { testingRunResult = new TestingRunResult( new ObjectId(), infoKey, testConfig.getInfo().getCategory().getName(), testConfig.getInfo().getSubCategory() ,Collections.singletonList(new TestResult(null, sampleDataList.get(0).getSamples().get(lastSampleIndex), diff --git a/libs/utils/src/main/java/com/akto/testing/ApiExecutor.java b/libs/utils/src/main/java/com/akto/testing/ApiExecutor.java index b05f94fea9..a49958eb13 100644 --- a/libs/utils/src/main/java/com/akto/testing/ApiExecutor.java +++ b/libs/utils/src/main/java/com/akto/testing/ApiExecutor.java @@ -254,7 +254,8 @@ public static OriginalHttpResponse sendRequest(OriginalHttpRequest request, bool builder = builder.url(request.getFullUrlWithParams()); - calculateHashAndAddAuth(request); + boolean executeScript = testingRunConfig != null; + calculateHashAndAddAuth(request, executeScript); OriginalHttpResponse response = null; switch (method) { @@ -328,7 +329,11 @@ public void writeTo(BufferedSink sink) throws IOException { } - private static void calculateHashAndAddAuth(OriginalHttpRequest originalHttpRequest) { + private static void calculateHashAndAddAuth(OriginalHttpRequest originalHttpRequest, boolean executeScript) { + if (!executeScript) { + loggerMaker.infoAndAddToDb("invalid context for hash calculation, returning"); + return; + } try { String script; if (Context.now() - lastTestScriptFetched > 5 * 60) { From d0bca09d96ee328a7753a6fe07f348cdfa546f2c Mon Sep 17 00:00:00 2001 From: ayushaga14 Date: Fri, 23 Aug 2024 14:34:27 +0530 Subject: [PATCH 12/12] maintain map --- .../src/main/java/com/akto/testing/ApiExecutor.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/libs/utils/src/main/java/com/akto/testing/ApiExecutor.java b/libs/utils/src/main/java/com/akto/testing/ApiExecutor.java index a49958eb13..0332db794c 100644 --- a/libs/utils/src/main/java/com/akto/testing/ApiExecutor.java +++ b/libs/utils/src/main/java/com/akto/testing/ApiExecutor.java @@ -37,9 +37,8 @@ public class ApiExecutor { // Load only first 1 MiB of response body into memory. private static final int MAX_RESPONSE_SIZE = 1024*1024; - - private static int lastTestScriptFetched = 0; - private static TestScript testScript = null; + private static Map lastFetchedMap = new HashMap<>(); + private static Map testScriptMap = new HashMap<>(); private static OriginalHttpResponse common(Request request, boolean followRedirects, boolean debug, List testLogs, boolean skipSSRFCheck, String requestProtocol) throws Exception { @@ -334,11 +333,16 @@ private static void calculateHashAndAddAuth(OriginalHttpRequest originalHttpRequ loggerMaker.infoAndAddToDb("invalid context for hash calculation, returning"); return; } + int accountId = Context.accountId.get(); try { String script; + TestScript testScript = testScriptMap.getOrDefault(accountId, null); + int lastTestScriptFetched = lastFetchedMap.getOrDefault(accountId, 0); if (Context.now() - lastTestScriptFetched > 5 * 60) { testScript = TestScriptsDao.instance.fetchTestScript(); lastTestScriptFetched = Context.now(); + testScriptMap.put(accountId, testScript); + lastFetchedMap.put(accountId, Context.now()); } if (testScript != null && testScript.getJavascript() != null) { script = testScript.getJavascript();