Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
8 changes: 4 additions & 4 deletions .gcp.env
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
SENTRIUS_VERSION=1.0.34
SENTRIUS_SSH_VERSION=1.0.3
SENTRIUS_KEYCLOAK_VERSION=1.0.4
SENTRIUS_AGENT_VERSION=1.0.15
SENTRIUS_VERSION=1.0.37
SENTRIUS_SSH_VERSION=1.0.4
SENTRIUS_KEYCLOAK_VERSION=1.0.6
SENTRIUS_AGENT_VERSION=1.0.16
Original file line number Diff line number Diff line change
@@ -1,40 +1,35 @@
package io.sentrius.agent.analysis.agents.sessions;

import java.nio.charset.StandardCharsets;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Base64;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import com.fasterxml.jackson.core.JsonProcessingException;
import io.sentrius.sso.core.model.categorization.CommandCategory;
import io.sentrius.sso.core.model.metadata.AnalyticsTracking;
import io.sentrius.sso.core.model.metadata.TerminalBehaviorMetrics;
import io.sentrius.sso.core.model.metadata.TerminalCommand;
import io.sentrius.sso.core.model.metadata.TerminalRiskIndicator;
import io.sentrius.sso.core.model.metadata.TerminalSessionMetadata;
import io.sentrius.sso.core.model.metadata.UserExperienceMetrics;
import io.sentrius.sso.core.model.security.IntegrationSecurityToken;
import io.sentrius.sso.core.model.sessions.TerminalLogs;
import io.sentrius.sso.core.repository.AnalyticsTrackingRepository;
import io.sentrius.sso.core.services.IntegrationSecurityTokenService;
import io.sentrius.sso.core.services.PluggableServices;
import io.sentrius.sso.core.services.SessionService;
import io.sentrius.sso.core.services.metadata.TerminalBehaviorMetricsService;
import io.sentrius.sso.core.services.metadata.TerminalCommandService;
import io.sentrius.sso.core.services.metadata.TerminalRiskIndicatorService;
import io.sentrius.sso.core.services.metadata.TerminalSessionMetadataService;
import io.sentrius.sso.core.services.metadata.UserExperienceMetricsService;
import io.sentrius.sso.core.utils.JsonUtil;
import io.sentrius.sso.integrations.external.ExternalIntegrationDTO;
import io.sentrius.sso.security.ApiKey;
import io.sentrius.sso.core.services.openai.categorization.CommandCategorizer;
import jakarta.transaction.Transactional;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.ApplicationContext;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

Expand All @@ -51,6 +46,7 @@ public class SessionAnalyticsAgent {
private final UserExperienceMetricsService experienceMetricsService;
private final AnalyticsTrackingRepository trackingRepository;
private final SessionService sessionService;
private final CommandCategorizer commandCategorizer;
final IntegrationSecurityTokenService integrationSecurityTokenService;


Expand All @@ -61,6 +57,7 @@ public void processSessions() {

// Fetch already processed session IDs in bulk
Set<Long> processedSessionIds = trackingRepository.findAllSessionIds();
log.info("Found {} processed sessions", processedSessionIds.size());
List<TerminalSessionMetadata> unprocessedSessions = sessionMetadataService.getSessionsByState("CLOSED").stream()
.filter(session -> !processedSessionIds.contains(session.getId()))
.collect(Collectors.toList());
Expand All @@ -69,13 +66,13 @@ public void processSessions() {
try {
processSession(session);
// ACTIVE -> INACTIVE -> CLOSED -> PROCESSED
// saveToTracking(session.getId(), "PROCESSED");
saveToTracking(session.getId(), "PROCESSED");
} catch (Exception e) {
log.error("Error processing session {}: {}", session.getId(), e.getMessage(), e);
saveToTracking(session.getId(), "ERROR");
}
// session.setSessionStatus("PROCESSED");
// sessionMetadataService.saveSession(session);
session.setSessionStatus("PROCESSED");
sessionMetadataService.saveSession(session);
}

log.info("Finished processing sessions");
Expand Down Expand Up @@ -185,7 +182,6 @@ public static String extractCommand(TerminalLogs previousLog, String logLine) {
return matcher.group(1).trim();
} else {
if (null != previousLog) {
log.info("Previous log: {}", previousLog.getOutput());
// it could be that we are at the beginning of the log set.
String lastLogLine = getLastLogLine(previousLog);
if (!lastLogLine.isEmpty()) {
Expand Down Expand Up @@ -215,26 +211,20 @@ private static String getLastLogLine(TerminalLogs previousLog) {
}

private TerminalCommand createTerminalCommand(String command, TerminalLogs terminalLog, TerminalSessionMetadata sessionMetadata) {
String encodedString = Base64.getEncoder().encodeToString(command.trim().getBytes(StandardCharsets.UTF_8));

TerminalCommand terminalCommand = new TerminalCommand();
terminalCommand.setCommand(command.trim());
terminalCommand.setCommand(encodedString);
terminalCommand.setSession(sessionMetadata);
terminalCommand.setExecutionTime(new Timestamp(System.currentTimeMillis()));
terminalCommand.setExecutionStatus("SUCCESS");
terminalCommand.setOutput(""); // Assume no output initially
terminalCommand.setCommandCategory(categorizeCommand(command));
terminalCommand.setCommandCategory(categorizeCommand(command).getCategoryName());

return terminalCommand;
}

private String categorizeCommand(String command) {
// probably need to define externally
if (command.startsWith("sudo")) {
return "PRIVILEGED";
} else if (command.contains("rm")) {
return "DESTRUCTIVE";
} else if (command.contains("ls") || command.contains("cat")) {
return "INFORMATIONAL";
}
return "GENERAL";
private CommandCategory categorizeCommand(String command) {
return commandCategorizer.categorizeCommand(command);
}
}
3 changes: 2 additions & 1 deletion analyagents/src/main/resources/application.properties
Original file line number Diff line number Diff line change
Expand Up @@ -61,4 +61,5 @@ spring.security.oauth2.client.provider.keycloak.issuer-uri=http://192.168.1.162:
# for testing analytics agents
agents.session-analytics.enabled=true
management.endpoints.web.exposure.include=health
management.endpoint.health.show-details=always
management.endpoint.health.show-details=always

Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,7 @@ protected List<HostGroup> createHostGroups(List<SideEffect> sideEffects, Map<Str
if (action) {

hostGroup = hostGroupRepository.save(hostGroup);
log.info("Creating Host Group {} with {}", hostGroup.getId(), hostGroupDto.getDisplayName());
log.info("Creating Host Enclave {} with {}", hostGroup.getId(), hostGroupDto.getDisplayName());
profiles.add(hostGroup);
for(var hs : hostGroup.getHostSystems()) {
if (null == hs.getHostGroups()){
Expand All @@ -287,27 +287,27 @@ protected List<HostGroup> createHostGroups(List<SideEffect> sideEffects, Map<Str
systemRepository.save(hs);
}
}
sideEffects.add(SideEffect.builder().sideEffectDescription("Creating Host Group " + hostGroupDto.getDisplayName()).type(
sideEffects.add(SideEffect.builder().sideEffectDescription("Creating Host Enclave " + hostGroupDto.getDisplayName()).type(
SideEffectType.UPDATE_DATABASE).asset("HostGroups").build());
}else {

boolean existsInHostGroup = false;


for(HostGroup hg : hostGroups) {
log.info("Updating Host Group {} with {}", hg.getId(), hg.getId());
log.info("Updating Host Enclave {} with {}", hg.getId(), hg.getId());
profiles.add(hg);

for(var hs : hostGroup.getHostSystems()) {
if (!systemRepository.isAssignedToHostGroups(hs.getId(), List.of( hg.getId()))) {
if (action) {
hs.getHostGroups().add(hg);
systemRepository.save(hs);
log.info("Updating Host Group {} with {}", hg.getId(), hs.getId());
log.info("Updating Host Enclave {} with {}", hg.getId(), hs.getId());
}

sideEffects.add(SideEffect.builder()
.sideEffectDescription("Updating Host Group " + hostGroupDto.getDisplayName()).type(
.sideEffectDescription("Updating Host Enclave " + hostGroupDto.getDisplayName()).type(
SideEffectType.UPDATE_DATABASE).asset("HostGroups").build());
}
}
Expand Down Expand Up @@ -453,10 +453,10 @@ protected List<User> createUsers(


sideEffects.add(SideEffect.builder().sideEffectDescription(
"Assigning user " + userDTO.getUsername() + " to Host Group " +
"Assigning user " + userDTO.getUsername() + " to Host Enclave " +
hostGroup.getName()).type(
SideEffectType.UPDATE_DATABASE).asset("Users").build());
log.info("Assigning user {} to Host Group {}", userDTO.getUsername(),
log.info("Assigning user {} to Host Enclave {}", userDTO.getUsername(),
hostGroup.getId());
user.getHostGroups().add(hostGroup);
}
Expand All @@ -473,15 +473,15 @@ protected List<User> createUsers(
for (var profile : userDTO.getHostGroups()) {
for (HostGroup hostGroup : profiles) {
if (hostGroup.getName().equals(profile.getDisplayName())) {
log.info("Assigning user {} to Host Group {}", userDTO.getUsername(),
log.info("Assigning user {} to Host Enclave {}", userDTO.getUsername(),
hostGroup.getId());
if (null == hostGroup.getId() || !userRepository.isAssignedToHostGroups(user.getId(),
List.of(hostGroup.getId()))) {
sideEffects.add(SideEffect.builder().sideEffectDescription(
"Assigning user " + userDTO.getUsername() + " to Host Group " +
"Assigning user " + userDTO.getUsername() + " to Host Enclave " +
hostGroup.getName()).type(
SideEffectType.UPDATE_DATABASE).asset("Users").build());
log.info("Assigning user {} to Host Group {}", userDTO.getUsername(),
log.info("Assigning user {} to Host Enclave {}", userDTO.getUsername(),
hostGroup.getId()
);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
CREATE TABLE command_categories (
id SERIAL PRIMARY KEY,
category_name VARCHAR(50) NOT NULL,
pattern TEXT NOT NULL, -- Store regex patterns
priority INT NOT NULL DEFAULT 0 -- Optional: for matching precedence
);


CREATE INDEX idx_pattern ON command_categories (pattern);
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
CREATE EXTENSION IF NOT EXISTS pg_trgm;

CREATE INDEX idx_command_pattern_trgm ON command_categories USING gin (pattern gin_trgm_ops);
4 changes: 2 additions & 2 deletions api/src/main/resources/static/js/rules.js
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ $(document).ready(function () {

if (row.canEdit) {
buttons +=
`<button class="btn btn-secondary spacer spacer-middle" data-bs-toggle="modal" data-bs-target="#edit_dialog_${data}" onclick="editRule(${data})">Edit</button><button id="role_btn_${data}" onclick="assignRule(${data})" class="btn btn-secondary assign_btn spacer spacer-right">Assign Host Groups</button>
`<button class="btn btn-secondary spacer spacer-middle" data-bs-toggle="modal" data-bs-target="#edit_dialog_${data}" onclick="editRule(${data})">Edit</button><button id="role_btn_${data}" onclick="assignRule(${data})" class="btn btn-secondary assign_btn spacer spacer-right">Assign Host Enclaves</button>
`;
}

Expand Down Expand Up @@ -165,7 +165,7 @@ $(document).ready(function () {
if (response.ok) {
$('#rule-table').DataTable().ajax.reload(null, false);
} else {
alert("Failed to assign host groups.");
alert("Failed to assign host enclaves.");
}
const modal = bootstrap.Modal.getInstance(document.getElementById("assignHostGroupsModal"));
modal.hide();
Expand Down
10 changes: 5 additions & 5 deletions api/src/main/resources/templates/fragments/assign_rule.html
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
<!-- Assign Host Groups Modal -->
<!-- Assign Host Enclaves Modal -->
<div class="modal fade" id="assignHostGroupsModal" tabindex="-1" aria-labelledby="assignHostGroupsModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<form id="assignHostGroupsForm" method="POST">
<div class="modal-header">
<h5 class="modal-title" id="assignHostGroupsModalLabel">Assign Host Groups</h5>
<h5 class="modal-title" id="assignHostGroupsModalLabel">Assign Host Enclaves</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
Expand All @@ -15,17 +15,17 @@ <h5 class="modal-title" id="assignHostGroupsModalLabel">Assign Host Groups</h5>
<label for="assignRuleName" class="form-label">Rule Name</label>
<input type="text" class="form-control" id="assignRuleName" name="assignRuleName" readonly>
</div>
<!-- Host Groups Multi-select -->
<!-- Host Enclaves Multi-select -->
<div class="mb-3">
<label for="hostGroups" class="form-label">Host Groups</label>
<label for="hostGroups" class="form-label">Host Enclaves</label>
<select name="hostGroups" id="hostGroups" class="form-select" multiple>
<!-- Options will be dynamically populated -->
</select>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
<button type="submit" class="btn btn-primary">Assign Host Groups</button>
<button type="submit" class="btn btn-primary">Assign Host Enclaves</button>
</div>
<!-- CSRF Token -->

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ <h5 class="card-title">Number of assigned hosts</h5>
<i class="fas fa-users card-icon"></i> <!-- Icon for the card -->
</div>
<div class="card-body">
<h5 class="card-title">Number of Host Groups</h5>
<h5 class="card-title">Number of Host Enclaves</h5>
<p class="card-text"><span id="assigned-sgs"></span></p>
</div>
</div>
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<img src="/images/hosts_medium.png" alt="Terminal Icon" class="card-image">
</div>
<div class="card-content">
<h3 class="card-title">Host Groups</h3>
<h3 class="card-title">Host Enclaves</h3>
<div class="card-stats">
<div class="card-stat">
<span>Assigned Systems:</span>
Expand Down
2 changes: 1 addition & 1 deletion api/src/main/resources/templates/fragments/topbar.html
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
<li class="nav-item" th:if="${enclaveList != null && !enclaveList.empty}">
<select th:name="enclaveList" th:onchange="'javascript:changeProfile(this.value)'"
class="form-select view_frm_select" title="Enclave">
<option value="">- Select Host Group -</option>
<option value="">- Select Host Enclave -</option>
<option th:each="p : ${enclaveList}" th:value="${p.id}" th:text="${p.nm}" th:if="${p.selected == true}" selected></option>
<option th:each="p : ${enclaveList}" th:value="${p.id}" th:text="${p.nm}" th:if="${p.selected != true}"></option>
</select>
Expand Down
10 changes: 3 additions & 7 deletions api/src/main/resources/templates/sso/dashboard.html
Original file line number Diff line number Diff line change
Expand Up @@ -428,18 +428,14 @@ <h5 class="card-title">User Operations</h5>
<div id="system-visualizer-card2" class="card custom-dark-card shadow-sm p-3"
style="max-width: 800px; flex: 1;" th:if="${#sets.contains(operatingUser.authorizationType.accessSet, 'CAN_MANAGE_SYSTEMS')}">
<div class="card-header">
<h5 class="card-title">User Operations</h5>
<h5 class="card-title">AI Admin Operations</h5>
</div>
<div class="card-body">
<!-- Buttons -->
<div class="mb-4 d-flex justify-content-center gap-2">
<a href="/api/v1/users/list" class="btn btn-danger">Delete Users</a>
<a href="/api/v1/users/list" class="btn btn-danger">Build Automation</a>
<a href="#" class="btn btn-primary" data-bs-toggle="modal"
data-bs-target="#userFormModal">Add User</a>
<a href="/sso/v1/users/settings" class="btn btn-primary"
th:if="${!#sets.contains(operatingUser.authorizationType.accessSet, 'CAN_VIEW_ZTATS')}">Your Settings</a>
<a href="/sso/v1/zerotrust/accesstoken/list" class="btn btn-primary"
th:if="${#sets.contains(operatingUser.authorizationType.accessSet, 'CAN_VIEW_ZTATS')}">View JITs</a>
data-bs-target="#userFormModal">Usage Patterns</a>
</div>
</div>
</div>
Expand Down
2 changes: 1 addition & 1 deletion api/src/main/resources/templates/sso/ssh/list_servers.html
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ <h3>Assigned SSH Servers</h3>
<tr>
<th>System Name</th>
<th>Hostname</th>
<th>Host Group</th>
<th>Host Enclave</th>
<th>SSH User</th>
<th>Port</th>
<th>Operations</th>
Expand Down
6 changes: 5 additions & 1 deletion core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,11 @@
<artifactId>quartz</artifactId>
<version>${quartz-version}</version>
</dependency>

<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
<version>${caffeine-version}</version>
</dependency>
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>
Expand Down
Loading
Loading