Skip to content
Open
Show file tree
Hide file tree
Changes from 19 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ public class AccessTokenAction implements Action, ServletResponseAware, ServletR
public static final String ACCESS_TOKEN_HEADER_NAME = "access-token";
public static final String CONTEXT_SOURCE_HEADER = "x-context-source";
public static final String AKTO_SESSION_TOKEN = "x-akto-session-token";
public static final String SUB_CATEGORY_HEADER = "x-sub-category";

@Override
public String execute() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,8 @@ public class ApiCollectionsAction extends UserAction {
int mcpDataCount;
@Setter
String type;
@Setter
String contextType;
@Getter
List<McpAuditInfo> auditAlerts;

Expand All @@ -116,10 +118,15 @@ public void setApiList(List<ApiInfoKey> apiList) {
* Only populates MCP URLs when dashboard context is not API security.
*/
private void populateCollectionUrls(ApiCollection apiCollection) {
// Do not populate MCP URLs if dashboard context is API security
if (Context.contextSource.get() != null && Context.contextSource.get() == GlobalEnums.CONTEXT_SOURCE.MCP) {
apiCollectionUrlService.populateMcpCollectionUrls(apiCollection);
}else {
try {
// Do not populate MCP URLs if dashboard context is API security
GlobalEnums.CONTEXT_SOURCE contextSource = Context.contextSource.get();
if (contextSource != null && contextSource == GlobalEnums.CONTEXT_SOURCE.MCP) {
apiCollectionUrlService.populateMcpCollectionUrls(apiCollection);
} else {
apiCollection.setUrls(new HashSet<>());
}
} catch (Exception e) {
apiCollection.setUrls(new HashSet<>());
}
}
Expand Down Expand Up @@ -237,7 +244,18 @@ public String fetchApiStats() {
}

public String fetchAllCollectionsBasic() {
UsersCollectionsList.deleteContextCollectionsForUser(Context.accountId.get(), Context.contextSource.get());
try {
// Safely delete context collections for user - handle potential null context source
Integer accountId = Context.accountId.get();
GlobalEnums.CONTEXT_SOURCE contextSource = Context.contextSource.get();
if (accountId != null) {
UsersCollectionsList.deleteContextCollectionsForUser(accountId, contextSource, Context.subCategory.get());
}
} catch (Exception e) {
// Log the error but don't fail the entire request
loggerMaker.errorAndAddToDb(e, "Error deleting context collections for user", LogDb.DASHBOARD);
}

this.apiCollections = ApiCollectionsDao.instance.findAll(Filters.empty(), Projections.exclude("urls"));
this.apiCollections = fillApiCollectionsUrlCount(this.apiCollections, Filters.nin(SingleTypeInfo._API_COLLECTION_ID, deactivatedCollections));
return Action.SUCCESS.toUpperCase();
Expand Down Expand Up @@ -316,7 +334,7 @@ public String createCollection() {

UsersCollectionsList.deleteCollectionIdsFromCache(userId, accountId);
// remove the cache of context collections for account
UsersCollectionsList.deleteContextCollectionsForUser(Context.accountId.get(), Context.contextSource.get());
UsersCollectionsList.deleteContextCollectionsForUser(Context.accountId.get(), Context.contextSource.get(), Context.subCategory.get());
} catch(Exception e){
}

Expand Down Expand Up @@ -385,7 +403,7 @@ public String deleteMultipleCollections() {
UsersCollectionsList.deleteCollectionIdsFromCache(userId, accountId);

// remove the cache of context collections for account
UsersCollectionsList.deleteContextCollectionsForUser(Context.accountId.get(), Context.contextSource.get());
UsersCollectionsList.deleteContextCollectionsForUser(Context.accountId.get(), Context.contextSource.get(), Context.subCategory.get());
} catch (Exception e) {
}

Expand Down Expand Up @@ -1171,7 +1189,9 @@ public String fetchMcpdata() {
Bson mcpTagFilter = Filters.elemMatch(ApiCollection.TAGS_STRING,
Filters.eq("keyName", com.akto.util.Constants.AKTO_MCP_SERVER_TAG)
);

List<ApiCollection> mcpCollections = ApiCollectionsDao.instance.findAll(mcpTagFilter, null);

List<Integer> mcpCollectionIds = mcpCollections.stream().map(ApiCollection::getId).collect(Collectors.toList());

switch (filterType) {
Expand Down Expand Up @@ -1314,11 +1334,13 @@ public String fetchMcpdata() {
Bson guardRailTagFilter = Filters.elemMatch(ApiCollection.TAGS_STRING,
Filters.eq("keyName", Constants.AKTO_GUARD_RAIL_TAG)
);

// Use projection to only fetch IDs, reducing memory usage
List<ApiCollection> guardRailCollections = ApiCollectionsDao.instance.findAll(
guardRailTagFilter,
Projections.include(ApiCollection.ID)
guardRailTagFilter,
Projections.include(ApiCollection.ID)
);

List<Integer> guardRailCollectionIds = guardRailCollections.stream()
.map(ApiCollection::getId)
.collect(Collectors.toList());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ public void doFilter(ServletRequest servletRequest, ServletResponse servletRespo
String accessTokenFromResponse = httpServletResponse.getHeader(AccessTokenAction.ACCESS_TOKEN_HEADER_NAME);
String accessTokenFromRequest = httpServletRequest.getHeader(AccessTokenAction.ACCESS_TOKEN_HEADER_NAME);
String contextSourceFromRequest = httpServletRequest.getHeader(AccessTokenAction.CONTEXT_SOURCE_HEADER);
String subCategoryFromRequest = httpServletRequest.getHeader(AccessTokenAction.SUB_CATEGORY_HEADER);

String aktoSessionTokenFromRequest = httpServletRequest.getHeader(AccessTokenAction.AKTO_SESSION_TOKEN);

Expand All @@ -108,6 +109,18 @@ public void doFilter(ServletRequest servletRequest, ServletResponse servletRespo
}
}

if(!StringUtils.isEmpty(subCategoryFromRequest)) {
if(StringUtils.isEmpty(subCategoryFromRequest)){
Context.subCategory.set(GlobalEnums.SUB_CATEGORY_SOURCE.DEFAULT);
} else {
try {
Context.subCategory.set(GlobalEnums.SUB_CATEGORY_SOURCE.valueOf(subCategoryFromRequest.toUpperCase()));
} catch (Exception e) {
Context.subCategory.set(GlobalEnums.SUB_CATEGORY_SOURCE.DEFAULT);
}
}
}

if(StringUtils.isNotEmpty(aktoSessionTokenFromRequest) && httpServletRequest.getRequestURI().contains("agent")){
try {
Jws<Claims> claims = JwtAuthenticator.authenticate(aktoSessionTokenFromRequest);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,9 @@ export default function Header() {
}

const handleDashboardChange = (value) => {
// Preserve current subcategory selection
const currentSubCategory = PersistStore.getState().subCategory || 'Cloud Security';

PersistStore.getState().setAllCollections([]);
PersistStore.getState().setCollectionsMap({});
PersistStore.getState().setHostNameMap({});
Expand All @@ -126,6 +129,20 @@ export default function Header() {
LocalStore.getState().setCategoryMap({});
LocalStore.getState().setSubCategoryMap({});
SessionStore.getState().setThreatFiltersMap({});

// Set appropriate default subcategory for each dashboard category
if (value === "Agentic Security") {
// For Agentic Security, use Cloud Security as default on first load
const defaultSubCategory = currentSubCategory === 'Default' ? 'Cloud Security' : currentSubCategory;
PersistStore.getState().setSubCategory(defaultSubCategory);
} else if (value === "API Security") {
// For API Security, use Default subcategory (no filtering)
PersistStore.getState().setSubCategory('Default');
} else {
// For other categories, use Default subcategory
PersistStore.getState().setSubCategory('Default');
}

setDashboardCategory(value);
window.location.reload();
window.location.href("/dashboard/observe/inventory")
Expand Down Expand Up @@ -244,7 +261,6 @@ export default function Header() {
<Dropdown
menuItems={[
{ value: "API Security", label: "API Security", id: "api-security" },
{ value: "MCP Security", label: "MCP Security", id: "mcp-security" },
{ value: "Agentic Security", label: "Agentic Security", id: "agentic-security" },
]}
initial={dashboardCategory || "API Security"}
Expand Down
Loading
Loading