Skip to content

Commit 55da75b

Browse files
committed
fixup initial functionality
1 parent 943de03 commit 55da75b

File tree

8 files changed

+214
-57
lines changed

8 files changed

+214
-57
lines changed

.local.env

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,4 @@ SENTRIUS_AI_AGENT_VERSION=1.1.263
66
LLMPROXY_VERSION=1.0.78
77
LAUNCHER_VERSION=1.0.82
88
AGENTPROXY_VERSION=1.0.85
9-
SSHPROXY_VERSION=1.0.31
9+
SSHPROXY_VERSION=1.0.40

.local.env.bak

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,4 @@ SENTRIUS_AI_AGENT_VERSION=1.1.263
66
LLMPROXY_VERSION=1.0.78
77
LAUNCHER_VERSION=1.0.82
88
AGENTPROXY_VERSION=1.0.85
9-
SSHPROXY_VERSION=1.0.31
9+
SSHPROXY_VERSION=1.0.40

dataplane/src/main/java/io/sentrius/sso/automation/auditing/BaseAccessTokenAuditor.java

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,7 @@
77
import io.sentrius.sso.core.model.users.User;
88

99
public abstract class BaseAccessTokenAuditor {
10-
/*
11-
protected final Long userId;
12-
protected final Long sessionId;
1310

14-
protected final Long systemId;*/
1511
protected final HostSystem system;
1612
protected final SessionLog session;
1713
protected final User user;

dataplane/src/main/java/io/sentrius/sso/core/model/sessions/SessionOutput.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ public Trigger getNextDenial() {
146146
return deny.isEmpty() ? null : deny.pop();
147147
}
148148
*/
149-
public void addJIT(Trigger trg) {
149+
public void addZtat(Trigger trg) {
150150
String message =
151151
"This command will require approval. Your command will not execute until approval is"
152152
+ " garnered.If approval is not already submitted you will be notified when it is"

dataplane/src/main/java/io/sentrius/sso/core/services/SshListenerService.java

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,7 @@ public void stopListeningToSshServer(ConnectedSystem connectedSystem) {
255255
sessionTrackingService.closeSession(connectedSystem);
256256
}
257257

258-
/** Maps key press events to the ascii values */
258+
/** Maps key press events to the ascii values
259259
static Map<Integer, byte[]> keyMap = new HashMap<>();
260260
261261
static {
@@ -273,6 +273,7 @@ public void stopListeningToSshServer(ConnectedSystem connectedSystem) {
273273
keyMap.put(40, new byte[] {(byte) 0x1b, (byte) 0x4f, (byte) 0x42});
274274
// BS
275275
keyMap.put(8, new byte[] {(byte) 0x7f});
276+
keyMap.put(127, new byte[] {(byte) 0x7f}); // DEL
276277
// TAB
277278
keyMap.put(9, new byte[] {(byte) 0x09});
278279
// CTR
@@ -285,6 +286,7 @@ public void stopListeningToSshServer(ConnectedSystem connectedSystem) {
285286
keyMap.put(66, new byte[] {(byte) 0x02});
286287
// CTR-C
287288
keyMap.put(67, new byte[] {(byte) 0x03});
289+
keyMap.put(3, new byte[] {(byte) 0x03});
288290
// CTR-D
289291
keyMap.put(68, new byte[] {(byte) 0x04});
290292
// CTR-E
@@ -345,8 +347,45 @@ public void stopListeningToSshServer(ConnectedSystem connectedSystem) {
345347
keyMap.put(35, "\033[4~".getBytes());
346348
// HOME
347349
keyMap.put(36, "\033[1~".getBytes());
350+
}*/
351+
public static Map<Integer, byte[]> keyMap = new HashMap<>();
352+
static {
353+
// --- Control characters ---
354+
keyMap.put(8, new byte[] {0x08}); // Backspace (^H)
355+
keyMap.put(127,new byte[] {0x7f}); // DEL
356+
keyMap.put(9, new byte[] {0x09}); // Tab
357+
keyMap.put(13, new byte[] {0x0d}); // Enter
358+
359+
// --- Arrow keys (CSI sequences) ---
360+
keyMap.put(37, "\033[D".getBytes()); // Left
361+
keyMap.put(38, "\033[A".getBytes()); // Up
362+
keyMap.put(39, "\033[C".getBytes()); // Right
363+
keyMap.put(40, "\033[B".getBytes()); // Down
364+
365+
// --- Home / End / Insert / Delete / PgUp / PgDn ---
366+
keyMap.put(36, "\033[H".getBytes()); // Home
367+
keyMap.put(35, "\033[F".getBytes()); // End
368+
keyMap.put(45, "\033[2~".getBytes()); // Insert
369+
keyMap.put(46, "\033[3~".getBytes()); // Delete
370+
keyMap.put(33, "\033[5~".getBytes()); // Page Up
371+
keyMap.put(34, "\033[6~".getBytes()); // Page Down
372+
373+
// --- Ctrl + Letter (ASCII 1–26) ---
374+
for (int i = 'A'; i <= 'Z'; i++) {
375+
keyMap.put(i, new byte[] { (byte) (i - 'A' + 1) });
376+
}
377+
// Also allow numeric keyCodes for Ctrl+C from browsers
378+
keyMap.put(3, new byte[] {0x03}); // Ctrl-C
379+
380+
// --- Ctrl-[ and Ctrl-] ---
381+
keyMap.put(219, new byte[] {0x1B}); // Ctrl-[ (Escape)
382+
keyMap.put(221, new byte[] {0x1D}); // Ctrl-]
383+
384+
// --- ESC key ---
385+
keyMap.put(27, new byte[] {0x1B});
348386
}
349387

388+
350389
public void removeSession(String sessionId) {
351390
log.trace("Removing session: {}", sessionId);
352391
activeSessions.remove(sessionId);

dataplane/src/main/java/io/sentrius/sso/core/services/terminal/SessionTrackingService.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,7 @@ public void addTrigger(ConnectedSystem connectedSystem, Trigger trigger) {
242242
case NO_ACTION, WARN_ACTION -> userSessionsOutput.getSessionOutputMap().get(connectedSystem.getSession().getId()).addWarning(trigger);
243243
case PERSISTENT_MESSAGE -> userSessionsOutput.getSessionOutputMap().get(connectedSystem.getSession().getId()).addPersistentMessage(trigger);
244244
case PROMPT_ACTION -> userSessionsOutput.getSessionOutputMap().get(connectedSystem.getSession().getId()).addPrompt(trigger);
245-
case JIT_ACTION -> userSessionsOutput.getSessionOutputMap().get(connectedSystem.getSession().getId()).addJIT(trigger);
245+
case JIT_ACTION -> userSessionsOutput.getSessionOutputMap().get(connectedSystem.getSession().getId()).addZtat(trigger);
246246
case DENY_ACTION -> userSessionsOutput.getSessionOutputMap().get(connectedSystem.getSession().getId()).addDenial(trigger);
247247
}
248248
}

ssh-proxy/src/main/java/io/sentrius/sso/sshproxy/handler/ResponseServiceSession.java

Lines changed: 150 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,13 @@
33
import java.io.IOException;
44
import java.io.InputStream;
55
import java.io.OutputStream;
6+
import java.nio.charset.StandardCharsets;
67
import java.util.Base64;
8+
import io.sentrius.sso.automation.auditing.BaseAccessTokenAuditor;
9+
import io.sentrius.sso.automation.auditing.Trigger;
710
import io.sentrius.sso.core.integrations.ssh.DataSession;
811
import io.sentrius.sso.core.model.ConnectedSystem;
12+
import io.sentrius.sso.core.services.SshListenerService;
913
import io.sentrius.sso.protobuf.Session;
1014
import lombok.extern.slf4j.Slf4j;
1115
import org.springframework.web.socket.TextMessage;
@@ -17,13 +21,24 @@ public class ResponseServiceSession implements DataSession {
1721
private final String sessionId;
1822
private final InputStream in;
1923
private final OutputStream out;
24+
private final BaseAccessTokenAuditor auditor;
2025
private ConnectedSystem connectedSystem;
2126

22-
public ResponseServiceSession(ConnectedSystem connectedSystem, InputStream in, OutputStream out) {
27+
28+
private static final String ANSI_RED = "\u001B[31m";
29+
private static final String ANSI_YELLOW = "\u001B[33m";
30+
private static final String ANSI_GREEN = "\u001B[32m";
31+
private static final String ANSI_BLUE = "\u001B[34m";
32+
private static final String ANSI_RESET = "\u001B[0m";
33+
private static final String ANSI_BOLD = "\u001B[1m";
34+
35+
public ResponseServiceSession(ConnectedSystem connectedSystem, InputStream in,
36+
OutputStream out) {
2337
this.sessionId = connectedSystem.getWebsocketSessionId();
2438
this.connectedSystem = connectedSystem;
2539
this.in = in;
2640
this.out = out;
41+
this.auditor = connectedSystem.getTerminalAuditor();
2742
}
2843
@Override
2944
public String getId() {
@@ -45,11 +60,142 @@ public void sendMessage(WebSocketMessage<?> message) throws IOException {
4560
Session.TerminalMessage auditLog =
4661
Session.TerminalMessage.parseFrom(messageBytes);
4762

48-
log.info("Sending terminal message to session {}: {} {}", sessionId, terminalMessage,
49-
auditLog.getCommand());
50-
out.write(auditLog.getCommandBytes().toByteArray());
63+
var trigger = auditLog.getTrigger();
64+
String msg = "";
65+
switch (trigger.getAction()) {
66+
case DENY_ACTION:
67+
msg = formatDenyMessage(trigger, auditLog);
68+
connectedSystem.getCommander().write(SshListenerService.keyMap.get(3));
69+
connectedSystem.getTerminalAuditor().clear(0); // clear in case
70+
break;
71+
case WARN_ACTION:
72+
msg = formatWarnMessage(trigger, auditLog);
73+
74+
break;
75+
case PROMPT_ACTION:
76+
msg = formatPromptMessage(trigger, auditLog);
77+
break;
78+
case JIT_ACTION:
79+
msg = formatJitMessage(trigger, auditLog);
80+
break;
81+
case RECORD_ACTION:
82+
msg = formatRecordMessage(trigger, auditLog);
83+
break;
84+
85+
case PERSISTENT_MESSAGE:
86+
msg = formatPersistentMessage(trigger, auditLog);
87+
break;
88+
case APPROVE_ACTION:
89+
msg = formatApproveMessage(trigger, auditLog);
90+
break;
91+
case LOG_ACTION:
92+
return ; // Log actions don't show user messages
93+
case ALERT_ACTION:
94+
msg = formatAlertMessage(trigger, auditLog);
95+
break;
96+
default: {
97+
msg = auditLog.getCommand();
98+
break;
99+
}
100+
};
101+
102+
log.info("Sending terminal message to session {}: ",
103+
msg);
104+
out.write(msg.getBytes(StandardCharsets.UTF_8));
51105
out.flush();
52106

107+
108+
53109
}
54110
}
111+
112+
113+
private String formatDenyMessage(Session.Trigger trigger, Session.TerminalMessage auditLog) {
114+
StringBuilder sb = new StringBuilder();
115+
sb.append("\r\n");
116+
sb.append(ANSI_RED).append(ANSI_BOLD).append("⚠ COMMAND BLOCKED ⚠").append(ANSI_RESET).append("\r\n");
117+
sb.append(ANSI_RED).append("Reason: ").append(trigger.getDescription()).append(ANSI_RESET).append("\r\n");
118+
sb.append(ANSI_RED).append("This command has been blocked by security policy.").append(ANSI_RESET).append("\r\n");
119+
sb.append("\r\n");
120+
return sb.toString();
121+
}
122+
123+
private String formatWarnMessage(Session.Trigger trigger, Session.TerminalMessage auditLog) {
124+
StringBuilder sb = new StringBuilder();
125+
sb.append("\r\n");
126+
sb.append(ANSI_YELLOW).append(ANSI_BOLD).append("⚠ WARNING ⚠").append(ANSI_RESET).append("\r\n");
127+
sb.append(ANSI_YELLOW).append("Warning: ").append(trigger.getDescription()).append(ANSI_RESET).append("\r\n");
128+
sb.append("\r\n");
129+
return sb.toString();
130+
}
131+
132+
private String formatPromptMessage(Session.Trigger trigger, Session.TerminalMessage auditLog) {
133+
StringBuilder sb = new StringBuilder();
134+
sb.append("\r\n");
135+
sb.append(ANSI_BLUE).append(ANSI_BOLD).append("📝 PROMPT").append(ANSI_RESET).append("\r\n");
136+
sb.append(ANSI_BLUE).append(trigger.getDescription()).append(ANSI_RESET).append("\r\n");
137+
if (!auditLog.getCommand().isEmpty()) {
138+
sb.append(ANSI_BLUE).append(auditLog.getCommand()).append(" (y/n): ").append(ANSI_RESET);
139+
}
140+
return sb.toString();
141+
}
142+
143+
private String formatJitMessage(Session.Trigger trigger, Session.TerminalMessage auditLog) {
144+
StringBuilder sb = new StringBuilder();
145+
sb.append("\r\n");
146+
sb.append(ANSI_YELLOW).append(ANSI_BOLD).append("🔐 JUST-IN-TIME ACCESS").append(ANSI_RESET).append("\r\n");
147+
sb.append(ANSI_YELLOW).append("Reason: ").append(trigger.getDescription()).append(ANSI_RESET).append("\r\n");
148+
sb.append(ANSI_YELLOW).append("Requesting access...").append(ANSI_RESET).append("\r\n");
149+
sb.append("\r\n");
150+
return sb.toString();
151+
}
152+
153+
private String formatRecordMessage(Session.Trigger trigger, Session.TerminalMessage auditLog) {
154+
StringBuilder sb = new StringBuilder();
155+
sb.append("\r\n");
156+
sb.append(ANSI_GREEN).append(ANSI_BOLD).append("📹 RECORDING").append(ANSI_RESET).append("\r\n");
157+
sb.append(ANSI_GREEN).append("This session is being recorded for audit purposes.").append(ANSI_RESET).append("\r\n");
158+
if (!trigger.getDescription().isEmpty()) {
159+
sb.append(ANSI_GREEN).append("Reason: ").append(trigger.getDescription()).append(ANSI_RESET).append("\r\n");
160+
}
161+
sb.append("\r\n");
162+
return sb.toString();
163+
}
164+
165+
private String formatPersistentMessage(Session.Trigger trigger, Session.TerminalMessage auditLog) {
166+
StringBuilder sb = new StringBuilder();
167+
sb.append("\r\n");
168+
sb.append(ANSI_BLUE).append(ANSI_BOLD).append("💬 MESSAGE").append(ANSI_RESET).append("\r\n");
169+
sb.append(ANSI_BLUE).append(trigger.getDescription()).append(ANSI_RESET).append("\r\n");
170+
sb.append("\r\n");
171+
return sb.toString();
172+
}
173+
174+
private String formatApproveMessage(Session.Trigger trigger, Session.TerminalMessage auditLog) {
175+
StringBuilder sb = new StringBuilder();
176+
sb.append("\r\n");
177+
sb.append(ANSI_GREEN).append(ANSI_BOLD).append("✅ APPROVED").append(ANSI_RESET).append("\r\n");
178+
sb.append(ANSI_GREEN).append(trigger.getDescription()).append(ANSI_RESET).append("\r\n");
179+
sb.append("\r\n");
180+
return sb.toString();
181+
}
182+
183+
private String formatAlertMessage(Session.Trigger trigger, Session.TerminalMessage auditLog) {
184+
StringBuilder sb = new StringBuilder();
185+
sb.append("\r\n");
186+
sb.append(ANSI_RED).append(ANSI_BOLD).append("🚨 ALERT").append(ANSI_RESET).append("\r\n");
187+
sb.append(ANSI_RED).append(trigger.getDescription()).append(ANSI_RESET).append("\r\n");
188+
sb.append("\r\n");
189+
return sb.toString();
190+
}
191+
192+
/**
193+
* Sends a plain message to the terminal
194+
*/
195+
public void sendMessage(String message, OutputStream out) throws IOException {
196+
if (message != null && !message.isEmpty()) {
197+
out.write(message.getBytes());
198+
out.flush();
199+
}
200+
}
55201
}

0 commit comments

Comments
 (0)