Skip to content

Commit

Permalink
Merge pull request #1613 from akto-api-security/feature/audit_logs
Browse files Browse the repository at this point in the history
Feature/audit logs
  • Loading branch information
avneesh-akto authored Oct 21, 2024
2 parents 08da57a + f184238 commit 216cb61
Show file tree
Hide file tree
Showing 18 changed files with 768 additions and 52 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
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;
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> apiAuditLogs;
private long totalAuditLogs;
public String fetchApiAuditLogsFromDb() {
User user = getSUser();
if(user == null) return ERROR.toUpperCase();

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<ApiAuditLogs> 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;
}
}
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -12,13 +16,18 @@
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;
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.List;
import java.util.Map;

public class RoleAccessInterceptor extends AbstractInterceptor {
Expand All @@ -27,6 +36,7 @@ public class RoleAccessInterceptor extends AbstractInterceptor {

String featureLabel;
String accessType;
String actionDescription;

public void setFeatureLabel(String featureLabel) {
this.featureLabel = featureLabel;
Expand All @@ -36,6 +46,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";
Expand Down Expand Up @@ -67,7 +81,9 @@ private int getUserAccountId (Map<String, Object> session) throws Exception{

@Override
public String intercept(ActionInvocation invocation) throws Exception {
ApiAuditLogs apiAuditLogs = null;
try {
HttpServletRequest request = ServletActionContext.getRequest();

if(featureLabel == null) {
throw new Exception("Feature list is null or empty");
Expand Down Expand Up @@ -111,17 +127,44 @@ public String intercept(ActionInvocation invocation) throws Exception {
if(this.accessType.equalsIgnoreCase(ReadWriteAccess.READ.toString()) || 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;
}

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");
UserAgentTypePolicy.ClientType userAgentType = UserAgentTypePolicy.findUserAgentType(userAgent);
List<String> userProxyIpAddresses = AuditLogsUtil.getClientIpAddresses(request);
String userIpAddress = userProxyIpAddresses.get(0);

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);
}

} catch(Exception e) {
String api = invocation.getProxy().getActionName();
String error = "Error in RoleInterceptor for api: " + api + " ERROR: " + e.getMessage();
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;
}
}
Loading

0 comments on commit 216cb61

Please sign in to comment.