Skip to content

Commit ceb6223

Browse files
Copilotphrocker
andauthored
Add RDP support to UI and Windows test container for RDP validation with enhanced deployment options, local environment support, Kubernetes networking compatibility, and robust JavaScript module handling (#11)
* Initial plan * Complete RDP UI support and Windows test container implementation Co-authored-by: phrocker <[email protected]> * Fix RDP form UI based on feedback and add Windows container deployment support Co-authored-by: phrocker <[email protected]> * Fix ingress template validation and local deployment support for RDP proxy Co-authored-by: phrocker <[email protected]> * Fix Windows container networking configuration for Kubernetes deployment Co-authored-by: phrocker <[email protected]> * Fix Windows container port forwarding and JavaScript RDP toggle functionality Co-authored-by: phrocker <[email protected]> * Fix ES6 module scope issue - make toggleRdpFields globally available Co-authored-by: phrocker <[email protected]> * Implement robust ES6 module fix with fallback import handling Co-authored-by: phrocker <[email protected]> * Fixes after testing --------- Co-authored-by: copilot-swe-agent[bot] <[email protected]> Co-authored-by: phrocker <[email protected]> Co-authored-by: Marc Parisi <[email protected]>
1 parent d789879 commit ceb6223

File tree

14 files changed

+347
-33
lines changed

14 files changed

+347
-33
lines changed

.local.env

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
SENTRIUS_VERSION=1.1.413
1+
SENTRIUS_VERSION=1.1.437
22
SENTRIUS_SSH_VERSION=1.1.43
33
SENTRIUS_KEYCLOAK_VERSION=1.1.55
4-
SENTRIUS_AGENT_VERSION=1.1.43
4+
SENTRIUS_AGENT_VERSION=1.1.44
55
SENTRIUS_AI_AGENT_VERSION=1.1.285
66
LLMPROXY_VERSION=1.0.85
77
LAUNCHER_VERSION=1.0.89
88
AGENTPROXY_VERSION=1.0.86
99
SSHPROXY_VERSION=1.0.89
10-
RDPPROXY_VERSION=1.0.2
10+
RDPPROXY_VERSION=1.0.3

.local.env.bak

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
SENTRIUS_VERSION=1.1.413
1+
SENTRIUS_VERSION=1.1.437
22
SENTRIUS_SSH_VERSION=1.1.43
33
SENTRIUS_KEYCLOAK_VERSION=1.1.55
4-
SENTRIUS_AGENT_VERSION=1.1.43
4+
SENTRIUS_AGENT_VERSION=1.1.44
55
SENTRIUS_AI_AGENT_VERSION=1.1.285
66
LLMPROXY_VERSION=1.0.85
77
LAUNCHER_VERSION=1.0.89
88
AGENTPROXY_VERSION=1.0.86
99
SSHPROXY_VERSION=1.0.89
10-
RDPPROXY_VERSION=1.0.2
10+
RDPPROXY_VERSION=1.0.3

api/src/main/java/io/sentrius/sso/controllers/api/HostApiController.java

Lines changed: 42 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,10 @@ public String shutdown() {
7878
}
7979

8080
@GetMapping("/list")
81-
public ResponseEntity<List<HostSystemDTO>> listSSHServers(HttpServletRequest request, HttpServletResponse response,
82-
@RequestParam(name = "groupId", required = false) Long groupId) {
81+
public ResponseEntity<List<HostSystemDTO>> listHostSystems(HttpServletRequest request, HttpServletResponse response,
82+
@RequestParam(name = "groupId", required = false) Long groupId,
83+
@RequestParam(name = "type", required = false,
84+
defaultValue = "SSH") String type) {
8385

8486
var hostSystems = groupId == null ?
8587
hostGroupService.getAssignedHostsForUser(getOperatingUser(request, response)) :
@@ -90,7 +92,22 @@ public ResponseEntity<List<HostSystemDTO>> listSSHServers(HttpServletRequest req
9092
List<HostSystemDTO> hostSystemDTOS = new ArrayList<>();
9193
for(HostSystem hostSystem : hostSystems) {
9294
for(HostGroup hostGroup : hostSystem.getHostGroups()) {
93-
hostSystemDTOS.add(hostSystem.toDTO(hostGroup));
95+
var hs = hostSystem.toDTO(hostGroup);
96+
switch(type){
97+
case "SSH":
98+
if (hs.isRdp()){
99+
continue;
100+
}
101+
break;
102+
case "RDP":
103+
if (!hs.isRdp()){
104+
continue;
105+
}
106+
break;
107+
default:
108+
// do nothing, return all
109+
}
110+
hostSystemDTOS.add(hs);
94111
}
95112

96113
}
@@ -124,7 +141,12 @@ public ResponseEntity<HostSystemDTO> addSSHServer(HttpServletRequest request, Ht
124141
@RequestParam("displayName") String displayName,
125142
@RequestParam("user") String user, @RequestParam("authorizedKeys") String authorizedKeys,
126143
@RequestParam("host") String host,
127-
@RequestParam("port") int port, @RequestParam("sshPassword") String sshPassword) {
144+
@RequestParam("port") int port, @RequestParam("sshPassword") String sshPassword,
145+
@RequestParam(value = "rdpEnabled", defaultValue = "false") boolean rdpEnabled,
146+
@RequestParam(value = "rdpUser", defaultValue = "Administrator") String rdpUser,
147+
@RequestParam(value = "rdpPassword", defaultValue = "") String rdpPassword,
148+
@RequestParam(value = "rdpPort", defaultValue = "3389") int rdpPort,
149+
@RequestParam(value = "rdpDomain", defaultValue = "") String rdpDomain) {
128150

129151

130152
var operatingUser = getOperatingUser(request, response);
@@ -142,19 +164,31 @@ public ResponseEntity<HostSystemDTO> addSSHServer(HttpServletRequest request, Ht
142164
hostGroups.add(hostGroup); // add the newly created host group to the list
143165
}
144166

145-
var hostSystem = HostSystem.builder()
167+
var hostSystemBuilder = HostSystem.builder()
146168
.displayName(displayName)
147169
.sshUser(user)
148170
.authorizedKeys(authorizedKeys)
149171
.host(host)
150172
.sshPassword(sshPassword)
151173
.port(port)
152-
.hostGroups(hostGroups)
153-
.build();
174+
.hostGroups(hostGroups);
175+
176+
// Add RDP configuration if enabled
177+
if (rdpEnabled) {
178+
log.info("Enabling RDP for host system: {}", displayName);
179+
hostSystemBuilder
180+
.rdpEnabled(rdpEnabled)
181+
.rdpUser(rdpUser)
182+
.rdpPassword(rdpPassword)
183+
.rdpPort(rdpPort)
184+
.rdpDomain(rdpDomain);
185+
}
186+
187+
var hostSystem = hostSystemBuilder.build();
154188

155189
hostSystem = hostGroupService.addHost(operatingUser, hostSystem);
156190

157-
log.info("Created host system: {}", hostSystem.getId());
191+
log.info("Created host system: {} with RDP enabled: {}", hostSystem.getId(), rdpEnabled);
158192

159193
/*
160194
HostSystem finalHostSystem = hostSystem;

api/src/main/resources/static/js/add_system.js

Lines changed: 105 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,110 @@
1-
import {countAssignedSystems} from "./functions.js";
2-
console.log("Script loaded"); // This should fire immediately if the script loads
3-
1+
// Handle import failure gracefully by using dynamic import with fallback
2+
let countAssignedSystems = function() {
3+
console.log("Fallback countAssignedSystems function");
4+
};
5+
6+
// Function to toggle RDP configuration fields
7+
function toggleRdpFields() {
8+
console.log("toggleRdpFields called");
9+
const rdpEnabled = document.getElementById('rdpEnabled');
10+
const rdpFields = document.getElementById('rdpFields');
11+
12+
// Add safety checks
13+
if (!rdpEnabled || !rdpFields) {
14+
console.error('RDP elements not found:', {
15+
rdpEnabled: !!rdpEnabled,
16+
rdpFields: !!rdpFields
17+
});
18+
return;
19+
}
20+
21+
const rdpInputs = rdpFields.querySelectorAll('input[type="text"], input[type="password"], input[type="number"]');
22+
23+
// SSH-specific fields that should be hidden when RDP is enabled
24+
const authorizedKeysField = document.getElementById('authorizedKeysField');
25+
const portField = document.getElementById('portField');
26+
const portInput = document.getElementById('port');
27+
28+
if (rdpEnabled.checked) {
29+
rdpFields.style.display = 'block';
30+
31+
// Hide SSH-specific fields
32+
if (authorizedKeysField) {
33+
authorizedKeysField.style.display = 'none';
34+
// Remove required attribute from authorized keys when RDP is enabled
35+
const authorizedKeysInput = document.getElementById('authorizedKeys');
36+
if (authorizedKeysInput) {
37+
authorizedKeysInput.required = false;
38+
}
39+
}
40+
if (portField && portInput) {
41+
portField.style.display = 'none';
42+
// Set port to RDP default and remove required
43+
portInput.value = '3389';
44+
portInput.required = false;
45+
}
46+
47+
// Make RDP fields conditionally required when enabled
48+
rdpInputs.forEach(input => {
49+
if (input.id === 'rdpPassword') {
50+
input.required = true;
51+
}
52+
});
53+
} else {
54+
rdpFields.style.display = 'none';
55+
56+
// Show SSH-specific fields
57+
if (authorizedKeysField) {
58+
authorizedKeysField.style.display = 'block';
59+
const authorizedKeysInput = document.getElementById('authorizedKeys');
60+
if (authorizedKeysInput) {
61+
authorizedKeysInput.required = true;
62+
}
63+
}
64+
if (portField && portInput) {
65+
portField.style.display = 'block';
66+
// Reset port to SSH default and make required
67+
portInput.value = '22';
68+
portInput.required = true;
69+
}
70+
71+
// Remove required attribute when disabled
72+
rdpInputs.forEach(input => {
73+
input.required = false;
74+
});
75+
}
76+
}
77+
78+
// Immediately assign to global scope - don't wait for DOMContentLoaded
79+
window.toggleRdpFields = toggleRdpFields;
80+
console.log("toggleRdpFields assigned to window immediately");
81+
82+
// Try to load the functions module dynamically (non-blocking)
83+
async function loadFunctionsModule() {
84+
try {
85+
const module = await import("./functions.js");
86+
countAssignedSystems = module.countAssignedSystems;
87+
console.log("Successfully loaded functions.js dynamically");
88+
} catch (error) {
89+
console.warn("Could not load functions.js:", error);
90+
// Keep using fallback function
91+
}
92+
}
493

5-
document.addEventListener('DOMContentLoaded', function () {
94+
// Load functions module when DOM is ready, but don't block other functionality
95+
document.addEventListener('DOMContentLoaded', function() {
696
console.log("DOMContentLoaded event fired");
97+
98+
// Load the functions module asynchronously
99+
loadFunctionsModule();
100+
101+
// Debug info for troubleshooting
102+
window.rdpToggleDebug = {
103+
functionExists: typeof toggleRdpFields === 'function',
104+
windowAssignment: typeof window.toggleRdpFields === 'function',
105+
globalAssignment: typeof globalThis.toggleRdpFields === 'function'
106+
};
107+
console.log("Debug info:", window.rdpToggleDebug);
7108

8109
const disableSSHButton = document.getElementById('disable-systems-button');
9110
if (disableSSHButton) {

api/src/main/resources/templates/fragments/add_system.html

Lines changed: 41 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,26 +17,63 @@ <h5 class="modal-title" id="hostFormModalLabel">Add Host Details</h5>
1717
<label for="displayName" class="form-label">Display Name</label>
1818
<input type="text" class="form-control" id="displayName" name="displayName" required>
1919
</div>
20-
<div class="mb-3">
20+
<div class="mb-3" id="userField">
2121
<label for="user" class="form-label">User</label>
2222
<input type="text" class="form-control" id="user" name="user" required>
2323
</div>
24-
<div class="mb-3">
24+
<div class="mb-3" id="sshPasswordField">
2525
<label for="user" class="form-label">User Password</label>
2626
<input type="password" class="form-control" id="sshPassword" name="sshPassword" required>
2727
</div>
28-
<div class="mb-3">
28+
<div class="mb-3" id="authorizedKeysField">
2929
<label for="authorizedKeys" class="form-label">Authorized Keys</label>
3030
<input type="text" class="form-control" id="authorizedKeys" name="authorizedKeys" required>
3131
</div>
3232
<div class="mb-3">
3333
<label for="host" class="form-label">Host</label>
3434
<input type="text" class="form-control" id="host" name="host" required>
3535
</div>
36-
<div class="mb-3">
36+
<div class="mb-3" id="portField">
3737
<label for="port" class="form-label">Port</label>
3838
<input type="number" class="form-control" id="port" name="port" value="22" required>
3939
</div>
40+
41+
<!-- RDP Configuration Toggle -->
42+
<div class="mb-3">
43+
<div class="form-check form-switch">
44+
<input class="form-check-input" type="checkbox" id="rdpEnabled" name="rdpEnabled" onchange="toggleRdpFields()">
45+
<label class="form-check-label" for="rdpEnabled">
46+
Enable RDP Connection
47+
</label>
48+
</div>
49+
</div>
50+
51+
<!-- RDP Configuration Fields (initially hidden) -->
52+
<div id="rdpFields" style="display: none;">
53+
<div class="card">
54+
<div class="card-header">
55+
<h6 class="mb-0">Assigned RDP servers</h6>
56+
</div>
57+
<div class="card-body">
58+
<div class="mb-3">
59+
<label for="rdpUser" class="form-label">RDP Username</label>
60+
<input type="text" class="form-control" id="rdpUser" name="rdpUser" value="Administrator" placeholder="Administrator">
61+
</div>
62+
<div class="mb-3">
63+
<label for="rdpPassword" class="form-label">RDP Password</label>
64+
<input type="password" class="form-control" id="rdpPassword" name="rdpPassword" placeholder="Enter RDP password">
65+
</div>
66+
<div class="mb-3">
67+
<label for="rdpPort" class="form-label">RDP Port</label>
68+
<input type="number" class="form-control" id="rdpPort" name="rdpPort" value="3389" placeholder="3389">
69+
</div>
70+
<div class="mb-3">
71+
<label for="rdpDomain" class="form-label">RDP Domain (Optional)</label>
72+
<input type="text" class="form-control" id="rdpDomain" name="rdpDomain" placeholder="Leave empty for local account">
73+
</div>
74+
</div>
75+
</div>
76+
</div>
4077
</div>
4178
<div class="modal-footer">
4279
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>

api/src/main/resources/templates/sso/enclaves/list_servers.html

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -333,10 +333,10 @@ <h3>Available Agents</h3>
333333
}
334334
]
335335
});
336-
var url = '/api/v1/enclaves/hosts/list';
336+
var url = '/api/v1/enclaves/hosts/list?type=SSH';
337337
console.log("group id: ", groupId);
338338
if (groupId && groupId !== '-1') {
339-
url = `/api/v1/enclaves/hosts/list?groupId=${groupId}`;
339+
url = `/api/v1/enclaves/hosts/list?groupId=${groupId}&type=SSH`;
340340
console.log("url is " + url);
341341
}
342342
let canDelete = [[${#sets.contains(operatingUser.authorizationType.accessSet, 'CAN_DEL_SYSTEMS')}]];
@@ -367,6 +367,35 @@ <h3>Available Agents</h3>
367367

368368
]
369369
});
370+
url = '/api/v1/enclaves/hosts/list?type=RDP';
371+
if (groupId && groupId !== '-1') {
372+
url = `/api/v1/enclaves/hosts/list?groupId=${groupId}&type=RDP`;
373+
console.log("url is " + url);
374+
}
375+
$('#rdp-table').DataTable({
376+
ajax: {
377+
url: url, // list
378+
dataSrc: '', // Specify the property where the data is located (e.g. use 'data' if response has a "data" field)
379+
},
380+
columns: [
381+
{ data: 'displayName' },
382+
{ data: 'displayName' },
383+
{ data: 'group.displayName' },
384+
{ data: 'rdpUser' },
385+
{ data: 'port' },
386+
387+
{
388+
data: null,
389+
render: function(data, type, row) {
390+
const groupId = row.group ? row.group.groupId : -1; // Access group.id
391+
const id = row.id;
392+
let ret=`blah`;
393+
return ret;
394+
}
395+
}
396+
397+
]
398+
});
370399
var agentUrl = '/api/v1/agent/list';
371400
console.log("group id: ", groupId);
372401
if (groupId && groupId !== '-1') {

core/src/main/java/io/sentrius/sso/core/dto/HostSystemDTO.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,8 @@ public class HostSystemDTO {
2525

2626
private String authorizedKeys;
2727

28+
private boolean isRdp;
29+
private boolean rdpUser;
30+
private boolean rdpPassword;
31+
2832
}

dataplane/src/main/java/io/sentrius/sso/core/model/HostSystem.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,11 @@ public HostSystemDTO toDTO() {
151151
dto.displayName(this.displayName);
152152
dto.host(this.host);
153153
dto.statusCd(this.statusCd);
154+
if (rdpEnabled) {
155+
dto.isRdp(true);
156+
dto.rdpUser(rdpUser != null && !rdpUser.isEmpty());
157+
dto.rdpPassword(rdpPassword != null && !rdpPassword.isEmpty());
158+
}
154159
dto.publicKeyList(this.publicKeyList != null ? new ArrayList<>(this.publicKeyList) : new ArrayList<>());
155160
dto.errorMsg(this.errorMsg);
156161
dto.port(this.port);
@@ -168,6 +173,11 @@ public HostSystemDTO toDTO(HostGroup hg) {
168173
dto.displayName(this.displayName);
169174
dto.host(this.host);
170175
dto.statusCd(this.statusCd);
176+
if (rdpEnabled) {
177+
dto.isRdp(true);
178+
dto.rdpUser(rdpUser != null && !rdpUser.isEmpty());
179+
dto.rdpPassword(rdpPassword != null && !rdpPassword.isEmpty());
180+
}
171181
dto.publicKeyList(this.publicKeyList != null ? new ArrayList<>(this.publicKeyList) : new ArrayList<>());
172182
dto.errorMsg(this.errorMsg);
173183
dto.port(this.port);

0 commit comments

Comments
 (0)