From e8d799cb2116a0f41860d361e0a920df6d3dcd24 Mon Sep 17 00:00:00 2001 From: TangoBeeAkto Date: Fri, 11 Oct 2024 13:57:43 +0530 Subject: [PATCH 01/19] feat: created dao and dto for api audit logs --- .../akto/dao/audit_logs/ApiAuditLogsDao.java | 21 +++++ .../com/akto/dto/audit_logs/ApiAuditLogs.java | 81 +++++++++++++++++++ 2 files changed, 102 insertions(+) create mode 100644 libs/dao/src/main/java/com/akto/dao/audit_logs/ApiAuditLogsDao.java create mode 100644 libs/dao/src/main/java/com/akto/dto/audit_logs/ApiAuditLogs.java diff --git a/libs/dao/src/main/java/com/akto/dao/audit_logs/ApiAuditLogsDao.java b/libs/dao/src/main/java/com/akto/dao/audit_logs/ApiAuditLogsDao.java new file mode 100644 index 0000000000..d4d29c828f --- /dev/null +++ b/libs/dao/src/main/java/com/akto/dao/audit_logs/ApiAuditLogsDao.java @@ -0,0 +1,21 @@ +package com.akto.dao.audit_logs; + +import com.akto.dao.AccountsContextDao; +import com.akto.dto.audit_logs.ApiAuditLogs; + +public class ApiAuditLogsDao extends AccountsContextDao { + + public static final ApiAuditLogsDao instance = new ApiAuditLogsDao(); + + private ApiAuditLogsDao() {} + + @Override + public String getCollName() { + return "api_audit_logs"; + } + + @Override + public Class getClassT() { + return ApiAuditLogs.class; + } +} diff --git a/libs/dao/src/main/java/com/akto/dto/audit_logs/ApiAuditLogs.java b/libs/dao/src/main/java/com/akto/dto/audit_logs/ApiAuditLogs.java new file mode 100644 index 0000000000..1f7cdd88a6 --- /dev/null +++ b/libs/dao/src/main/java/com/akto/dto/audit_logs/ApiAuditLogs.java @@ -0,0 +1,81 @@ +package com.akto.dto.audit_logs; + +public class ApiAuditLogs { + + public static final String TIMESTAMP = "timestamp"; + private long timestamp; + + public static final String API_ENDPOINT = "apiEndpoint"; + private String apiEndpoint; + + public static final String ACTION_DESCRIPTION = "actionDescription"; + private String actionDescription; + + public static final String USER_EMAIL = "userEmail"; + private String userEmail; + + public static final String USER_AGENT = "userAgent"; + private String userAgent; + + public static final String USER_IP_ADDRESS = "userIpAddress"; + private String userIpAddress; + + public ApiAuditLogs() {} + + public ApiAuditLogs(long timestamp, String apiEndpoint, String actionDescription, String userEmail, String userAgent, String userIpAddress) { + this.timestamp = timestamp; + this.apiEndpoint = apiEndpoint; + this.actionDescription = actionDescription; + this.userEmail = userEmail; + this.userAgent = userAgent; + this.userIpAddress = userIpAddress; + } + + public long getTimestamp() { + return timestamp; + } + + public void setTimestamp(long timestamp) { + this.timestamp = timestamp; + } + + public String getApiEndpoint() { + return apiEndpoint; + } + + public void setApiEndpoint(String apiEndpoint) { + this.apiEndpoint = apiEndpoint; + } + + public String getActionDescription() { + return actionDescription; + } + + public void setActionDescription(String actionDescription) { + this.actionDescription = actionDescription; + } + + public String getUserEmail() { + return userEmail; + } + + public void setUserEmail(String userEmail) { + this.userEmail = userEmail; + } + + public String getUserAgent() { + return userAgent; + } + + public void setUserAgent(String userAgent) { + this.userAgent = userAgent; + } + + public String getUserIpAddress() { + return userIpAddress; + } + + public void setUserIpAddress(String userIpAddress) { + this.userIpAddress = userIpAddress; + } +} From 5597323c7d57857f2edba07db27a799292896c41 Mon Sep 17 00:00:00 2001 From: TangoBeeAkto Date: Fri, 11 Oct 2024 14:07:32 +0530 Subject: [PATCH 02/19] feat: inserting api audit logs for every write action --- .../interceptor/RoleAccessInterceptor.java | 29 +++++++++++++++ .../akto/audit_logs_util/AuditLogsUtil.java | 35 +++++++++++++++++++ 2 files changed, 64 insertions(+) create mode 100644 libs/utils/src/main/java/com/akto/audit_logs_util/AuditLogsUtil.java diff --git a/apps/dashboard/src/main/java/com/akto/interceptor/RoleAccessInterceptor.java b/apps/dashboard/src/main/java/com/akto/interceptor/RoleAccessInterceptor.java index 40f084c644..b1a13e0cd1 100644 --- a/apps/dashboard/src/main/java/com/akto/interceptor/RoleAccessInterceptor.java +++ b/apps/dashboard/src/main/java/com/akto/interceptor/RoleAccessInterceptor.java @@ -1,8 +1,12 @@ package com.akto.interceptor; +import com.akto.audit_logs_util.AuditLogsUtil; import com.akto.dao.RBACDao; +import com.akto.dao.audit_logs.ApiAuditLogsDao; import com.akto.dao.billing.OrganizationsDao; +import com.akto.dao.context.Context; import com.akto.dto.User; +import com.akto.dto.audit_logs.ApiAuditLogs; import com.akto.dto.billing.FeatureAccess; import com.akto.dto.billing.Organization; import com.akto.dto.RBAC.Role; @@ -17,7 +21,9 @@ import com.opensymphony.xwork2.ActionInvocation; import com.opensymphony.xwork2.ActionSupport; import com.opensymphony.xwork2.interceptor.AbstractInterceptor; +import org.apache.struts2.ServletActionContext; +import javax.servlet.http.HttpServletRequest; import java.util.HashMap; import java.util.Map; @@ -27,6 +33,7 @@ public class RoleAccessInterceptor extends AbstractInterceptor { String featureLabel; String accessType; + String actionDescription; public void setFeatureLabel(String featureLabel) { this.featureLabel = featureLabel; @@ -36,6 +43,10 @@ public void setAccessType(String accessType) { this.accessType = accessType; } + public void setActionDescription(String actionDescription) { + this.actionDescription = actionDescription; + } + public final static String FORBIDDEN = "FORBIDDEN"; private final static String USER = "user"; private final static String FEATURE_LABEL_STRING = "RBAC_FEATURE"; @@ -68,6 +79,7 @@ private int getUserAccountId (Map session) throws Exception{ @Override public String intercept(ActionInvocation invocation) throws Exception { try { + HttpServletRequest request = ServletActionContext.getRequest(); if(featureLabel == null) { throw new Exception("Feature list is null or empty"); @@ -116,6 +128,23 @@ public String intercept(ActionInvocation invocation) throws Exception { ((ActionSupport) invocation.getAction()).addActionError("The role '" + userRole + "' does not have access."); return FORBIDDEN; } + + try { + if (this.accessType.equalsIgnoreCase(ReadWriteAccess.READ_WRITE.toString())) { + long timestamp = Context.now(); + String apiEndpoint = invocation.getProxy().getActionName(); + String actionDescription = this.actionDescription == null ? "Error: Description not available" : this.actionDescription; + String userEmail = user.getLogin(); + String userAgent = request.getHeader("User-Agent") == null ? "Unknown User-Agent" : request.getHeader("User-Agent"); + String userIpAddress = AuditLogsUtil.getClientIpAddress(request); + + ApiAuditLogs apiAuditLogs = new ApiAuditLogs(timestamp, apiEndpoint, actionDescription, userEmail, userAgent, userIpAddress); + ApiAuditLogsDao.instance.insertOne(apiAuditLogs); + } + } catch(Exception e) { + loggerMaker.errorAndAddToDb(e, "Error while inserting api audit logs: " + e.getMessage(), LogDb.DASHBOARD); + } + } catch(Exception e) { String api = invocation.getProxy().getActionName(); String error = "Error in RoleInterceptor for api: " + api + " ERROR: " + e.getMessage(); diff --git a/libs/utils/src/main/java/com/akto/audit_logs_util/AuditLogsUtil.java b/libs/utils/src/main/java/com/akto/audit_logs_util/AuditLogsUtil.java new file mode 100644 index 0000000000..96e96e1c42 --- /dev/null +++ b/libs/utils/src/main/java/com/akto/audit_logs_util/AuditLogsUtil.java @@ -0,0 +1,35 @@ +package com.akto.audit_logs_util; + +import javax.servlet.http.HttpServletRequest; + +public class AuditLogsUtil { + public static String getClientIpAddress(HttpServletRequest request) { + String ip = request.getHeader("X-Forwarded-For"); + + if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) { + ip = request.getHeader("X-Real-IP"); + } + if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) { + ip = request.getHeader("Proxy-Client-IP"); + } + if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) { + ip = request.getHeader("WL-Proxy-Client-IP"); + } + if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) { + ip = request.getHeader("HTTP_CLIENT_IP"); + } + if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) { + ip = request.getHeader("HTTP_X_FORWARDED_FOR"); + } + + if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) { + ip = request.getRemoteAddr(); + } + + if ("[0:0:0:0:0:0:0:1]".equals(ip) || "[::1]".equals(ip)) { + ip = "127.0.0.1"; + } + + return (ip == null || ip.isEmpty()) ? "unknown" : ip; + } +} From b847a3769ab3c634701addebaa6d85b4e01c7279 Mon Sep 17 00:00:00 2001 From: TangoBeeAkto Date: Fri, 11 Oct 2024 17:50:45 +0530 Subject: [PATCH 03/19] feat: created mongodb index for timestamp field --- libs/dao/src/main/java/com/akto/DaoInit.java | 2 ++ .../main/java/com/akto/dao/audit_logs/ApiAuditLogsDao.java | 6 ++++++ 2 files changed, 8 insertions(+) diff --git a/libs/dao/src/main/java/com/akto/DaoInit.java b/libs/dao/src/main/java/com/akto/DaoInit.java index 5997c522a7..e17e862aaf 100644 --- a/libs/dao/src/main/java/com/akto/DaoInit.java +++ b/libs/dao/src/main/java/com/akto/DaoInit.java @@ -1,6 +1,7 @@ package com.akto; import com.akto.dao.*; +import com.akto.dao.audit_logs.ApiAuditLogsDao; import com.akto.dao.billing.OrganizationsDao; import com.akto.dao.loaders.LoadersDao; import com.akto.dao.testing.TestRolesDao; @@ -402,6 +403,7 @@ public static void createIndices() { RBACDao.instance.createIndicesIfAbsent(); TrafficAlertsDao.instance.createIndicesIfAbsent(); RuntimeMetricsDao.instance.createIndicesIfAbsent(); + ApiAuditLogsDao.instance.createIndicesIfAbsent(); } } diff --git a/libs/dao/src/main/java/com/akto/dao/audit_logs/ApiAuditLogsDao.java b/libs/dao/src/main/java/com/akto/dao/audit_logs/ApiAuditLogsDao.java index d4d29c828f..4a88eea9d4 100644 --- a/libs/dao/src/main/java/com/akto/dao/audit_logs/ApiAuditLogsDao.java +++ b/libs/dao/src/main/java/com/akto/dao/audit_logs/ApiAuditLogsDao.java @@ -1,6 +1,7 @@ package com.akto.dao.audit_logs; import com.akto.dao.AccountsContextDao; +import com.akto.dao.MCollection; import com.akto.dto.audit_logs.ApiAuditLogs; public class ApiAuditLogsDao extends AccountsContextDao { @@ -9,6 +10,11 @@ public class ApiAuditLogsDao extends AccountsContextDao { private ApiAuditLogsDao() {} + public void createIndicesIfAbsent() { + String[] fieldNames = { ApiAuditLogs.TIMESTAMP }; + MCollection.createIndexIfAbsent(getDBName(), getCollName(), fieldNames, true); + } + @Override public String getCollName() { return "api_audit_logs"; From cf6355146cde06954a5296f5eceaae10734373a6 Mon Sep 17 00:00:00 2001 From: TangoBeeAkto Date: Fri, 11 Oct 2024 20:14:28 +0530 Subject: [PATCH 04/19] feat: created a new endpoint to fetch api audit logs from db # Conflicts: # apps/dashboard/src/main/resources/struts.xml --- .../com/akto/action/ApiAuditLogsAction.java | 65 +++++++++++++++++++ .../interceptor/RoleAccessInterceptor.java | 6 +- apps/dashboard/src/main/resources/struts.xml | 21 ++++++ .../com/akto/dto/audit_logs/ApiAuditLogs.java | 16 ++++- .../akto/audit_logs_util/AuditLogsUtil.java | 50 +++++++------- 5 files changed, 133 insertions(+), 25 deletions(-) create mode 100644 apps/dashboard/src/main/java/com/akto/action/ApiAuditLogsAction.java diff --git a/apps/dashboard/src/main/java/com/akto/action/ApiAuditLogsAction.java b/apps/dashboard/src/main/java/com/akto/action/ApiAuditLogsAction.java new file mode 100644 index 0000000000..43371a0476 --- /dev/null +++ b/apps/dashboard/src/main/java/com/akto/action/ApiAuditLogsAction.java @@ -0,0 +1,65 @@ +package com.akto.action; + +import com.akto.dao.audit_logs.ApiAuditLogsDao; +import com.akto.dto.audit_logs.ApiAuditLogs; +import com.mongodb.client.model.Filters; +import com.mongodb.client.model.Sorts; +import org.bson.conversions.Bson; + +import java.util.List; + +public class ApiAuditLogsAction extends UserAction { + private int skip; + private int limit; + private int sortOrder; + private int startTimestamp; + private int endTimestamp; + + private List apiAuditLogs; + private long totalAuditLogs; + public String fetchApiAuditLogsFromDb() { + Bson filters = Filters.and( + Filters.gte(ApiAuditLogs.TIMESTAMP, startTimestamp), + Filters.lt(ApiAuditLogs.TIMESTAMP, endTimestamp) + ); + Bson sort = sortOrder == -1 ? Sorts.descending(ApiAuditLogs.TIMESTAMP) : Sorts.ascending(ApiAuditLogs.TIMESTAMP); + + if(limit == -1) { + apiAuditLogs = ApiAuditLogsDao.instance.findAll(filters); + totalAuditLogs = apiAuditLogs.size(); + } else { + apiAuditLogs = ApiAuditLogsDao.instance.findAll(filters, skip, limit, sort); + totalAuditLogs = ApiAuditLogsDao.instance.getMCollection().countDocuments(Filters.empty()); + } + + return SUCCESS.toUpperCase(); + } + + public List getApiAuditLogs() { + return apiAuditLogs; + } + + public long getTotalAuditLogs() { + return totalAuditLogs; + } + + public void setSortOrder(int sortOrder) { + this.sortOrder = sortOrder; + } + + public void setSkip(int skip) { + this.skip = skip; + } + + public void setLimit(int limit) { + this.limit = limit; + } + + public void setStartTimestamp(int startTimestamp) { + this.startTimestamp = startTimestamp; + } + + public void setEndTimestamp(int endTimestamp) { + this.endTimestamp = endTimestamp; + } +} diff --git a/apps/dashboard/src/main/java/com/akto/interceptor/RoleAccessInterceptor.java b/apps/dashboard/src/main/java/com/akto/interceptor/RoleAccessInterceptor.java index b1a13e0cd1..6cb1fd6866 100644 --- a/apps/dashboard/src/main/java/com/akto/interceptor/RoleAccessInterceptor.java +++ b/apps/dashboard/src/main/java/com/akto/interceptor/RoleAccessInterceptor.java @@ -25,6 +25,7 @@ import javax.servlet.http.HttpServletRequest; import java.util.HashMap; +import java.util.List; import java.util.Map; public class RoleAccessInterceptor extends AbstractInterceptor { @@ -136,9 +137,10 @@ public String intercept(ActionInvocation invocation) throws Exception { String actionDescription = this.actionDescription == null ? "Error: Description not available" : this.actionDescription; String userEmail = user.getLogin(); String userAgent = request.getHeader("User-Agent") == null ? "Unknown User-Agent" : request.getHeader("User-Agent"); - String userIpAddress = AuditLogsUtil.getClientIpAddress(request); + List userProxyIpAddresses = AuditLogsUtil.getClientIpAddresses(request); + String userIpAddress = userProxyIpAddresses.get(0); - ApiAuditLogs apiAuditLogs = new ApiAuditLogs(timestamp, apiEndpoint, actionDescription, userEmail, userAgent, userIpAddress); + ApiAuditLogs apiAuditLogs = new ApiAuditLogs(timestamp, apiEndpoint, actionDescription, userEmail, userAgent, userIpAddress, userProxyIpAddresses); ApiAuditLogsDao.instance.insertOne(apiAuditLogs); } } catch(Exception e) { diff --git a/apps/dashboard/src/main/resources/struts.xml b/apps/dashboard/src/main/resources/struts.xml index e3c4fdbfe9..5e9f2c8d1e 100644 --- a/apps/dashboard/src/main/resources/struts.xml +++ b/apps/dashboard/src/main/resources/struts.xml @@ -7013,6 +7013,27 @@ + + + + + LOGS + READ + + + + 403 + false + ^actionErrors.* + apiAuditLogs, totalAuditLogs + + + + + 401 + + + diff --git a/libs/dao/src/main/java/com/akto/dto/audit_logs/ApiAuditLogs.java b/libs/dao/src/main/java/com/akto/dto/audit_logs/ApiAuditLogs.java index 1f7cdd88a6..8b77c2f3a6 100644 --- a/libs/dao/src/main/java/com/akto/dto/audit_logs/ApiAuditLogs.java +++ b/libs/dao/src/main/java/com/akto/dto/audit_logs/ApiAuditLogs.java @@ -1,5 +1,7 @@ package com.akto.dto.audit_logs; +import java.util.List; + public class ApiAuditLogs { public static final String TIMESTAMP = "timestamp"; @@ -20,15 +22,19 @@ public class ApiAuditLogs { public static final String USER_IP_ADDRESS = "userIpAddress"; private String userIpAddress; + public static final String USER_PROXY_IP_ADDRESSES = "userProxyIpAddresses"; + private List userProxyIpAddresses; + public ApiAuditLogs() {} - public ApiAuditLogs(long timestamp, String apiEndpoint, String actionDescription, String userEmail, String userAgent, String userIpAddress) { + public ApiAuditLogs(long timestamp, String apiEndpoint, String actionDescription, String userEmail, String userAgent, String userIpAddress, List userProxyIpAddresses) { this.timestamp = timestamp; this.apiEndpoint = apiEndpoint; this.actionDescription = actionDescription; this.userEmail = userEmail; this.userAgent = userAgent; this.userIpAddress = userIpAddress; + this.userProxyIpAddresses = userProxyIpAddresses; } public long getTimestamp() { @@ -78,4 +84,12 @@ public String getUserIpAddress() { public void setUserIpAddress(String userIpAddress) { this.userIpAddress = userIpAddress; } + + public List getUserProxyIpAddresses() { + return userProxyIpAddresses; + } + + public void setUserProxyIpAddresses(List userProxyIpAddresses) { + this.userProxyIpAddresses = userProxyIpAddresses; + } } diff --git a/libs/utils/src/main/java/com/akto/audit_logs_util/AuditLogsUtil.java b/libs/utils/src/main/java/com/akto/audit_logs_util/AuditLogsUtil.java index 96e96e1c42..7633524ffd 100644 --- a/libs/utils/src/main/java/com/akto/audit_logs_util/AuditLogsUtil.java +++ b/libs/utils/src/main/java/com/akto/audit_logs_util/AuditLogsUtil.java @@ -1,35 +1,41 @@ package com.akto.audit_logs_util; import javax.servlet.http.HttpServletRequest; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; public class AuditLogsUtil { - public static String getClientIpAddress(HttpServletRequest request) { - String ip = request.getHeader("X-Forwarded-For"); + public static List getClientIpAddresses(HttpServletRequest request) { + List headers = Arrays.asList( + "X-Forwarded-For", + "X-Real-IP", + "Proxy-Client-IP", + "WL-Proxy-Client-IP", + "HTTP_CLIENT_IP", + "HTTP_X_FORWARDED_FOR" + ); - if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) { - ip = request.getHeader("X-Real-IP"); - } - if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) { - ip = request.getHeader("Proxy-Client-IP"); - } - if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) { - ip = request.getHeader("WL-Proxy-Client-IP"); - } - if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) { - ip = request.getHeader("HTTP_CLIENT_IP"); - } - if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) { - ip = request.getHeader("HTTP_X_FORWARDED_FOR"); - } + List ipAddresses = new ArrayList<>(); - if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) { - ip = request.getRemoteAddr(); + for (String header : headers) { + String ips = request.getHeader(header); + if (ips != null && !ips.isEmpty() && !"unknown".equalsIgnoreCase(ips)) { + for (String ip : ips.split(",")) { + ipAddresses.add(ip.trim()); + } + break; + } } - if ("[0:0:0:0:0:0:0:1]".equals(ip) || "[::1]".equals(ip)) { - ip = "127.0.0.1"; + if (ipAddresses.isEmpty()) { + String remoteIp = request.getRemoteAddr(); + if (remoteIp != null && !remoteIp.isEmpty()) { + ipAddresses.add(remoteIp); + } } - return (ip == null || ip.isEmpty()) ? "unknown" : ip; + return ipAddresses.isEmpty() ? Collections.singletonList("unknown") : ipAddresses; } } From 79dd7994e256f44bb76e5148d915378f142ede64 Mon Sep 17 00:00:00 2001 From: TangoBeeAkto Date: Fri, 11 Oct 2024 20:15:10 +0530 Subject: [PATCH 05/19] feat: fetching and show api audit logs in the settings --- .../src/apps/dashboard/pages/settings/api.js | 7 + .../pages/settings/audit_logs/AuditLogs.jsx | 165 ++++++++++++++++++ .../pages/settings/nav/SettingsLeftNav.jsx | 9 +- .../web/polaris_web/web/src/apps/main/App.js | 5 + 4 files changed, 185 insertions(+), 1 deletion(-) create mode 100644 apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/settings/audit_logs/AuditLogs.jsx diff --git a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/settings/api.js b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/settings/api.js index 84c8bfbded..21afa316a4 100644 --- a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/settings/api.js +++ b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/settings/api.js @@ -447,6 +447,13 @@ const settingRequests = { accountPermission, modifiedValueForAccount } }) + }, + fetchApiAuditLogsFromDb(skip, limit, sortOrder, startTimestamp, endTimestamp) { + return request({ + url: '/api/fetchApiAuditLogsFromDb', + method: 'post', + data: {skip, limit, sortOrder, startTimestamp, endTimestamp} + }) } } diff --git a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/settings/audit_logs/AuditLogs.jsx b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/settings/audit_logs/AuditLogs.jsx new file mode 100644 index 0000000000..281fb016d0 --- /dev/null +++ b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/settings/audit_logs/AuditLogs.jsx @@ -0,0 +1,165 @@ +import { Button, IndexFiltersMode, Text } from '@shopify/polaris' +import React, { useEffect, useReducer, useState } from 'react' +import settingRequests from '../api' +import func from '@/util/func' +import PageWithMultipleCards from '../../../components/layouts/PageWithMultipleCards' +import TitleWithInfo from '../../../components/shared/TitleWithInfo' +import DateRangeFilter from '../../../components/layouts/DateRangeFilter' +import { produce } from 'immer' +import values from "@/util/values"; +import GithubSimpleTable from '../../../components/tables/GithubSimpleTable' +import { CellType } from '../../../components/tables/rows/GithubRow' + +const headers = [ + { + title: "User email", + text: "User email", + value: "userEmail", + filterKey: "userEmail", + showFilter: true + }, + { + title: "API endpoint", + text: "API endpoint", + value: "apiEndpoint", + filterKey: "apiEndpoint", + showFilter: true + }, + { + title: "Action description", + text: "Action description", + value: "actionDescription" + }, + { + title: "Timestamp", + text: "Timestamp", + value: "timestamp", + sortActive: true, + }, + { + title: "User IP address", + text: "User IP address", + value: "userIpAddress", + filterKey: "userIpAddress", + showFilter: true + }, + { + title: "User agent", + text: "User agent", + value: "userAgent", + filterKey: "rawUserAgent", + isText: CellType.TEXT, + }, +] + +const sortOptions = [ + { label: 'Timestamp', value: 'timestamp asc', directionLabel: 'Newest', sortKey: 'rawTimestamp', columnIndex: 4 }, + { label: 'Timestamp', value: 'timestamp desc', directionLabel: 'Oldest', sortKey: 'rawTimestamp', columnIndex: 4 }, +] + +const resourceName = { + singular: 'audit log', + plural: 'audit logs', +} + +const AuditLogs = () => { + const [key, setKey] = useState(false) + const [loading, setLoading] = useState(false) + const [tableLoading, setTableLoading] = useState(false) + const [auditLogsData, setAuditLogsData] = useState([]) + + const [currDateRange, dispatchCurrDateRange] = useReducer(produce((draft, action) => func.dateRangeReducer(draft, action)), values.ranges[2]) + const getTimeEpoch = (key) => { + return Math.floor(Date.parse(currDateRange.period[key]) / 1000) + } + const startTimestamp = getTimeEpoch("since") + const endTimestamp = getTimeEpoch("until") + + const fetchData = async () => { + setLoading(true) + setTableLoading(true) + await settingRequests.fetchApiAuditLogsFromDb(0, -1, 1, startTimestamp, endTimestamp).then((resp) => { + const apiAuditLogsArr = resp?.apiAuditLogs.map((item) => { + const { timestamp, userAgent } = item + return { + ...item, + timestamp: func.prettifyEpoch(timestamp), + rawTimestamp: timestamp, + userAgent: {userAgent}, + rawUserAgent: userAgent + } + }) + + setAuditLogsData(apiAuditLogsArr) + }) + + setLoading(false) + setTableLoading(false) + } + + useEffect(() => { + fetchData() + }, [startTimestamp, endTimestamp]) + + const exportAuditLogsCSV = async () => { + setLoading(true) + if(auditLogsData == null || auditLogsData.length === 0) { + func.setToast(true, true, "Can not export empty CSV") + return + } + const csvHeaders = Object.keys(auditLogsData[0]).join(',') + '\n' + const csvRows = auditLogsData.map(row => { + return Object.values(row).join(',') + }).join('\n') + + const csvString = csvHeaders + csvRows + let blob = new Blob([csvString], { + type: "application/csvcharset=UTF-8" + }); + saveAs(blob, "akto_audit_logs.csv") ; + func.setToast(true, false,"CSV exported successfully") + setLoading(false) + } + + function disambiguateLabel(key, value) { + return func.convertToDisambiguateLabelObj(value, null, 2) + } + + const auditLogsTable = ( + {}} + showFooter={false} + loading={tableLoading} + /> + ) + + return ( + + } + primaryAction={} + secondaryActions={ dispatchCurrDateRange({ type: "update", period: dateObj.period, title: dateObj.title, alias: dateObj.alias })} />} + isFirstPage={true} + components={[auditLogsTable]} + /> + ) +} + +export default AuditLogs \ No newline at end of file diff --git a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/settings/nav/SettingsLeftNav.jsx b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/settings/nav/SettingsLeftNav.jsx index edcb24f082..32f95cab23 100644 --- a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/settings/nav/SettingsLeftNav.jsx +++ b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/settings/nav/SettingsLeftNav.jsx @@ -1,5 +1,5 @@ import { Navigation } from "@shopify/polaris" -import { StoreDetailsFilledMinor, IdentityCardFilledMajor, AutomationFilledMajor, AppsFilledMajor} from "@shopify/polaris-icons" +import { StoreDetailsFilledMinor, IdentityCardFilledMajor, AutomationFilledMajor, AppsFilledMajor, ComposeMajor} from "@shopify/polaris-icons" import { ListFilledMajor, ReportFilledMinor, LockFilledMajor, CollectionsFilledMajor, PlanMajor, ChatMajor} from "@shopify/polaris-icons" import { VariantMajor, VocabularyMajor, AdjustMinor } from "@shopify/polaris-icons" import { useLocation, useNavigate } from "react-router-dom" @@ -37,6 +37,12 @@ const SettingsLeftNav = () => { selected: page === "self-hosted", onClick: () => navigate("/dashboard/settings/self-hosted") }] : [] + const auditLogsArr = ((window.IS_SAAS === 'true' || window.DASHBOARD_MODE === 'ON_PREM') && window.USER_ROLE === 'ADMIN') ? [{ + label: 'Audit logs', + icon: ComposeMajor, + selected: page === 'audit-logs', + onClick: () => navigate("/dashboard/settings/audit-logs") + }] : [] const billingArr = window.IS_SAAS === 'true' || window.DASHBOARD_MODE === 'ON_PREM' ? [{ label: 'Billing', @@ -111,6 +117,7 @@ const SettingsLeftNav = () => { }, ...billingArr, ...selfHostedArr, + ...auditLogsArr, { label: 'Help & Support', icon: ChatMajor, diff --git a/apps/dashboard/web/polaris_web/web/src/apps/main/App.js b/apps/dashboard/web/polaris_web/web/src/apps/main/App.js index e413ea1552..7f746d0ade 100644 --- a/apps/dashboard/web/polaris_web/web/src/apps/main/App.js +++ b/apps/dashboard/web/polaris_web/web/src/apps/main/App.js @@ -77,6 +77,7 @@ import SignUpWithSSO from "../signup/components/SignUpWithSSO"; import TeamsWebhooks from "../dashboard/pages/settings/integrations/teamsWebhooks/TeamsWebhooks"; import TeamsWebhook from "../dashboard/pages/settings/integrations/teamsWebhooks/TeamsWebhook"; +import AuditLogs from "../dashboard/pages/settings/audit_logs/AuditLogs"; // if you add a component in a new path, please verify the search implementation in function -> 'getSearchItemsArr' in func.js @@ -317,6 +318,10 @@ const router = createBrowserRouter([ { path: "self-hosted", element: + }, + { + path: 'audit-logs', + element: } ] }, From d18fac905bc61dcb07688058365b1b251e9e1230 Mon Sep 17 00:00:00 2001 From: TangoBeeAkto Date: Fri, 11 Oct 2024 23:07:10 +0530 Subject: [PATCH 06/19] feat: handling non-admin user behaviour for audit logs --- .../java/com/akto/action/ApiAuditLogsAction.java | 13 +++++++++++++ apps/dashboard/src/main/resources/struts.xml | 9 +++++---- .../components/layouts/DateRangeFilter.jsx | 1 + .../pages/settings/audit_logs/AuditLogs.jsx | 8 +++++--- 4 files changed, 24 insertions(+), 7 deletions(-) diff --git a/apps/dashboard/src/main/java/com/akto/action/ApiAuditLogsAction.java b/apps/dashboard/src/main/java/com/akto/action/ApiAuditLogsAction.java index 43371a0476..91b5227dc0 100644 --- a/apps/dashboard/src/main/java/com/akto/action/ApiAuditLogsAction.java +++ b/apps/dashboard/src/main/java/com/akto/action/ApiAuditLogsAction.java @@ -1,6 +1,10 @@ package com.akto.action; +import com.akto.dao.RBACDao; import com.akto.dao.audit_logs.ApiAuditLogsDao; +import com.akto.dao.context.Context; +import com.akto.dto.RBAC; +import com.akto.dto.User; import com.akto.dto.audit_logs.ApiAuditLogs; import com.mongodb.client.model.Filters; import com.mongodb.client.model.Sorts; @@ -18,6 +22,15 @@ public class ApiAuditLogsAction extends UserAction { private List apiAuditLogs; private long totalAuditLogs; public String fetchApiAuditLogsFromDb() { + User user = getSUser(); + if(user == null) return ERROR.toUpperCase(); + + RBAC.Role currentRoleForUser = RBACDao.getCurrentRoleForUser(user.getId(), Context.accountId.get()); + if(currentRoleForUser == null || !currentRoleForUser.equals(RBAC.Role.ADMIN)) { + addActionError("You do not have access to the audit logs."); + return ERROR.toUpperCase(); + } + Bson filters = Filters.and( Filters.gte(ApiAuditLogs.TIMESTAMP, startTimestamp), Filters.lt(ApiAuditLogs.TIMESTAMP, endTimestamp) diff --git a/apps/dashboard/src/main/resources/struts.xml b/apps/dashboard/src/main/resources/struts.xml index 5e9f2c8d1e..893daecaa0 100644 --- a/apps/dashboard/src/main/resources/struts.xml +++ b/apps/dashboard/src/main/resources/struts.xml @@ -7017,7 +7017,7 @@ - LOGS + ADMIN_ACTIONS READ @@ -7025,12 +7025,13 @@ 403 false ^actionErrors.* - apiAuditLogs, totalAuditLogs - - 401 + + 422 + false + ^actionErrors.* diff --git a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/components/layouts/DateRangeFilter.jsx b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/components/layouts/DateRangeFilter.jsx index 8c10fd366a..c2e72b56ff 100644 --- a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/components/layouts/DateRangeFilter.jsx +++ b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/components/layouts/DateRangeFilter.jsx @@ -25,6 +25,7 @@ function DateRangeFilter(props){ fullHeight activator={ } - secondaryActions={ dispatchCurrDateRange({ type: "update", period: dateObj.period, title: dateObj.title, alias: dateObj.alias })} />} + secondaryActions={ dispatchCurrDateRange({ type: "update", period: dateObj.period, title: dateObj.title, alias: dateObj.alias })} />} isFirstPage={true} components={[auditLogsTable]} /> From f3e9fbf1a061335f96f4a4f7e7910f7c9314d808 Mon Sep 17 00:00:00 2001 From: TangoBeeAkto Date: Sat, 12 Oct 2024 00:14:48 +0530 Subject: [PATCH 07/19] feat: cleaning the UI --- .../apps/dashboard/pages/settings/audit_logs/AuditLogs.jsx | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/settings/audit_logs/AuditLogs.jsx b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/settings/audit_logs/AuditLogs.jsx index 37ffb50af4..71e31e4098 100644 --- a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/settings/audit_logs/AuditLogs.jsx +++ b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/settings/audit_logs/AuditLogs.jsx @@ -1,4 +1,4 @@ -import { Button, IndexFiltersMode, Text } from '@shopify/polaris' +import { Box, Button, IndexFiltersMode, Text } from '@shopify/polaris' import React, { useEffect, useReducer, useState } from 'react' import settingRequests from '../api' import func from '@/util/func' @@ -80,12 +80,13 @@ const AuditLogs = () => { setTableLoading(true) await settingRequests.fetchApiAuditLogsFromDb(0, -1, 1, startTimestamp, endTimestamp).then((resp) => { const apiAuditLogsArr = resp?.apiAuditLogs.map((item) => { - const { timestamp, userAgent } = item + const { actionDescription, timestamp, userAgent } = item return { ...item, + actionDescription: {actionDescription}, timestamp: func.prettifyEpoch(timestamp), rawTimestamp: timestamp, - userAgent: {userAgent}, + userAgent: {userAgent}, rawUserAgent: userAgent } }) From 11e50cc578be612ec38b1a2caee4d55d2873f3ae Mon Sep 17 00:00:00 2001 From: TangoBeeAkto Date: Sat, 12 Oct 2024 11:28:26 +0530 Subject: [PATCH 08/19] feat: changing audit logs table column names --- .../pages/settings/audit_logs/AuditLogs.jsx | 21 ++++++++++--------- .../web/polaris_web/web/src/util/func.js | 11 ++++++++++ 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/settings/audit_logs/AuditLogs.jsx b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/settings/audit_logs/AuditLogs.jsx index 71e31e4098..879c99a126 100644 --- a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/settings/audit_logs/AuditLogs.jsx +++ b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/settings/audit_logs/AuditLogs.jsx @@ -19,20 +19,20 @@ const headers = [ showFilter: true }, { - title: "API endpoint", - text: "API endpoint", + title: "Operation", + text: "Operation", value: "apiEndpoint", filterKey: "apiEndpoint", showFilter: true }, { - title: "Action description", - text: "Action description", + title: "Operation description", + text: "Operation description", value: "actionDescription" }, { - title: "Timestamp", - text: "Timestamp", + title: "Time", + text: "Time", value: "timestamp", sortActive: true, }, @@ -80,13 +80,14 @@ const AuditLogs = () => { setTableLoading(true) await settingRequests.fetchApiAuditLogsFromDb(0, -1, 1, startTimestamp, endTimestamp).then((resp) => { const apiAuditLogsArr = resp?.apiAuditLogs.map((item) => { - const { actionDescription, timestamp, userAgent } = item + const { apiEndpoint, actionDescription, timestamp, userAgent } = item return { ...item, - actionDescription: {actionDescription}, + apiEndpoint: func.formatEndpoint(apiEndpoint), + actionDescription:

{actionDescription}

, timestamp: func.prettifyEpoch(timestamp), rawTimestamp: timestamp, - userAgent: {userAgent}, + userAgent:

{userAgent}

, rawUserAgent: userAgent } }) @@ -157,7 +158,7 @@ const AuditLogs = () => { titleText={"Audit logs"} /> } - primaryAction={} + primaryAction={} secondaryActions={ dispatchCurrDateRange({ type: "update", period: dateObj.period, title: dateObj.title, alias: dateObj.alias })} />} isFirstPage={true} components={[auditLogsTable]} diff --git a/apps/dashboard/web/polaris_web/web/src/util/func.js b/apps/dashboard/web/polaris_web/web/src/util/func.js index c7f01b9750..8f3daa2e1e 100644 --- a/apps/dashboard/web/polaris_web/web/src/util/func.js +++ b/apps/dashboard/web/polaris_web/web/src/util/func.js @@ -1647,6 +1647,17 @@ showConfirmationModal(modalContent, primaryActionContent, primaryAction) { if(iconsUsedMap[iconString] !== undefined){ return iconsUsedMap[iconString] } return null + }, + formatEndpoint(endpoint) { + const trimmedEndpoint = endpoint.replace(/^api\//, '') + const spacedEndpoint = trimmedEndpoint.replace(/([a-z])([A-Z])/g, '$1 $2') + const finalEndpoint = spacedEndpoint.replace(/[_-]/g, ' ') + const capitalizedEndpoint = finalEndpoint + .split(' ') + .map(word => word.charAt(0).toUpperCase() + word.slice(1)) + .join(' ') + + return capitalizedEndpoint } } From 674972fbccb33eb277bf6e1c451927ffa4768066 Mon Sep 17 00:00:00 2001 From: TangoBeeAkto Date: Sat, 12 Oct 2024 16:07:49 +0530 Subject: [PATCH 09/19] feat: changing accessType of READ_WRITE endpoints to READ only --- .../interceptor/RoleAccessInterceptor.java | 13 +++- apps/dashboard/src/main/resources/struts.xml | 73 ++++++++++--------- 2 files changed, 48 insertions(+), 38 deletions(-) diff --git a/apps/dashboard/src/main/java/com/akto/interceptor/RoleAccessInterceptor.java b/apps/dashboard/src/main/java/com/akto/interceptor/RoleAccessInterceptor.java index 6cb1fd6866..9960140dee 100644 --- a/apps/dashboard/src/main/java/com/akto/interceptor/RoleAccessInterceptor.java +++ b/apps/dashboard/src/main/java/com/akto/interceptor/RoleAccessInterceptor.java @@ -18,6 +18,7 @@ import com.akto.log.LoggerMaker.LogDb; import com.akto.util.DashboardMode; import com.mongodb.client.model.Filters; +import com.opensymphony.xwork2.Action; import com.opensymphony.xwork2.ActionInvocation; import com.opensymphony.xwork2.ActionSupport; import com.opensymphony.xwork2.interceptor.AbstractInterceptor; @@ -79,6 +80,7 @@ private int getUserAccountId (Map session) throws Exception{ @Override public String intercept(ActionInvocation invocation) throws Exception { + ApiAuditLogs apiAuditLogs = null; try { HttpServletRequest request = ServletActionContext.getRequest(); @@ -140,8 +142,7 @@ public String intercept(ActionInvocation invocation) throws Exception { List userProxyIpAddresses = AuditLogsUtil.getClientIpAddresses(request); String userIpAddress = userProxyIpAddresses.get(0); - ApiAuditLogs apiAuditLogs = new ApiAuditLogs(timestamp, apiEndpoint, actionDescription, userEmail, userAgent, userIpAddress, userProxyIpAddresses); - ApiAuditLogsDao.instance.insertOne(apiAuditLogs); + apiAuditLogs = new ApiAuditLogs(timestamp, apiEndpoint, actionDescription, userEmail, userAgent, userIpAddress, userProxyIpAddresses); } } catch(Exception e) { loggerMaker.errorAndAddToDb(e, "Error while inserting api audit logs: " + e.getMessage(), LogDb.DASHBOARD); @@ -153,6 +154,12 @@ public String intercept(ActionInvocation invocation) throws Exception { loggerMaker.errorAndAddToDb(e, error, LoggerMaker.LogDb.DASHBOARD); } - return invocation.invoke(); + String result = invocation.invoke(); + + if (apiAuditLogs != null && result.equalsIgnoreCase(Action.SUCCESS.toUpperCase())) { + ApiAuditLogsDao.instance.insertOne(apiAuditLogs); + } + + return result; } } diff --git a/apps/dashboard/src/main/resources/struts.xml b/apps/dashboard/src/main/resources/struts.xml index 893daecaa0..b9b4770575 100644 --- a/apps/dashboard/src/main/resources/struts.xml +++ b/apps/dashboard/src/main/resources/struts.xml @@ -209,7 +209,7 @@ INTEGRATIONS - READ_WRITE + READ 403 @@ -228,7 +228,7 @@ INTEGRATIONS - READ_WRITE + READ 403 @@ -246,7 +246,7 @@ INTEGRATIONS - READ_WRITE + READ 403 @@ -264,7 +264,7 @@ INTEGRATIONS - READ_WRITE + READ 403 @@ -340,7 +340,7 @@ USER_ACTIONS - READ_WRITE + READ 403 @@ -484,7 +484,7 @@ ADMIN_ACTIONS - READ_WRITE + READ @@ -563,7 +563,7 @@ ADMIN_ACTIONS - READ_WRITE + READ @@ -642,7 +642,7 @@ ADMIN_ACTIONS - READ_WRITE + READ @@ -663,7 +663,7 @@ ADMIN_ACTIONS - READ_WRITE + READ @@ -1411,7 +1411,7 @@ INTEGRATIONS - READ_WRITE + READ @@ -2037,7 +2037,7 @@ INTEGRATIONS - READ_WRITE + READ 403 @@ -2056,7 +2056,7 @@ INTEGRATIONS - READ_WRITE + READ 403 @@ -2621,7 +2621,7 @@ SENSITIVE_DATA - READ_WRITE + READ 403 @@ -3517,7 +3517,7 @@ LOGS - READ_WRITE + READ @@ -3537,7 +3537,7 @@ LOGS - READ_WRITE + READ @@ -3577,7 +3577,7 @@ ISSUES - READ_WRITE + READ @@ -4082,7 +4082,7 @@ ADMIN_ACTIONS - READ_WRITE + READ @@ -4103,7 +4103,7 @@ ADMIN_ACTIONS - READ_WRITE + READ @@ -4601,7 +4601,7 @@ INTEGRATIONS - READ_WRITE + READ @@ -4675,7 +4675,7 @@ INTEGRATIONS - READ_WRITE + READ @@ -4769,7 +4769,7 @@ ADMIN_ACTIONS - READ_WRITE + READ @@ -4813,7 +4813,7 @@ INTEGRATIONS - READ_WRITE + READ @@ -4834,7 +4834,7 @@ INTEGRATIONS - READ_WRITE + READ @@ -4855,7 +4855,7 @@ INTEGRATIONS - READ_WRITE + READ @@ -4897,7 +4897,7 @@ USER_CONFIG - READ_WRITE + READ @@ -4940,7 +4940,7 @@ INTEGRATIONS - READ_WRITE + READ @@ -5188,7 +5188,7 @@ METRICS - READ_WRITE + READ @@ -5231,7 +5231,7 @@ METRICS - READ_WRITE + READ @@ -5312,7 +5312,7 @@ INTEGRATIONS - READ_WRITE + READ @@ -5370,7 +5370,7 @@ INTEGRATIONS - READ_WRITE + READ @@ -5815,7 +5815,7 @@ INTEGRATIONS - READ_WRITE + READ @@ -6086,7 +6086,7 @@ BILLING - READ_WRITE + READ @@ -6130,7 +6130,7 @@ BILLING - READ_WRITE + READ @@ -6520,7 +6520,7 @@ USER_ACTIONS - READ_WRITE + READ @@ -6912,7 +6912,7 @@ ADMIN_ACTIONS - READ_WRITE + READ 403 @@ -7020,6 +7020,9 @@ ADMIN_ACTIONS READ + + API_AUDIT_LOGS + 403 From 5c9fa4d26bc8cf59729026df2419c4a722b13a25 Mon Sep 17 00:00:00 2001 From: fenil Date: Mon, 14 Oct 2024 19:32:56 +0530 Subject: [PATCH 10/19] Added description to logs --- apps/dashboard/src/main/resources/struts.xml | 157 +++++++++++++++++++ 1 file changed, 157 insertions(+) diff --git a/apps/dashboard/src/main/resources/struts.xml b/apps/dashboard/src/main/resources/struts.xml index b9b4770575..8740e9acec 100644 --- a/apps/dashboard/src/main/resources/struts.xml +++ b/apps/dashboard/src/main/resources/struts.xml @@ -129,6 +129,7 @@ ADMIN_ACTIONS READ_WRITE + "User created a new account" 403 @@ -152,6 +153,7 @@ USER_ACTIONS READ_WRITE + Navigated to a specific account in Akto 403 @@ -172,6 +174,7 @@ INTEGRATIONS READ_WRITE + User configured Google settings 403 @@ -192,6 +195,7 @@ INTEGRATIONS READ_WRITE + User sent Google authentication code to the server 403 @@ -303,6 +307,7 @@ ADMIN_ACTIONS READ_WRITE + "Removed a user from Akto" 403 @@ -321,6 +326,7 @@ USER_ACTIONS READ_WRITE + "User made another user admin in Akto" 403 @@ -430,6 +436,7 @@ ADMIN_ACTIONS READ_WRITE + "User deleted Github SSO settings" @@ -459,6 +466,7 @@ ADMIN_ACTIONS READ_WRITE + "User added Github SSO settings" @@ -509,6 +517,7 @@ ADMIN_ACTIONS READ_WRITE + "User added Okta SSO settings" @@ -538,6 +547,7 @@ ADMIN_ACTIONS READ_WRITE + "User deleted Okta SSO settings" @@ -588,6 +598,7 @@ ADMIN_ACTIONS READ_WRITE + "User added Azure SSO settings" @@ -617,6 +628,7 @@ ADMIN_ACTIONS READ_WRITE + "User deleted Azure SSO settings" @@ -685,6 +697,7 @@ ADMIN_ACTIONS READ_WRITE + "User added Github App Secret Key" @@ -706,6 +719,7 @@ ADMIN_ACTIONS READ_WRITE + "User deleted Github App Secret Key" @@ -1051,6 +1065,7 @@ ISSUES READ_WRITE + "User triaged an API as false positive" @@ -1072,6 +1087,7 @@ USER_ACTIONS READ_WRITE + "User invited another user to Akto" @@ -1105,6 +1121,7 @@ SENSITIVE_DATA READ_WRITE + "User added a sensitive field" @@ -1127,6 +1144,7 @@ SENSITIVE_DATA READ_WRITE + "User bulk marked sensitive fields" @@ -1191,6 +1209,7 @@ USER_CONFIG READ_WRITE + "User analyzed API samples for access matrix" @@ -1233,6 +1252,7 @@ USER_CONFIG READ_WRITE + "User updated an access matrix task" @@ -1254,6 +1274,7 @@ USER_CONFIG READ_WRITE + "User created multiple access matrix tasks" @@ -1274,6 +1295,7 @@ USER_CONFIG READ_WRITE + "User deleted an access matrix" @@ -1295,6 +1317,7 @@ USER_CONFIG READ_WRITE + "User deleted an access matrix task" @@ -1316,6 +1339,7 @@ API_COLLECTIONS READ_WRITE + "User generated an OpenAPI file for a collection" @@ -1336,6 +1360,7 @@ API_COLLECTIONS READ_WRITE + "User deactivated collections from inventory" @@ -1360,6 +1385,7 @@ INTEGRATIONS READ_WRITE + "User imported an OpenAPI specification" @@ -1387,6 +1413,7 @@ API_COLLECTIONS READ_WRITE + "User activated collections in inventory" @@ -1442,6 +1469,7 @@ INTEGRATIONS READ_WRITE + "User imported OpenAPI/Swagger file to Akto" @@ -1668,6 +1696,7 @@ API_COLLECTIONS READ_WRITE + "User added APIs to a custom collection" 403 @@ -1689,6 +1718,7 @@ API_COLLECTIONS READ_WRITE + "User deleted APIs from a custom collection" 403 @@ -1710,6 +1740,7 @@ API_COLLECTIONS READ_WRITE + "User removed APIs from a custom collection" 403 @@ -1731,6 +1762,7 @@ API_COLLECTIONS READ_WRITE + "User computed custom collections" 403 @@ -1774,6 +1806,7 @@ API_COLLECTIONS READ_WRITE + "User updated environment type" 403 @@ -1794,6 +1827,7 @@ API_COLLECTIONS READ_WRITE + "User redacted a collection" 403 @@ -1816,6 +1850,7 @@ API_COLLECTIONS READ_WRITE + "User uploaded a HAR file" 403 @@ -1845,6 +1880,7 @@ API_COLLECTIONS READ_WRITE + "User uploaded a TCP file" 403 @@ -1864,6 +1900,7 @@ API_COLLECTIONS READ_WRITE + "User created an empty collection" 403 @@ -1892,6 +1929,7 @@ API_COLLECTIONS READ_WRITE + "User created a custom collection with API endpoints" 403 @@ -1913,6 +1951,7 @@ API_COLLECTIONS READ_WRITE + "User updated a custom collection" 403 @@ -1977,6 +2016,7 @@ INTEGRATIONS READ_WRITE + "User added/updated Postman credentials" 403 @@ -1996,6 +2036,7 @@ INTEGRATIONS READ_WRITE + "User created a Postman API" 403 @@ -2017,6 +2058,7 @@ INTEGRATIONS READ_WRITE + "User added an API collection via Postman API" 403 @@ -2111,6 +2153,7 @@ INTEGRATIONS READ_WRITE + "User imported Postman data to Akto" 403 @@ -2138,6 +2181,7 @@ INTEGRATIONS READ_WRITE + "User added a Slack webhook" 403 @@ -2165,6 +2209,7 @@ INTEGRATIONS READ_WRITE + "User deleted a Slack webhook" 403 @@ -2187,6 +2232,7 @@ INTEGRATIONS READ_WRITE + "User added an API token" 403 @@ -2211,6 +2257,7 @@ INTEGRATIONS READ_WRITE + "User deleted an API token" 403 @@ -2317,6 +2364,7 @@ API_COLLECTIONS READ_WRITE + "User deleted an API collection" 403 @@ -2336,6 +2384,7 @@ API_COLLECTIONS READ_WRITE + "User deleted multiple API collections" 403 @@ -2534,6 +2583,7 @@ SENSITIVE_DATA READ_WRITE + "User added/updated a sensitive data type" 403 @@ -2562,6 +2612,7 @@ SENSITIVE_DATA READ_WRITE + "User reset a sensitive data type" 403 @@ -2582,6 +2633,7 @@ SENSITIVE_DATA READ_WRITE + "User added/updated a sensitive data type" 403 @@ -2602,6 +2654,7 @@ SENSITIVE_DATA READ_WRITE + "User reset a sensitive data type" 403 @@ -2642,6 +2695,7 @@ SENSITIVE_DATA READ_WRITE + "User reset a sensitive data type" 403 @@ -2662,6 +2716,7 @@ SENSITIVE_DATA READ_WRITE + "User updated the active status of a sensitive data type" 403 @@ -2720,6 +2775,7 @@ AUTH_TYPE READ_WRITE + "User added a custom auth type" 403 @@ -2740,6 +2796,7 @@ AUTH_TYPE READ_WRITE + "User updated a custom auth type" 403 @@ -2761,6 +2818,7 @@ AUTH_TYPE READ_WRITE + "User resets all custom auth types" 403 @@ -2781,6 +2839,7 @@ AUTH_TYPE READ_WRITE + "User updated the active status of a custom auth type" 403 @@ -2804,6 +2863,7 @@ ADMIN_ACTIONS READ_WRITE + "User updated the sample data redaction status" @@ -2828,6 +2888,7 @@ ADMIN_ACTIONS READ_WRITE + "User updated the merge async status" @@ -2847,6 +2908,7 @@ ADMIN_ACTIONS READ_WRITE + "User updated the global rate limit" @@ -2866,6 +2928,7 @@ ADMIN_ACTIONS READ_WRITE + "User updated the delta time for ignoring summaries" @@ -2901,6 +2964,7 @@ ADMIN_ACTIONS READ_WRITE + "User updated the private CIDR IPs" @@ -2924,6 +2988,7 @@ ADMIN_ACTIONS READ_WRITE + "User applied access type to a collection" 403 @@ -2944,6 +3009,7 @@ ADMIN_ACTIONS READ_WRITE + "User updated the partner IPs" @@ -2967,6 +3033,7 @@ TAGS READ_WRITE + "User added/updated a tag config" @@ -2988,6 +3055,7 @@ TAGS READ_WRITE + "User reviewed a tag config" @@ -3009,6 +3077,7 @@ TAGS READ_WRITE + "User updated the active status of a tag config" @@ -3030,6 +3099,7 @@ ADMIN_ACTIONS READ_WRITE + "User successfully updated Akto via instance refresh" @@ -3053,6 +3123,7 @@ START_TEST_RUN READ_WRITE + "User started a test run" @@ -3188,6 +3259,7 @@ START_TEST_RUN READ_WRITE + "User toggled a collection for testing" @@ -3209,6 +3281,7 @@ USER_CONFIG READ_WRITE + "User added an auth mechanism" @@ -3238,6 +3311,7 @@ USER_CONFIG READ_WRITE + "User triggered login steps" @@ -3420,6 +3494,7 @@ ADMIN_ACTIONS READ_WRITE + "User updated the setup (Production/Staging/QA/Development) type" @@ -3441,6 +3516,7 @@ ADMIN_ACTIONS READ_WRITE + "User updated the regex matching in merging status" @@ -3462,6 +3538,7 @@ ADMIN_ACTIONS READ_WRITE + "User updated the telemetry status" @@ -3483,6 +3560,7 @@ DEFAULT_PAYLOADS READ_WRITE + "User updated the redundant URL settings" @@ -3658,6 +3736,7 @@ TEST_ROLES READ_WRITE + "User created a test role" @@ -3679,6 +3758,7 @@ TEST_ROLES READ_WRITE + "User deleted a test role" @@ -3700,6 +3780,7 @@ TEST_ROLES READ_WRITE + "User updated a test role" @@ -3721,6 +3802,7 @@ TEST_ROLES READ_WRITE + "User deleted an auth mechanism from a test role" @@ -3742,6 +3824,7 @@ TEST_ROLES READ_WRITE + "User updated an auth mechanism in a test role" @@ -3763,6 +3846,7 @@ TEST_ROLES READ_WRITE + "User added an auth mechanism to a test role" @@ -3841,6 +3925,7 @@ ISSUES READ_WRITE + "User updated the status of an issue" @@ -3860,6 +3945,7 @@ ISSUES READ_WRITE + "User bulk updated the status of issues" @@ -3879,6 +3965,7 @@ START_TEST_RUN READ_WRITE + "User created a workflow test" @@ -3899,6 +3986,7 @@ START_TEST_RUN READ_WRITE + "User edited a workflow test" @@ -3919,6 +4007,7 @@ TEST_RESULTS READ_WRITE + "User set the state of a workflow test" @@ -3939,6 +4028,7 @@ TEST_RESULTS READ_WRITE + "User exported a workflow test as a string" @@ -3959,6 +4049,7 @@ TEST_RESULTS READ_WRITE + "User edited the details of a workflow node" @@ -4020,6 +4111,7 @@ ADMIN_ACTIONS READ_WRITE + "User fetched OTPs" @@ -4041,6 +4133,7 @@ ADMIN_ACTIONS READ_WRITE + "User sent OTPs" @@ -4125,6 +4218,7 @@ INTEGRATIONS READ_WRITE + "User imported collection data in Burp" @@ -4149,6 +4243,7 @@ INTEGRATIONS READ_WRITE + "User added a custom webhook" @@ -4175,6 +4270,7 @@ TEST_RESULTS READ_WRITE + "User deleted scheduled workflow tests" @@ -4219,6 +4315,7 @@ INTEGRATIONS READ_WRITE + "User updated a custom webhook" @@ -4266,6 +4363,7 @@ TEST_RESULTS READ_WRITE + "User deleted test runs" @@ -4287,6 +4385,7 @@ TEST_RESULTS READ_WRITE + "User deleted test runs from summaries" @@ -4329,6 +4428,7 @@ TEST_RESULTS READ_WRITE + "User downloaded workflow as JSON" @@ -4350,6 +4450,7 @@ INTEGRATIONS READ_WRITE + "User changed the status of a webhook" @@ -4374,6 +4475,7 @@ INTEGRATIONS READ_WRITE + "User ran a webhook once" @@ -4412,6 +4514,7 @@ START_TEST_RUN READ_WRITE + "User stopped all tests" @@ -4433,6 +4536,7 @@ START_TEST_RUN READ_WRITE + "User stopped a test" @@ -4622,6 +4726,7 @@ INTEGRATIONS READ_WRITE + "User updated the load balancer details" @@ -4697,6 +4802,7 @@ INTEGRATIONS READ_WRITE + "User created a runtime stack" @@ -4749,6 +4855,7 @@ ADMIN_ACTIONS READ_WRITE + "User saved OTP data" @@ -4793,6 +4900,7 @@ USER_CONFIG READ_WRITE + "User triggered a login step in user config" @@ -4919,6 +5027,7 @@ USER_CONFIG READ_WRITE + "User uploaded a recorded flow in user config" @@ -4984,6 +5093,7 @@ ADMIN_ACTIONS READ_WRITE + "User updated the Akto UI mode" @@ -5051,6 +5161,7 @@ USER_ACTIONS READ_WRITE + "User ran onboarding tests" @@ -5095,6 +5206,7 @@ USER_ACTIONS READ_WRITE + "User skipped onboarding" @@ -5118,6 +5230,7 @@ ASK_GPT READ_WRITE + "User asked a question via AktoGPT" @@ -5168,6 +5281,7 @@ ASK_GPT READ_WRITE + "User updated AktoGPT config" @@ -5255,6 +5369,7 @@ INTEGRATIONS READ_WRITE + "User imported collection data using postman file" @@ -5284,6 +5399,7 @@ INTEGRATIONS READ_WRITE + "User imported collection data using postman file" @@ -5342,6 +5458,7 @@ INTEGRATIONS READ_WRITE + "User deleted postman import logs" @@ -5394,6 +5511,7 @@ INTEGRATIONS READ_WRITE + "User closed a loader" @@ -5415,6 +5533,7 @@ TEST_EDITOR READ_WRITE + "User set a test inactive in test editor" @@ -5436,6 +5555,7 @@ EXTERNAL_TEST_LIBRARY READ_WRITE + "User added a new test library" @@ -5457,6 +5577,7 @@ EXTERNAL_TEST_LIBRARY READ_WRITE + "User removed a test library" @@ -5478,6 +5599,7 @@ EXTERNAL_TEST_LIBRARY READ_WRITE + "User synced a custom test library" @@ -5522,6 +5644,7 @@ TEST_EDITOR READ_WRITE + "User saved a Akto test editor file" @@ -5544,6 +5667,7 @@ ADMIN_ACTIONS READ_WRITE + "User toggled debug logs feature in settings" @@ -5565,6 +5689,7 @@ ADMIN_ACTIONS READ_WRITE + "User added a filter header value map" @@ -5586,6 +5711,7 @@ ADMIN_ACTIONS READ_WRITE + "User added an API collection name mapper" @@ -5606,6 +5732,7 @@ ADMIN_ACTIONS READ_WRITE + "User deleted an API collection name mapper" @@ -5627,6 +5754,7 @@ TEST_EDITOR READ_WRITE + "User ran a test for a given template in test editor" @@ -5702,6 +5830,7 @@ ADMIN_ACTIONS READ_WRITE + "User updated the traffic alert threshold seconds in settings" @@ -5723,6 +5852,7 @@ API_COLLECTIONS READ_WRITE + "User de-merged an API" @@ -5756,6 +5886,7 @@ INTEGRATIONS READ_WRITE + "User tested Jira integration" @@ -5787,6 +5918,7 @@ INTEGRATIONS READ_WRITE + "User added a Jira integration" @@ -5837,6 +5969,7 @@ ISSUES READ_WRITE + "User created a Jira issue" @@ -5858,6 +5991,7 @@ ISSUES READ_WRITE + "User attached a file to a Jira issue" @@ -5980,6 +6114,7 @@ INTEGRATIONS READ_WRITE + "User marked a connection as skipped" @@ -5999,6 +6134,7 @@ USER_ACTIONS READ_WRITE + "User updated their username and organization name" @@ -6018,6 +6154,7 @@ BILLING READ_WRITE + "User provisioned a subscription" @@ -6041,6 +6178,7 @@ BILLING READ_WRITE + "User synced usage data" @@ -6064,6 +6202,7 @@ BILLING READ_WRITE + "User synced with Akto usage data" @@ -6108,6 +6247,7 @@ BILLING READ_WRITE + "User refreshed usage data for an organization" @@ -6173,6 +6313,7 @@ DEFAULT_PAYLOADS READ_WRITE + "User saved a default payload" @@ -6194,6 +6335,7 @@ API_COLLECTIONS READ_WRITE + "User built a dependency table" @@ -6216,6 +6358,7 @@ API_COLLECTIONS READ_WRITE + "User invoked a dependency table" @@ -6237,6 +6380,7 @@ API_COLLECTIONS READ_WRITE + "User saved replace details" @@ -6258,6 +6402,7 @@ API_COLLECTIONS READ_WRITE + "User saved global variables" @@ -6363,6 +6508,7 @@ API_COLLECTIONS READ_WRITE + "User synced extracted APIs from source code" @@ -6450,6 +6596,7 @@ TRAFFIC_FILTERS READ_WRITE + "User marked an alert as dismissed" @@ -6495,6 +6642,7 @@ USER_ACTIONS READ_WRITE + "User updated a script" TEST_PRE_SCRIPT @@ -6543,6 +6691,7 @@ USER_ACTIONS READ_WRITE + "User added a script" TEST_PRE_SCRIPT @@ -6571,6 +6720,7 @@ INTEGRATIONS READ_WRITE + "User added a code analysis repo" 403 @@ -6593,6 +6743,7 @@ INTEGRATIONS READ_WRITE + "User deleted a code analysis repo" 403 @@ -6676,6 +6827,7 @@ ADMIN_ACTIONS READ_WRITE + "User saved a filter in YAML template" 403 @@ -6751,6 +6903,7 @@ ADMIN_ACTIONS READ_WRITE + "User added advanced filters for traffic analysis" 403 @@ -6832,6 +6985,7 @@ ADMIN_ACTIONS READ_WRITE + "User deleted an advanced filter for traffic analysis" 403 @@ -6853,6 +7007,7 @@ ADMIN_ACTIONS READ_WRITE + "User changed the state of an advanced filter for traffic analysis" 403 @@ -6934,6 +7089,7 @@ ADMIN_ACTIONS READ_WRITE + "User updated retrospective filter settings" 403 @@ -6977,6 +7133,7 @@ ADMIN_ACTIONS READ_WRITE + "User modified account settings" 403 From 0f5e8f67f6b5b350f78622ad95915ed3afa0a05d Mon Sep 17 00:00:00 2001 From: TangoBeeAkto Date: Mon, 14 Oct 2024 13:15:41 +0530 Subject: [PATCH 11/19] feat: adding null check for accessGiven --- .../main/java/com/akto/interceptor/RoleAccessInterceptor.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/dashboard/src/main/java/com/akto/interceptor/RoleAccessInterceptor.java b/apps/dashboard/src/main/java/com/akto/interceptor/RoleAccessInterceptor.java index 9960140dee..3caf577be4 100644 --- a/apps/dashboard/src/main/java/com/akto/interceptor/RoleAccessInterceptor.java +++ b/apps/dashboard/src/main/java/com/akto/interceptor/RoleAccessInterceptor.java @@ -123,7 +123,7 @@ public String intercept(ActionInvocation invocation) throws Exception { ReadWriteAccess accessGiven = userRoleRecord.getReadWriteAccessForFeature(featureType); boolean hasRequiredAccess = false; - if(this.accessType.equalsIgnoreCase(ReadWriteAccess.READ.toString()) || this.accessType.equalsIgnoreCase(accessGiven.toString())){ + if(this.accessType.equalsIgnoreCase(ReadWriteAccess.READ.toString()) || (accessGiven != null && this.accessType.equalsIgnoreCase(accessGiven.toString()))){ hasRequiredAccess = true; } @@ -133,7 +133,7 @@ public String intercept(ActionInvocation invocation) throws Exception { } try { - if (this.accessType.equalsIgnoreCase(ReadWriteAccess.READ_WRITE.toString())) { + if (accessGiven != null && this.accessType.equalsIgnoreCase(ReadWriteAccess.READ_WRITE.toString())) { long timestamp = Context.now(); String apiEndpoint = invocation.getProxy().getActionName(); String actionDescription = this.actionDescription == null ? "Error: Description not available" : this.actionDescription; From 11904330c30c031d127c245f4e6536d928b970db Mon Sep 17 00:00:00 2001 From: Umesh Kumar <166806589+TangoBeeAkto@users.noreply.github.com> Date: Mon, 21 Oct 2024 12:57:37 +0530 Subject: [PATCH 12/19] feat: giving admin_actions read access only to admins --- .../com/akto/action/ApiAuditLogsAction.java | 9 - .../interceptor/RoleAccessInterceptor.java | 5 +- apps/dashboard/src/main/resources/struts.xml | 309 +++++++++--------- .../pages/settings/audit_logs/AuditLogs.jsx | 4 +- 4 files changed, 160 insertions(+), 167 deletions(-) diff --git a/apps/dashboard/src/main/java/com/akto/action/ApiAuditLogsAction.java b/apps/dashboard/src/main/java/com/akto/action/ApiAuditLogsAction.java index 91b5227dc0..7d519cf2a3 100644 --- a/apps/dashboard/src/main/java/com/akto/action/ApiAuditLogsAction.java +++ b/apps/dashboard/src/main/java/com/akto/action/ApiAuditLogsAction.java @@ -1,9 +1,6 @@ package com.akto.action; -import com.akto.dao.RBACDao; import com.akto.dao.audit_logs.ApiAuditLogsDao; -import com.akto.dao.context.Context; -import com.akto.dto.RBAC; import com.akto.dto.User; import com.akto.dto.audit_logs.ApiAuditLogs; import com.mongodb.client.model.Filters; @@ -25,12 +22,6 @@ public String fetchApiAuditLogsFromDb() { User user = getSUser(); if(user == null) return ERROR.toUpperCase(); - RBAC.Role currentRoleForUser = RBACDao.getCurrentRoleForUser(user.getId(), Context.accountId.get()); - if(currentRoleForUser == null || !currentRoleForUser.equals(RBAC.Role.ADMIN)) { - addActionError("You do not have access to the audit logs."); - return ERROR.toUpperCase(); - } - Bson filters = Filters.and( Filters.gte(ApiAuditLogs.TIMESTAMP, startTimestamp), Filters.lt(ApiAuditLogs.TIMESTAMP, endTimestamp) diff --git a/apps/dashboard/src/main/java/com/akto/interceptor/RoleAccessInterceptor.java b/apps/dashboard/src/main/java/com/akto/interceptor/RoleAccessInterceptor.java index 3caf577be4..d7eab9c23f 100644 --- a/apps/dashboard/src/main/java/com/akto/interceptor/RoleAccessInterceptor.java +++ b/apps/dashboard/src/main/java/com/akto/interceptor/RoleAccessInterceptor.java @@ -126,7 +126,10 @@ public String intercept(ActionInvocation invocation) throws Exception { if(this.accessType.equalsIgnoreCase(ReadWriteAccess.READ.toString()) || (accessGiven != null && this.accessType.equalsIgnoreCase(accessGiven.toString()))){ hasRequiredAccess = true; } - + if(featureLabel.equals(Feature.ADMIN_ACTIONS.name())){ + hasRequiredAccess = userRole.equals(Role.ADMIN.name()); + } + if(!hasRequiredAccess) { ((ActionSupport) invocation.getAction()).addActionError("The role '" + userRole + "' does not have access."); return FORBIDDEN; diff --git a/apps/dashboard/src/main/resources/struts.xml b/apps/dashboard/src/main/resources/struts.xml index 8740e9acec..a07346e496 100644 --- a/apps/dashboard/src/main/resources/struts.xml +++ b/apps/dashboard/src/main/resources/struts.xml @@ -129,7 +129,7 @@ ADMIN_ACTIONS READ_WRITE - "User created a new account" + User created a new account 403 @@ -307,7 +307,7 @@ ADMIN_ACTIONS READ_WRITE - "Removed a user from Akto" + Removed a user from Akto 403 @@ -326,7 +326,7 @@ USER_ACTIONS READ_WRITE - "User made another user admin in Akto" + User made another user admin in Akto 403 @@ -436,7 +436,7 @@ ADMIN_ACTIONS READ_WRITE - "User deleted Github SSO settings" + User deleted Github SSO settings @@ -466,7 +466,7 @@ ADMIN_ACTIONS READ_WRITE - "User added Github SSO settings" + User added Github SSO settings @@ -517,7 +517,7 @@ ADMIN_ACTIONS READ_WRITE - "User added Okta SSO settings" + User added Okta SSO settings @@ -547,7 +547,7 @@ ADMIN_ACTIONS READ_WRITE - "User deleted Okta SSO settings" + User deleted Okta SSO settings @@ -598,7 +598,7 @@ ADMIN_ACTIONS READ_WRITE - "User added Azure SSO settings" + User added Azure SSO settings @@ -628,7 +628,7 @@ ADMIN_ACTIONS READ_WRITE - "User deleted Azure SSO settings" + User deleted Azure SSO settings @@ -697,7 +697,7 @@ ADMIN_ACTIONS READ_WRITE - "User added Github App Secret Key" + User added Github App Secret Key @@ -719,7 +719,7 @@ ADMIN_ACTIONS READ_WRITE - "User deleted Github App Secret Key" + User deleted Github App Secret Key @@ -1065,7 +1065,7 @@ ISSUES READ_WRITE - "User triaged an API as false positive" + User triaged an API as false positive @@ -1087,7 +1087,7 @@ USER_ACTIONS READ_WRITE - "User invited another user to Akto" + User invited another user to Akto @@ -1121,7 +1121,7 @@ SENSITIVE_DATA READ_WRITE - "User added a sensitive field" + User added a sensitive field @@ -1144,7 +1144,7 @@ SENSITIVE_DATA READ_WRITE - "User bulk marked sensitive fields" + User bulk marked sensitive fields @@ -1209,7 +1209,7 @@ USER_CONFIG READ_WRITE - "User analyzed API samples for access matrix" + User analyzed API samples for access matrix @@ -1252,7 +1252,7 @@ USER_CONFIG READ_WRITE - "User updated an access matrix task" + User updated an access matrix task @@ -1274,7 +1274,7 @@ USER_CONFIG READ_WRITE - "User created multiple access matrix tasks" + User created multiple access matrix tasks @@ -1295,7 +1295,7 @@ USER_CONFIG READ_WRITE - "User deleted an access matrix" + User deleted an access matrix @@ -1317,7 +1317,7 @@ USER_CONFIG READ_WRITE - "User deleted an access matrix task" + User deleted an access matrix task @@ -1339,7 +1339,7 @@ API_COLLECTIONS READ_WRITE - "User generated an OpenAPI file for a collection" + User generated an OpenAPI file for a collection @@ -1360,7 +1360,7 @@ API_COLLECTIONS READ_WRITE - "User deactivated collections from inventory" + User deactivated collections from inventory @@ -1385,7 +1385,7 @@ INTEGRATIONS READ_WRITE - "User imported an OpenAPI specification" + User imported an OpenAPI specification @@ -1413,7 +1413,7 @@ API_COLLECTIONS READ_WRITE - "User activated collections in inventory" + User activated collections in inventory @@ -1469,7 +1469,7 @@ INTEGRATIONS READ_WRITE - "User imported OpenAPI/Swagger file to Akto" + User imported OpenAPI/Swagger file to Akto @@ -1696,7 +1696,7 @@ API_COLLECTIONS READ_WRITE - "User added APIs to a custom collection" + User added APIs to a custom collection 403 @@ -1718,7 +1718,7 @@ API_COLLECTIONS READ_WRITE - "User deleted APIs from a custom collection" + User deleted APIs from a custom collection 403 @@ -1740,7 +1740,7 @@ API_COLLECTIONS READ_WRITE - "User removed APIs from a custom collection" + User removed APIs from a custom collection 403 @@ -1762,7 +1762,7 @@ API_COLLECTIONS READ_WRITE - "User computed custom collections" + User computed custom collections 403 @@ -1806,7 +1806,7 @@ API_COLLECTIONS READ_WRITE - "User updated environment type" + User updated environment type 403 @@ -1827,7 +1827,7 @@ API_COLLECTIONS READ_WRITE - "User redacted a collection" + User redacted a collection 403 @@ -1850,7 +1850,7 @@ API_COLLECTIONS READ_WRITE - "User uploaded a HAR file" + User uploaded a HAR file 403 @@ -1880,7 +1880,7 @@ API_COLLECTIONS READ_WRITE - "User uploaded a TCP file" + User uploaded a TCP file 403 @@ -1900,7 +1900,7 @@ API_COLLECTIONS READ_WRITE - "User created an empty collection" + User created an empty collection 403 @@ -1929,7 +1929,7 @@ API_COLLECTIONS READ_WRITE - "User created a custom collection with API endpoints" + User created a custom collection with API endpoints 403 @@ -1951,7 +1951,7 @@ API_COLLECTIONS READ_WRITE - "User updated a custom collection" + User updated a custom collection 403 @@ -2016,7 +2016,7 @@ INTEGRATIONS READ_WRITE - "User added/updated Postman credentials" + User added/updated Postman credentials 403 @@ -2036,7 +2036,7 @@ INTEGRATIONS READ_WRITE - "User created a Postman API" + User created a Postman API 403 @@ -2058,7 +2058,7 @@ INTEGRATIONS READ_WRITE - "User added an API collection via Postman API" + User added an API collection via Postman API 403 @@ -2153,7 +2153,7 @@ INTEGRATIONS READ_WRITE - "User imported Postman data to Akto" + User imported Postman data to Akto 403 @@ -2181,7 +2181,7 @@ INTEGRATIONS READ_WRITE - "User added a Slack webhook" + User added a Slack webhook 403 @@ -2209,7 +2209,7 @@ INTEGRATIONS READ_WRITE - "User deleted a Slack webhook" + User deleted a Slack webhook 403 @@ -2232,7 +2232,7 @@ INTEGRATIONS READ_WRITE - "User added an API token" + User added an API token 403 @@ -2257,7 +2257,7 @@ INTEGRATIONS READ_WRITE - "User deleted an API token" + User deleted an API token 403 @@ -2364,7 +2364,7 @@ API_COLLECTIONS READ_WRITE - "User deleted an API collection" + User deleted an API collection 403 @@ -2384,7 +2384,7 @@ API_COLLECTIONS READ_WRITE - "User deleted multiple API collections" + User deleted multiple API collections 403 @@ -2583,7 +2583,7 @@ SENSITIVE_DATA READ_WRITE - "User added/updated a sensitive data type" + User added/updated a sensitive data type 403 @@ -2612,7 +2612,7 @@ SENSITIVE_DATA READ_WRITE - "User reset a sensitive data type" + User reset a sensitive data type 403 @@ -2633,7 +2633,7 @@ SENSITIVE_DATA READ_WRITE - "User added/updated a sensitive data type" + User added/updated a sensitive data type 403 @@ -2654,7 +2654,7 @@ SENSITIVE_DATA READ_WRITE - "User reset a sensitive data type" + User reset a sensitive data type 403 @@ -2695,7 +2695,7 @@ SENSITIVE_DATA READ_WRITE - "User reset a sensitive data type" + User reset a sensitive data type 403 @@ -2716,7 +2716,7 @@ SENSITIVE_DATA READ_WRITE - "User updated the active status of a sensitive data type" + User updated the active status of a sensitive data type 403 @@ -2775,7 +2775,7 @@ AUTH_TYPE READ_WRITE - "User added a custom auth type" + User added a custom auth type 403 @@ -2796,7 +2796,7 @@ AUTH_TYPE READ_WRITE - "User updated a custom auth type" + User updated a custom auth type 403 @@ -2818,7 +2818,7 @@ AUTH_TYPE READ_WRITE - "User resets all custom auth types" + User resets all custom auth types 403 @@ -2839,7 +2839,7 @@ AUTH_TYPE READ_WRITE - "User updated the active status of a custom auth type" + User updated the active status of a custom auth type 403 @@ -2863,7 +2863,7 @@ ADMIN_ACTIONS READ_WRITE - "User updated the sample data redaction status" + User updated the sample data redaction status @@ -2888,7 +2888,7 @@ ADMIN_ACTIONS READ_WRITE - "User updated the merge async status" + User updated the merge async status @@ -2908,7 +2908,7 @@ ADMIN_ACTIONS READ_WRITE - "User updated the global rate limit" + User updated the global rate limit @@ -2928,7 +2928,7 @@ ADMIN_ACTIONS READ_WRITE - "User updated the delta time for ignoring summaries" + User updated the delta time for ignoring summaries @@ -2964,7 +2964,7 @@ ADMIN_ACTIONS READ_WRITE - "User updated the private CIDR IPs" + User updated the private CIDR IPs @@ -2988,7 +2988,7 @@ ADMIN_ACTIONS READ_WRITE - "User applied access type to a collection" + User applied access type to a collection 403 @@ -3009,7 +3009,7 @@ ADMIN_ACTIONS READ_WRITE - "User updated the partner IPs" + User updated the partner IPs @@ -3033,7 +3033,7 @@ TAGS READ_WRITE - "User added/updated a tag config" + User added/updated a tag config @@ -3055,7 +3055,7 @@ TAGS READ_WRITE - "User reviewed a tag config" + User reviewed a tag config @@ -3077,7 +3077,7 @@ TAGS READ_WRITE - "User updated the active status of a tag config" + User updated the active status of a tag config @@ -3099,7 +3099,7 @@ ADMIN_ACTIONS READ_WRITE - "User successfully updated Akto via instance refresh" + User successfully updated Akto via instance refresh @@ -3123,7 +3123,7 @@ START_TEST_RUN READ_WRITE - "User started a test run" + User started a test run @@ -3259,7 +3259,7 @@ START_TEST_RUN READ_WRITE - "User toggled a collection for testing" + User toggled a collection for testing @@ -3281,7 +3281,7 @@ USER_CONFIG READ_WRITE - "User added an auth mechanism" + User added an auth mechanism @@ -3311,7 +3311,7 @@ USER_CONFIG READ_WRITE - "User triggered login steps" + User triggered login steps @@ -3494,7 +3494,7 @@ ADMIN_ACTIONS READ_WRITE - "User updated the setup (Production/Staging/QA/Development) type" + User updated the setup (Production/Staging/QA/Development) type @@ -3516,7 +3516,7 @@ ADMIN_ACTIONS READ_WRITE - "User updated the regex matching in merging status" + User updated the regex matching in merging status @@ -3538,7 +3538,7 @@ ADMIN_ACTIONS READ_WRITE - "User updated the telemetry status" + User updated the telemetry status @@ -3560,7 +3560,7 @@ DEFAULT_PAYLOADS READ_WRITE - "User updated the redundant URL settings" + User updated the redundant URL settings @@ -3736,7 +3736,7 @@ TEST_ROLES READ_WRITE - "User created a test role" + User created a test role @@ -3758,7 +3758,7 @@ TEST_ROLES READ_WRITE - "User deleted a test role" + User deleted a test role @@ -3780,7 +3780,7 @@ TEST_ROLES READ_WRITE - "User updated a test role" + User updated a test role @@ -3802,7 +3802,7 @@ TEST_ROLES READ_WRITE - "User deleted an auth mechanism from a test role" + User deleted an auth mechanism from a test role @@ -3824,7 +3824,7 @@ TEST_ROLES READ_WRITE - "User updated an auth mechanism in a test role" + User updated an auth mechanism in a test role @@ -3846,7 +3846,7 @@ TEST_ROLES READ_WRITE - "User added an auth mechanism to a test role" + User added an auth mechanism to a test role @@ -3925,7 +3925,7 @@ ISSUES READ_WRITE - "User updated the status of an issue" + User updated the status of an issue @@ -3945,7 +3945,7 @@ ISSUES READ_WRITE - "User bulk updated the status of issues" + User bulk updated the status of issues @@ -3965,7 +3965,7 @@ START_TEST_RUN READ_WRITE - "User created a workflow test" + User created a workflow test @@ -3986,7 +3986,7 @@ START_TEST_RUN READ_WRITE - "User edited a workflow test" + User edited a workflow test @@ -4007,7 +4007,7 @@ TEST_RESULTS READ_WRITE - "User set the state of a workflow test" + User set the state of a workflow test @@ -4028,7 +4028,7 @@ TEST_RESULTS READ_WRITE - "User exported a workflow test as a string" + User exported a workflow test as a string @@ -4049,7 +4049,7 @@ TEST_RESULTS READ_WRITE - "User edited the details of a workflow node" + User edited the details of a workflow node @@ -4111,7 +4111,7 @@ ADMIN_ACTIONS READ_WRITE - "User fetched OTPs" + User fetched OTPs @@ -4133,7 +4133,7 @@ ADMIN_ACTIONS READ_WRITE - "User sent OTPs" + User sent OTPs @@ -4218,7 +4218,7 @@ INTEGRATIONS READ_WRITE - "User imported collection data in Burp" + User imported collection data in Burp @@ -4243,7 +4243,7 @@ INTEGRATIONS READ_WRITE - "User added a custom webhook" + User added a custom webhook @@ -4270,7 +4270,7 @@ TEST_RESULTS READ_WRITE - "User deleted scheduled workflow tests" + User deleted scheduled workflow tests @@ -4315,7 +4315,7 @@ INTEGRATIONS READ_WRITE - "User updated a custom webhook" + User updated a custom webhook @@ -4363,7 +4363,7 @@ TEST_RESULTS READ_WRITE - "User deleted test runs" + User deleted test runs @@ -4385,7 +4385,7 @@ TEST_RESULTS READ_WRITE - "User deleted test runs from summaries" + User deleted test runs from summaries @@ -4428,7 +4428,7 @@ TEST_RESULTS READ_WRITE - "User downloaded workflow as JSON" + User downloaded workflow as JSON @@ -4450,7 +4450,7 @@ INTEGRATIONS READ_WRITE - "User changed the status of a webhook" + User changed the status of a webhook @@ -4475,7 +4475,7 @@ INTEGRATIONS READ_WRITE - "User ran a webhook once" + User ran a webhook once @@ -4514,7 +4514,7 @@ START_TEST_RUN READ_WRITE - "User stopped all tests" + User stopped all tests @@ -4536,7 +4536,7 @@ START_TEST_RUN READ_WRITE - "User stopped a test" + User stopped a test @@ -4726,7 +4726,7 @@ INTEGRATIONS READ_WRITE - "User updated the load balancer details" + User updated the load balancer details @@ -4802,7 +4802,7 @@ INTEGRATIONS READ_WRITE - "User created a runtime stack" + User created a runtime stack @@ -4855,7 +4855,7 @@ ADMIN_ACTIONS READ_WRITE - "User saved OTP data" + User saved OTP data @@ -4900,7 +4900,7 @@ USER_CONFIG READ_WRITE - "User triggered a login step in user config" + User triggered a login step in user config @@ -5027,7 +5027,7 @@ USER_CONFIG READ_WRITE - "User uploaded a recorded flow in user config" + User uploaded a recorded flow in user config @@ -5093,7 +5093,7 @@ ADMIN_ACTIONS READ_WRITE - "User updated the Akto UI mode" + User updated the Akto UI mode @@ -5161,7 +5161,7 @@ USER_ACTIONS READ_WRITE - "User ran onboarding tests" + User ran onboarding tests @@ -5205,8 +5205,7 @@ USER_ACTIONS - READ_WRITE - "User skipped onboarding" + READ @@ -5230,7 +5229,7 @@ ASK_GPT READ_WRITE - "User asked a question via AktoGPT" + User asked a question via AktoGPT @@ -5281,7 +5280,7 @@ ASK_GPT READ_WRITE - "User updated AktoGPT config" + User updated AktoGPT config @@ -5369,7 +5368,7 @@ INTEGRATIONS READ_WRITE - "User imported collection data using postman file" + User imported collection data using postman file @@ -5399,7 +5398,7 @@ INTEGRATIONS READ_WRITE - "User imported collection data using postman file" + User imported collection data using postman file @@ -5458,7 +5457,7 @@ INTEGRATIONS READ_WRITE - "User deleted postman import logs" + User deleted postman import logs @@ -5511,7 +5510,7 @@ INTEGRATIONS READ_WRITE - "User closed a loader" + User closed a loader @@ -5533,7 +5532,7 @@ TEST_EDITOR READ_WRITE - "User set a test inactive in test editor" + User set a test inactive in test editor @@ -5555,7 +5554,7 @@ EXTERNAL_TEST_LIBRARY READ_WRITE - "User added a new test library" + User added a new test library @@ -5577,7 +5576,7 @@ EXTERNAL_TEST_LIBRARY READ_WRITE - "User removed a test library" + User removed a test library @@ -5599,7 +5598,7 @@ EXTERNAL_TEST_LIBRARY READ_WRITE - "User synced a custom test library" + User synced a custom test library @@ -5644,7 +5643,7 @@ TEST_EDITOR READ_WRITE - "User saved a Akto test editor file" + User saved a Akto test editor file @@ -5667,7 +5666,7 @@ ADMIN_ACTIONS READ_WRITE - "User toggled debug logs feature in settings" + User toggled debug logs feature in settings @@ -5689,7 +5688,7 @@ ADMIN_ACTIONS READ_WRITE - "User added a filter header value map" + User added a filter header value map @@ -5711,7 +5710,7 @@ ADMIN_ACTIONS READ_WRITE - "User added an API collection name mapper" + User added an API collection name mapper @@ -5732,7 +5731,7 @@ ADMIN_ACTIONS READ_WRITE - "User deleted an API collection name mapper" + User deleted an API collection name mapper @@ -5754,7 +5753,7 @@ TEST_EDITOR READ_WRITE - "User ran a test for a given template in test editor" + User ran a test for a given template in test editor @@ -5830,7 +5829,7 @@ ADMIN_ACTIONS READ_WRITE - "User updated the traffic alert threshold seconds in settings" + User updated the traffic alert threshold seconds in settings @@ -5852,7 +5851,7 @@ API_COLLECTIONS READ_WRITE - "User de-merged an API" + User de-merged an API @@ -5886,7 +5885,7 @@ INTEGRATIONS READ_WRITE - "User tested Jira integration" + User tested Jira integration @@ -5918,7 +5917,7 @@ INTEGRATIONS READ_WRITE - "User added a Jira integration" + User added a Jira integration @@ -5969,7 +5968,7 @@ ISSUES READ_WRITE - "User created a Jira issue" + User created a Jira issue @@ -5991,7 +5990,7 @@ ISSUES READ_WRITE - "User attached a file to a Jira issue" + User attached a file to a Jira issue @@ -6114,7 +6113,7 @@ INTEGRATIONS READ_WRITE - "User marked a connection as skipped" + User marked a connection as skipped @@ -6134,7 +6133,7 @@ USER_ACTIONS READ_WRITE - "User updated their username and organization name" + User updated their username and organization name @@ -6154,7 +6153,7 @@ BILLING READ_WRITE - "User provisioned a subscription" + User provisioned a subscription @@ -6178,7 +6177,7 @@ BILLING READ_WRITE - "User synced usage data" + User synced usage data @@ -6202,7 +6201,7 @@ BILLING READ_WRITE - "User synced with Akto usage data" + User synced with Akto usage data @@ -6247,7 +6246,7 @@ BILLING READ_WRITE - "User refreshed usage data for an organization" + User refreshed usage data for an organization @@ -6313,7 +6312,7 @@ DEFAULT_PAYLOADS READ_WRITE - "User saved a default payload" + User saved a default payload @@ -6335,7 +6334,7 @@ API_COLLECTIONS READ_WRITE - "User built a dependency table" + User built a dependency table @@ -6358,7 +6357,7 @@ API_COLLECTIONS READ_WRITE - "User invoked a dependency table" + User invoked a dependency table @@ -6380,7 +6379,7 @@ API_COLLECTIONS READ_WRITE - "User saved replace details" + User saved replace details @@ -6402,7 +6401,7 @@ API_COLLECTIONS READ_WRITE - "User saved global variables" + User saved global variables @@ -6508,7 +6507,7 @@ API_COLLECTIONS READ_WRITE - "User synced extracted APIs from source code" + User synced extracted APIs from source code @@ -6596,7 +6595,7 @@ TRAFFIC_FILTERS READ_WRITE - "User marked an alert as dismissed" + User marked an alert as dismissed @@ -6642,7 +6641,7 @@ USER_ACTIONS READ_WRITE - "User updated a script" + User updated a script TEST_PRE_SCRIPT @@ -6691,7 +6690,7 @@ USER_ACTIONS READ_WRITE - "User added a script" + User added a script TEST_PRE_SCRIPT @@ -6720,7 +6719,7 @@ INTEGRATIONS READ_WRITE - "User added a code analysis repo" + User added a code analysis repo 403 @@ -6743,7 +6742,7 @@ INTEGRATIONS READ_WRITE - "User deleted a code analysis repo" + User deleted a code analysis repo 403 @@ -6827,7 +6826,7 @@ ADMIN_ACTIONS READ_WRITE - "User saved a filter in YAML template" + User saved a filter in YAML template 403 @@ -6903,7 +6902,7 @@ ADMIN_ACTIONS READ_WRITE - "User added advanced filters for traffic analysis" + User added advanced filters for traffic analysis 403 @@ -6985,7 +6984,7 @@ ADMIN_ACTIONS READ_WRITE - "User deleted an advanced filter for traffic analysis" + User deleted an advanced filter for traffic analysis 403 @@ -7007,7 +7006,7 @@ ADMIN_ACTIONS READ_WRITE - "User changed the state of an advanced filter for traffic analysis" + User changed the state of an advanced filter for traffic analysis 403 @@ -7089,7 +7088,7 @@ ADMIN_ACTIONS READ_WRITE - "User updated retrospective filter settings" + User updated retrospective filter settings 403 @@ -7133,7 +7132,7 @@ ADMIN_ACTIONS READ_WRITE - "User modified account settings" + User modified account settings 403 diff --git a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/settings/audit_logs/AuditLogs.jsx b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/settings/audit_logs/AuditLogs.jsx index 879c99a126..56ac646995 100644 --- a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/settings/audit_logs/AuditLogs.jsx +++ b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/settings/audit_logs/AuditLogs.jsx @@ -84,10 +84,10 @@ const AuditLogs = () => { return { ...item, apiEndpoint: func.formatEndpoint(apiEndpoint), - actionDescription:

{actionDescription}

, + actionDescription: {actionDescription}, timestamp: func.prettifyEpoch(timestamp), rawTimestamp: timestamp, - userAgent:

{userAgent}

, + userAgent: {userAgent}, rawUserAgent: userAgent } }) From 19f5a55847218ae828cc1cd5a9f3a1f6e3ec9d4b Mon Sep 17 00:00:00 2001 From: Umesh Kumar <166806589+TangoBeeAkto@users.noreply.github.com> Date: Mon, 21 Oct 2024 13:17:39 +0530 Subject: [PATCH 13/19] feat: showing search box on audit logs page by default --- .../src/apps/dashboard/pages/settings/audit_logs/AuditLogs.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/settings/audit_logs/AuditLogs.jsx b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/settings/audit_logs/AuditLogs.jsx index 56ac646995..c616f000ff 100644 --- a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/settings/audit_logs/AuditLogs.jsx +++ b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/settings/audit_logs/AuditLogs.jsx @@ -144,7 +144,7 @@ const AuditLogs = () => { useNewRow={true} condensedHeight={true} disambiguateLabel={disambiguateLabel} - mode={IndexFiltersMode.Default} + mode={IndexFiltersMode.Filtering} onRowClick={(data) => {}} showFooter={false} loading={tableLoading} From a1b9a20ef9e79cfd3f5fb181da9bdcde9e742376 Mon Sep 17 00:00:00 2001 From: Umesh Kumar <166806589+TangoBeeAkto@users.noreply.github.com> Date: Mon, 21 Oct 2024 13:29:10 +0530 Subject: [PATCH 14/19] fix: fetching issues by status only if we have testingRunSummaryId --- .../testing/vulnerability_report/VulnerabilityReport.jsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/testing/vulnerability_report/VulnerabilityReport.jsx b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/testing/vulnerability_report/VulnerabilityReport.jsx index a691dfdccf..33c1c1cb98 100644 --- a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/testing/vulnerability_report/VulnerabilityReport.jsx +++ b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/testing/vulnerability_report/VulnerabilityReport.jsx @@ -187,11 +187,11 @@ function VulnerabilityReport() { let vulnerableTestingRunResults = [] //let sampleDataVsCurlMap = {} let allIgnoredTestingRunIssues = [] - await api.fetchIssuesByStatusAndSummaryId(testingRunSummaryId, ["IGNORED", "FIXED"]).then((issues) => { - allIgnoredTestingRunIssues = issues - }) if (testingRunSummaryId) { + await api.fetchIssuesByStatusAndSummaryId(testingRunSummaryId, ["IGNORED", "FIXED"]).then((issues) => { + allIgnoredTestingRunIssues = issues + }) while (true) { let testingRunCountsFromDB = 0 await api.fetchVulnerableTestingRunResults(testingRunSummaryId, resultsCount).then((resp) => { From 371698ada73bd405c8aa7c7f0093218184a07262 Mon Sep 17 00:00:00 2001 From: Umesh Kumar <166806589+TangoBeeAkto@users.noreply.github.com> Date: Mon, 21 Oct 2024 14:10:33 +0530 Subject: [PATCH 15/19] fix: not calling admin_actions api if user is not admin --- apps/dashboard/src/main/resources/struts.xml | 2 +- .../apps/dashboard/pages/settings/about/About.jsx | 4 +++- .../pages/settings/test_library/TestLibrary.jsx | 4 +++- .../pages/testing/user_config/UserConfig.jsx | 14 ++++++++------ 4 files changed, 15 insertions(+), 9 deletions(-) diff --git a/apps/dashboard/src/main/resources/struts.xml b/apps/dashboard/src/main/resources/struts.xml index a07346e496..b7a249ebb5 100644 --- a/apps/dashboard/src/main/resources/struts.xml +++ b/apps/dashboard/src/main/resources/struts.xml @@ -4556,7 +4556,7 @@ - ADMIN_ACTIONS + USER_ACTIONS READ diff --git a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/settings/about/About.jsx b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/settings/about/About.jsx index df366c5807..f0cb31b069 100644 --- a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/settings/about/About.jsx +++ b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/settings/about/About.jsx @@ -72,7 +72,9 @@ function About() { } useEffect(()=>{ - fetchDetails() + if(window.USER_ROLE === 'ADMIN') { + fetchDetails() + } },[]) function TitleComponent ({title,description}) { diff --git a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/settings/test_library/TestLibrary.jsx b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/settings/test_library/TestLibrary.jsx index 0124d945bd..1c20010a95 100644 --- a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/settings/test_library/TestLibrary.jsx +++ b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/settings/test_library/TestLibrary.jsx @@ -37,7 +37,9 @@ function TestLibrary() { } useEffect(() => { - fetchData(); + if(window.USER_ROLE === 'ADMIN') { + fetchData(); + } }, []) async function handleRemoveTestLibrary(repositoryUrl) { 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 b7d6810b15..d31aa4a826 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 @@ -41,12 +41,14 @@ function UserConfig() { else setHardcodedOpen(false) } - await settingRequests.fetchAdminSettings().then((resp)=> { - setInitialLimit(resp.accountSettings.globalRateLimit); - const val = resp?.accountSettings?.timeForScheduledSummaries === undefined || resp?.accountSettings?.timeForScheduledSummaries === 0 ? (120*60) : resp?.accountSettings?.timeForScheduledSummaries - setInitialDeltaTime(val/60) - LocalStore.getState().setDefaultIgnoreSummaryTime(val) - }) + if(window.USER_ROLE === 'ADMIN') { + await settingRequests.fetchAdminSettings().then((resp)=> { + setInitialLimit(resp.accountSettings.globalRateLimit); + const val = resp?.accountSettings?.timeForScheduledSummaries === undefined || resp?.accountSettings?.timeForScheduledSummaries === 0 ? (120*60) : resp?.accountSettings?.timeForScheduledSummaries + setInitialDeltaTime(val/60) + LocalStore.getState().setDefaultIgnoreSummaryTime(val) + }) + } await api.fetchScript().then((resp)=> { if (resp) { From 4fd34eb1a5164b6f3f4ebee7cd8e87861b99b335 Mon Sep 17 00:00:00 2001 From: Umesh Kumar <166806589+TangoBeeAkto@users.noreply.github.com> Date: Mon, 21 Oct 2024 14:35:40 +0530 Subject: [PATCH 16/19] feat: showing user agent client type in audit logs --- .../interceptor/RoleAccessInterceptor.java | 3 +- .../akto/audit_logs_util/AuditLogsUtil.java | 35 +++++++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/apps/dashboard/src/main/java/com/akto/interceptor/RoleAccessInterceptor.java b/apps/dashboard/src/main/java/com/akto/interceptor/RoleAccessInterceptor.java index d7eab9c23f..e2a11309c4 100644 --- a/apps/dashboard/src/main/java/com/akto/interceptor/RoleAccessInterceptor.java +++ b/apps/dashboard/src/main/java/com/akto/interceptor/RoleAccessInterceptor.java @@ -142,10 +142,11 @@ public String intercept(ActionInvocation invocation) throws Exception { String actionDescription = this.actionDescription == null ? "Error: Description not available" : this.actionDescription; String userEmail = user.getLogin(); String userAgent = request.getHeader("User-Agent") == null ? "Unknown User-Agent" : request.getHeader("User-Agent"); + AuditLogsUtil.ClientType userAgentType = AuditLogsUtil.findUserAgentType(userAgent); List userProxyIpAddresses = AuditLogsUtil.getClientIpAddresses(request); String userIpAddress = userProxyIpAddresses.get(0); - apiAuditLogs = new ApiAuditLogs(timestamp, apiEndpoint, actionDescription, userEmail, userAgent, userIpAddress, userProxyIpAddresses); + apiAuditLogs = new ApiAuditLogs(timestamp, apiEndpoint, actionDescription, userEmail, userAgentType.name(), userIpAddress, userProxyIpAddresses); } } catch(Exception e) { loggerMaker.errorAndAddToDb(e, "Error while inserting api audit logs: " + e.getMessage(), LogDb.DASHBOARD); diff --git a/libs/utils/src/main/java/com/akto/audit_logs_util/AuditLogsUtil.java b/libs/utils/src/main/java/com/akto/audit_logs_util/AuditLogsUtil.java index 7633524ffd..bdee4e6fc8 100644 --- a/libs/utils/src/main/java/com/akto/audit_logs_util/AuditLogsUtil.java +++ b/libs/utils/src/main/java/com/akto/audit_logs_util/AuditLogsUtil.java @@ -1,12 +1,47 @@ package com.akto.audit_logs_util; +import com.akto.util.Pair; + import javax.servlet.http.HttpServletRequest; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; +import java.util.regex.Pattern; public class AuditLogsUtil { + + public enum ClientType { + JAVA, NODE, GOLANG, CPP, PYTHON, MOBILE, BROWSER, CLOUDFLARE, POSTMAN, CURL, CUSTOM + } + private static final List> CLIENT_PATTERNS = new ArrayList<>(); + static { + CLIENT_PATTERNS.add(new Pair<>(Pattern.compile("android|iPhone|iPad"), ClientType.MOBILE)); + CLIENT_PATTERNS.add(new Pair<>(Pattern.compile("Mozilla|Chrome|Safari|Firefox|Edg|AppleWebKit"), ClientType.BROWSER)); + CLIENT_PATTERNS.add(new Pair<>(Pattern.compile("PostmanRuntime"), ClientType.POSTMAN)); + CLIENT_PATTERNS.add(new Pair<>(Pattern.compile("curl"), ClientType.CURL)); + CLIENT_PATTERNS.add(new Pair<>(Pattern.compile("Apache-HttpClient|okhttp|unirest-java|Java"), ClientType.JAVA)); + CLIENT_PATTERNS.add(new Pair<>(Pattern.compile("node-fetch|axios|got|node"), ClientType.NODE)); + CLIENT_PATTERNS.add(new Pair<>(Pattern.compile("Go-http-client|golang"), ClientType.GOLANG)); + CLIENT_PATTERNS.add(new Pair<>(Pattern.compile("C\\+\\+|cpprestsdk"), ClientType.CPP)); + CLIENT_PATTERNS.add(new Pair<>(Pattern.compile("python-requests|urllib3"), ClientType.PYTHON)); + CLIENT_PATTERNS.add(new Pair<>(Pattern.compile("Cloudflare-Traffic-Manager"), ClientType.CLOUDFLARE)); + } + + public static ClientType findUserAgentType(String userAgentValue) { + if (userAgentValue == null || userAgentValue.isEmpty()) { + return ClientType.CUSTOM; + } + + for (Pair entry : CLIENT_PATTERNS) { + if (entry.getFirst().matcher(userAgentValue).find()) { + return entry.getSecond(); + } + } + + return ClientType.CUSTOM; + } + public static List getClientIpAddresses(HttpServletRequest request) { List headers = Arrays.asList( "X-Forwarded-For", From cacc94616df412e9e14de16c1d24fe1e646d8569 Mon Sep 17 00:00:00 2001 From: Umesh Kumar <166806589+TangoBeeAkto@users.noreply.github.com> Date: Mon, 21 Oct 2024 15:07:13 +0530 Subject: [PATCH 17/19] feat: code clean up --- .../{ => settings}/ApiAuditLogsAction.java | 3 +- .../interceptor/RoleAccessInterceptor.java | 7 +-- apps/dashboard/src/main/resources/struts.xml | 2 +- .../components/layouts/DateRangeFilter.jsx | 1 - .../pages/settings/audit_logs/AuditLogs.jsx | 8 ++-- .../akto/audit_logs_util/AuditLogsUtil.java | 45 +------------------ .../runtime/policies/ApiAccessTypePolicy.java | 2 +- .../runtime/policies/UserAgentTypePolicy.java | 41 +++++++++++++++++ 8 files changed, 55 insertions(+), 54 deletions(-) rename apps/dashboard/src/main/java/com/akto/action/{ => settings}/ApiAuditLogsAction.java (96%) create mode 100644 libs/utils/src/main/java/com/akto/runtime/policies/UserAgentTypePolicy.java diff --git a/apps/dashboard/src/main/java/com/akto/action/ApiAuditLogsAction.java b/apps/dashboard/src/main/java/com/akto/action/settings/ApiAuditLogsAction.java similarity index 96% rename from apps/dashboard/src/main/java/com/akto/action/ApiAuditLogsAction.java rename to apps/dashboard/src/main/java/com/akto/action/settings/ApiAuditLogsAction.java index 7d519cf2a3..7fe71ae395 100644 --- a/apps/dashboard/src/main/java/com/akto/action/ApiAuditLogsAction.java +++ b/apps/dashboard/src/main/java/com/akto/action/settings/ApiAuditLogsAction.java @@ -1,5 +1,6 @@ -package com.akto.action; +package com.akto.action.settings; +import com.akto.action.UserAction; import com.akto.dao.audit_logs.ApiAuditLogsDao; import com.akto.dto.User; import com.akto.dto.audit_logs.ApiAuditLogs; diff --git a/apps/dashboard/src/main/java/com/akto/interceptor/RoleAccessInterceptor.java b/apps/dashboard/src/main/java/com/akto/interceptor/RoleAccessInterceptor.java index e2a11309c4..31636c8be1 100644 --- a/apps/dashboard/src/main/java/com/akto/interceptor/RoleAccessInterceptor.java +++ b/apps/dashboard/src/main/java/com/akto/interceptor/RoleAccessInterceptor.java @@ -16,6 +16,7 @@ import com.akto.filter.UserDetailsFilter; import com.akto.log.LoggerMaker; import com.akto.log.LoggerMaker.LogDb; +import com.akto.runtime.policies.UserAgentTypePolicy; import com.akto.util.DashboardMode; import com.mongodb.client.model.Filters; import com.opensymphony.xwork2.Action; @@ -123,7 +124,7 @@ public String intercept(ActionInvocation invocation) throws Exception { ReadWriteAccess accessGiven = userRoleRecord.getReadWriteAccessForFeature(featureType); boolean hasRequiredAccess = false; - if(this.accessType.equalsIgnoreCase(ReadWriteAccess.READ.toString()) || (accessGiven != null && this.accessType.equalsIgnoreCase(accessGiven.toString()))){ + if(this.accessType.equalsIgnoreCase(ReadWriteAccess.READ.toString()) || this.accessType.equalsIgnoreCase(accessGiven.toString())){ hasRequiredAccess = true; } if(featureLabel.equals(Feature.ADMIN_ACTIONS.name())){ @@ -136,13 +137,13 @@ public String intercept(ActionInvocation invocation) throws Exception { } try { - if (accessGiven != null && this.accessType.equalsIgnoreCase(ReadWriteAccess.READ_WRITE.toString())) { + if (this.accessType.equalsIgnoreCase(ReadWriteAccess.READ_WRITE.toString())) { long timestamp = Context.now(); String apiEndpoint = invocation.getProxy().getActionName(); String actionDescription = this.actionDescription == null ? "Error: Description not available" : this.actionDescription; String userEmail = user.getLogin(); String userAgent = request.getHeader("User-Agent") == null ? "Unknown User-Agent" : request.getHeader("User-Agent"); - AuditLogsUtil.ClientType userAgentType = AuditLogsUtil.findUserAgentType(userAgent); + UserAgentTypePolicy.ClientType userAgentType = UserAgentTypePolicy.findUserAgentType(userAgent); List userProxyIpAddresses = AuditLogsUtil.getClientIpAddresses(request); String userIpAddress = userProxyIpAddresses.get(0); diff --git a/apps/dashboard/src/main/resources/struts.xml b/apps/dashboard/src/main/resources/struts.xml index b7a249ebb5..1c870344e6 100644 --- a/apps/dashboard/src/main/resources/struts.xml +++ b/apps/dashboard/src/main/resources/struts.xml @@ -7169,7 +7169,7 @@
- + diff --git a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/components/layouts/DateRangeFilter.jsx b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/components/layouts/DateRangeFilter.jsx index c2e72b56ff..8c10fd366a 100644 --- a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/components/layouts/DateRangeFilter.jsx +++ b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/components/layouts/DateRangeFilter.jsx @@ -25,7 +25,6 @@ function DateRangeFilter(props){ fullHeight activator={ } - secondaryActions={ dispatchCurrDateRange({ type: "update", period: dateObj.period, title: dateObj.title, alias: dateObj.alias })} />} + primaryAction={} + secondaryActions={ dispatchCurrDateRange({ type: "update", period: dateObj.period, title: dateObj.title, alias: dateObj.alias })} />} isFirstPage={true} components={[auditLogsTable]} /> diff --git a/libs/utils/src/main/java/com/akto/audit_logs_util/AuditLogsUtil.java b/libs/utils/src/main/java/com/akto/audit_logs_util/AuditLogsUtil.java index bdee4e6fc8..3331a4b432 100644 --- a/libs/utils/src/main/java/com/akto/audit_logs_util/AuditLogsUtil.java +++ b/libs/utils/src/main/java/com/akto/audit_logs_util/AuditLogsUtil.java @@ -1,56 +1,15 @@ package com.akto.audit_logs_util; -import com.akto.util.Pair; - +import com.akto.runtime.policies.ApiAccessTypePolicy; import javax.servlet.http.HttpServletRequest; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; import java.util.List; -import java.util.regex.Pattern; public class AuditLogsUtil { - public enum ClientType { - JAVA, NODE, GOLANG, CPP, PYTHON, MOBILE, BROWSER, CLOUDFLARE, POSTMAN, CURL, CUSTOM - } - private static final List> CLIENT_PATTERNS = new ArrayList<>(); - static { - CLIENT_PATTERNS.add(new Pair<>(Pattern.compile("android|iPhone|iPad"), ClientType.MOBILE)); - CLIENT_PATTERNS.add(new Pair<>(Pattern.compile("Mozilla|Chrome|Safari|Firefox|Edg|AppleWebKit"), ClientType.BROWSER)); - CLIENT_PATTERNS.add(new Pair<>(Pattern.compile("PostmanRuntime"), ClientType.POSTMAN)); - CLIENT_PATTERNS.add(new Pair<>(Pattern.compile("curl"), ClientType.CURL)); - CLIENT_PATTERNS.add(new Pair<>(Pattern.compile("Apache-HttpClient|okhttp|unirest-java|Java"), ClientType.JAVA)); - CLIENT_PATTERNS.add(new Pair<>(Pattern.compile("node-fetch|axios|got|node"), ClientType.NODE)); - CLIENT_PATTERNS.add(new Pair<>(Pattern.compile("Go-http-client|golang"), ClientType.GOLANG)); - CLIENT_PATTERNS.add(new Pair<>(Pattern.compile("C\\+\\+|cpprestsdk"), ClientType.CPP)); - CLIENT_PATTERNS.add(new Pair<>(Pattern.compile("python-requests|urllib3"), ClientType.PYTHON)); - CLIENT_PATTERNS.add(new Pair<>(Pattern.compile("Cloudflare-Traffic-Manager"), ClientType.CLOUDFLARE)); - } - - public static ClientType findUserAgentType(String userAgentValue) { - if (userAgentValue == null || userAgentValue.isEmpty()) { - return ClientType.CUSTOM; - } - - for (Pair entry : CLIENT_PATTERNS) { - if (entry.getFirst().matcher(userAgentValue).find()) { - return entry.getSecond(); - } - } - - return ClientType.CUSTOM; - } - public static List getClientIpAddresses(HttpServletRequest request) { - List headers = Arrays.asList( - "X-Forwarded-For", - "X-Real-IP", - "Proxy-Client-IP", - "WL-Proxy-Client-IP", - "HTTP_CLIENT_IP", - "HTTP_X_FORWARDED_FOR" - ); + List headers = ApiAccessTypePolicy.CLIENT_IP_HEADERS; List ipAddresses = new ArrayList<>(); diff --git a/libs/utils/src/main/java/com/akto/runtime/policies/ApiAccessTypePolicy.java b/libs/utils/src/main/java/com/akto/runtime/policies/ApiAccessTypePolicy.java index cd6d06caa9..7eea8633fc 100644 --- a/libs/utils/src/main/java/com/akto/runtime/policies/ApiAccessTypePolicy.java +++ b/libs/utils/src/main/java/com/akto/runtime/policies/ApiAccessTypePolicy.java @@ -47,7 +47,7 @@ public ApiAccessTypePolicy(List privateCidrList) { */ ); - static final private List CLIENT_IP_HEADERS = Arrays.asList( + static final public List CLIENT_IP_HEADERS = Arrays.asList( "x-forwarded-for", "x-real-ip", "x-cluster-client-ip", diff --git a/libs/utils/src/main/java/com/akto/runtime/policies/UserAgentTypePolicy.java b/libs/utils/src/main/java/com/akto/runtime/policies/UserAgentTypePolicy.java new file mode 100644 index 0000000000..92833dbb9b --- /dev/null +++ b/libs/utils/src/main/java/com/akto/runtime/policies/UserAgentTypePolicy.java @@ -0,0 +1,41 @@ +package com.akto.runtime.policies; + +import com.akto.util.Pair; + +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Pattern; + +public class UserAgentTypePolicy { + + public enum ClientType { + JAVA, NODE, GOLANG, CPP, PYTHON, MOBILE, BROWSER, CLOUDFLARE, POSTMAN, CURL, CUSTOM + } + private static final List> CLIENT_PATTERNS = new ArrayList<>(); + static { + CLIENT_PATTERNS.add(new Pair<>(Pattern.compile("android|iPhone|iPad"), ClientType.MOBILE)); + CLIENT_PATTERNS.add(new Pair<>(Pattern.compile("Mozilla|Chrome|Safari|Firefox|Edg|AppleWebKit"), ClientType.BROWSER)); + CLIENT_PATTERNS.add(new Pair<>(Pattern.compile("PostmanRuntime"), ClientType.POSTMAN)); + CLIENT_PATTERNS.add(new Pair<>(Pattern.compile("curl"), ClientType.CURL)); + CLIENT_PATTERNS.add(new Pair<>(Pattern.compile("Apache-HttpClient|okhttp|unirest-java|Java"), ClientType.JAVA)); + CLIENT_PATTERNS.add(new Pair<>(Pattern.compile("node-fetch|axios|got|node"), ClientType.NODE)); + CLIENT_PATTERNS.add(new Pair<>(Pattern.compile("Go-http-client|golang"), ClientType.GOLANG)); + CLIENT_PATTERNS.add(new Pair<>(Pattern.compile("C\\+\\+|cpprestsdk"), ClientType.CPP)); + CLIENT_PATTERNS.add(new Pair<>(Pattern.compile("python-requests|urllib3"), ClientType.PYTHON)); + CLIENT_PATTERNS.add(new Pair<>(Pattern.compile("Cloudflare-Traffic-Manager"), ClientType.CLOUDFLARE)); + } + + public static ClientType findUserAgentType(String userAgentValue) { + if (userAgentValue == null || userAgentValue.isEmpty()) { + return ClientType.CUSTOM; + } + + for (Pair entry : CLIENT_PATTERNS) { + if (entry.getFirst().matcher(userAgentValue).find()) { + return entry.getSecond(); + } + } + + return ClientType.CUSTOM; + } +} From e45766985e518f08284d3afa2a15c4b83e5cc829 Mon Sep 17 00:00:00 2001 From: Ark2307 Date: Mon, 21 Oct 2024 15:17:10 +0530 Subject: [PATCH 18/19] Fixing api audit logs dao --- .../com/akto/dao/audit_logs/ApiAuditLogsDao.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/libs/dao/src/main/java/com/akto/dao/audit_logs/ApiAuditLogsDao.java b/libs/dao/src/main/java/com/akto/dao/audit_logs/ApiAuditLogsDao.java index 4a88eea9d4..3fa068a57a 100644 --- a/libs/dao/src/main/java/com/akto/dao/audit_logs/ApiAuditLogsDao.java +++ b/libs/dao/src/main/java/com/akto/dao/audit_logs/ApiAuditLogsDao.java @@ -2,6 +2,7 @@ import com.akto.dao.AccountsContextDao; import com.akto.dao.MCollection; +import com.akto.dao.context.Context; import com.akto.dto.audit_logs.ApiAuditLogs; public class ApiAuditLogsDao extends AccountsContextDao { @@ -11,8 +12,23 @@ public class ApiAuditLogsDao extends AccountsContextDao { private ApiAuditLogsDao() {} public void createIndicesIfAbsent() { + + boolean exists = false; + for (String col: clients[0].getDatabase(Context.accountId.get()+"").listCollectionNames()){ + if (getCollName().equalsIgnoreCase(col)){ + exists = true; + break; + } + }; + + if (!exists) { + clients[0].getDatabase(Context.accountId.get()+"").createCollection(getCollName()); + } + String[] fieldNames = { ApiAuditLogs.TIMESTAMP }; MCollection.createIndexIfAbsent(getDBName(), getCollName(), fieldNames, true); + + fieldNames = new String[]{ApiAuditLogs.USER_EMAIL, ApiAuditLogs.USER_IP_ADDRESS}; } @Override From f184238636d139354c4db1788cae06a0bb21bf44 Mon Sep 17 00:00:00 2001 From: Aryan Khandelwal <60040654+Ark2307@users.noreply.github.com> Date: Mon, 21 Oct 2024 15:29:27 +0530 Subject: [PATCH 19/19] Update ApiAuditLogsDao.java --- .../src/main/java/com/akto/dao/audit_logs/ApiAuditLogsDao.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libs/dao/src/main/java/com/akto/dao/audit_logs/ApiAuditLogsDao.java b/libs/dao/src/main/java/com/akto/dao/audit_logs/ApiAuditLogsDao.java index 3fa068a57a..85e3917c38 100644 --- a/libs/dao/src/main/java/com/akto/dao/audit_logs/ApiAuditLogsDao.java +++ b/libs/dao/src/main/java/com/akto/dao/audit_logs/ApiAuditLogsDao.java @@ -28,7 +28,8 @@ public void createIndicesIfAbsent() { String[] fieldNames = { ApiAuditLogs.TIMESTAMP }; MCollection.createIndexIfAbsent(getDBName(), getCollName(), fieldNames, true); - fieldNames = new String[]{ApiAuditLogs.USER_EMAIL, ApiAuditLogs.USER_IP_ADDRESS}; + fieldNames = new String[]{ApiAuditLogs.USER_EMAIL, ApiAuditLogs.USER_IP_ADDRESS, ApiAuditLogs.TIMESTAMP}; + MCollection.createIndexIfAbsent(getDBName(), getCollName(), fieldNames, true); } @Override