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
2 changes: 1 addition & 1 deletion .local.env
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
SENTRIUS_VERSION=1.1.334
SENTRIUS_VERSION=1.1.341
SENTRIUS_SSH_VERSION=1.1.41
SENTRIUS_KEYCLOAK_VERSION=1.1.53
SENTRIUS_AGENT_VERSION=1.1.42
Expand Down
2 changes: 1 addition & 1 deletion .local.env.bak
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
SENTRIUS_VERSION=1.1.334
SENTRIUS_VERSION=1.1.341
SENTRIUS_SSH_VERSION=1.1.41
SENTRIUS_KEYCLOAK_VERSION=1.1.53
SENTRIUS_AGENT_VERSION=1.1.42
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.BooleanNode;
Expand All @@ -15,18 +16,24 @@
import io.sentrius.sso.core.annotations.LimitAccess;
import io.sentrius.sso.core.config.SystemOptions;
import io.sentrius.sso.core.controllers.BaseController;
import io.sentrius.sso.core.dto.HostGroupDTO;
import io.sentrius.sso.core.dto.UserPublicKeyDTO;
import io.sentrius.sso.core.exceptions.ZtatException;
import io.sentrius.sso.core.model.hostgroup.HostGroup;
import io.sentrius.sso.core.model.security.UserType;
import io.sentrius.sso.core.model.security.enums.UserAccessEnum;
import io.sentrius.sso.core.model.users.User;
import io.sentrius.sso.core.dto.UserDTO;
import io.sentrius.sso.core.dto.UserTypeDTO;
import io.sentrius.sso.core.model.users.UserConfig;
import io.sentrius.sso.core.model.users.UserPublicKey;
import io.sentrius.sso.core.model.users.UserSettings;
import io.sentrius.sso.core.services.ConfigurationService;
import io.sentrius.sso.core.services.ErrorOutputService;
import io.sentrius.sso.core.services.HostGroupService;
import io.sentrius.sso.core.services.SessionService;
import io.sentrius.sso.core.services.UserCustomizationService;
import io.sentrius.sso.core.services.UserPublicKeyService;
import io.sentrius.sso.core.services.UserService;
import io.sentrius.sso.core.services.agents.AgentService;
import io.sentrius.sso.core.services.agents.ZeroTrustClientService;
Expand All @@ -45,8 +52,10 @@
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
Expand All @@ -63,6 +72,7 @@ public class UserApiController extends BaseController {
final CryptoService cryptoService;
private final MessagingUtil messagingUtil;
final UserCustomizationService userThemeService;
final UserPublicKeyService userPublicKeyService;
final ZeroTrustRequestService ztatRequestService;
final ZeroTrustAccessTokenService ztatService;
final AgentService agentService;
Expand All @@ -87,6 +97,7 @@ protected UserApiController(
HostGroupService hostGroupService, CryptoService cryptoService,
MessagingUtil messagingUtil,
UserCustomizationService userThemeService,
UserPublicKeyService userPublicKeyService,
SessionService sessionService,
ZeroTrustRequestService ztatRequestService,
ZeroTrustAccessTokenService ztatService, AgentService agentService,
Expand All @@ -97,6 +108,7 @@ protected UserApiController(
this.cryptoService = cryptoService;
this.messagingUtil = messagingUtil;
this.userThemeService = userThemeService;
this.userPublicKeyService = userPublicKeyService;
this.sessionService = sessionService;
this.ztatRequestService = ztatRequestService;
this.ztatService = ztatService;
Expand Down Expand Up @@ -428,5 +440,131 @@ private List<Map<String, Object>> getAgentSessionDurations() {
return agentSessions;
}

// Public Key Management Endpoints

@GetMapping("/publickeys")
public ResponseEntity<List<UserPublicKeyDTO>> getUserPublicKeys(HttpServletRequest request,
HttpServletResponse response) {
var user = userService.getOperatingUser(request, response, null);
var publicKeys = userPublicKeyService.getPublicKeysForUser(user.getId());
List<UserPublicKeyDTO> publicKeyDTOs = new ArrayList<>();
for (UserPublicKey key : publicKeys) {
UserPublicKeyDTO dto = UserPublicKeyDTO.builder().build();
//dto.setId(key.getId());
dto.setKeyName(key.getKeyName());
dto.setKeyType(key.getKeyType());
dto.setPublicKey(key.getPublicKey());
dto.setIsEnabled(key.getIsEnabled());
if (key.getHostGroup() != null) {
dto.setHostGroup( HostGroupDTO.builder().groupId(key.getHostGroup().getId()).build());
//dto.setHostGroupName(key.getHostGroup().getName());
}
publicKeyDTOs.add(dto);
}
return ResponseEntity.ok(publicKeyDTOs);
}

@PostMapping("/publickeys")
public ResponseEntity<ObjectNode> addPublicKey(HttpServletRequest request, HttpServletResponse response, @RequestBody
UserPublicKeyDTO publicKey) {
ObjectNode node = JsonUtil.MAPPER.createObjectNode();
try {

HostGroup hostGroup = hostGroupService.getHostGroup(publicKey.getHostGroup().getGroupId());


UserPublicKey key = new UserPublicKey();
key.setKeyName(publicKey.getKeyName());
key.setKeyType(publicKey.getKeyType());
key.setPublicKey(publicKey.getPublicKey());
key.setIsEnabled(publicKey.getIsEnabled());
if (null != hostGroup) {
key.setHostGroup(hostGroup);
}
var user = userService.getOperatingUser(request, response, null);
key.setUser(user);

if (key.getCreatedAt() == null) {
key.setCreatedAt(new java.sql.Timestamp(System.currentTimeMillis()));
}

var savedKey = userPublicKeyService.addPublicKey(key);
node.put("status", "Public key successfully added");
node.put("id", savedKey.getId());
return ResponseEntity.ok(node);
} catch (Exception e) {
log.error("Error adding public key", e);
node.put("status", "Error adding public key");
return ResponseEntity.internalServerError().body(node);
}
}

@PostMapping("/publickeys/{keyId}/assign")
public ResponseEntity<ObjectNode> assignPublicKeyToHostGroup(
HttpServletRequest request, HttpServletResponse response,
@PathVariable Long keyId, @RequestParam Long hostGroupId) {
ObjectNode node = JsonUtil.MAPPER.createObjectNode();
try {
var user = userService.getOperatingUser(request, response, null);
var publicKeyOpt = userPublicKeyService.getPublicKeyById(keyId);

if (publicKeyOpt.isEmpty()) {
node.put("status", "Public key not found");
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(node);
}

var publicKey = publicKeyOpt.get();

// Verify the key belongs to the current user
if (!publicKey.getUser().getId().equals(user.getId())) {
node.put("status", "Unauthorized");
return ResponseEntity.status(HttpStatus.FORBIDDEN).body(node);
}

var hostGroup = hostGroupService.getHostGroup(hostGroupId);
publicKey.setHostGroup(hostGroup);
userPublicKeyService.addPublicKey(publicKey);

node.put("status", "Public key successfully assigned to host group");
return ResponseEntity.ok(node);
} catch (Exception e) {
log.error("Error assigning public key to host group", e);
node.put("status", "Error assigning public key to host group");
return ResponseEntity.internalServerError().body(node);
}
}

@DeleteMapping("/publickeys/{keyId}")
public ResponseEntity<ObjectNode> deletePublicKey(
HttpServletRequest request, HttpServletResponse response,
@PathVariable Long keyId) {
ObjectNode node = JsonUtil.MAPPER.createObjectNode();
try {
var user = userService.getOperatingUser(request, response, null);
var publicKeyOpt = userPublicKeyService.getPublicKeyById(keyId);

if (publicKeyOpt.isEmpty()) {
node.put("status", "Public key not found");
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(node);
}

var publicKey = publicKeyOpt.get();

// Verify the key belongs to the current user
if (!publicKey.getUser().getId().equals(user.getId())) {
node.put("status", "Unauthorized");
return ResponseEntity.status(HttpStatus.FORBIDDEN).body(node);
}

userPublicKeyService.deletePublicKey(keyId);
node.put("status", "Public key successfully deleted");
return ResponseEntity.ok(node);
} catch (Exception e) {
log.error("Error deleting public key", e);
node.put("status", "Error deleting public key");
return ResponseEntity.internalServerError().body(node);
}
}

}

Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@
import io.sentrius.sso.core.model.users.UserConfig;
import io.sentrius.sso.core.model.users.UserSettings;
import io.sentrius.sso.core.services.ErrorOutputService;
import io.sentrius.sso.core.services.HostGroupService;
import io.sentrius.sso.core.services.UserCustomizationService;
import io.sentrius.sso.core.services.UserPublicKeyService;
import io.sentrius.sso.core.services.UserService;
import io.sentrius.sso.core.services.WorkHoursService;
import io.sentrius.sso.core.services.security.CryptoService;
Expand All @@ -44,16 +46,21 @@
public class UserController extends BaseController {

final UserCustomizationService userThemeService;
final UserPublicKeyService userPublicKeyService;
final HostGroupService hostGroupService;
final WorkHoursService workHoursService;
final CryptoService cryptoService;

protected UserController(
UserService userService, SystemOptions systemOptions,
ErrorOutputService errorOutputService, UserCustomizationService userThemeService, WorkHoursService workHoursService,
CryptoService cryptoService
ErrorOutputService errorOutputService, UserCustomizationService userThemeService,
UserPublicKeyService userPublicKeyService, HostGroupService hostGroupService,
WorkHoursService workHoursService, CryptoService cryptoService
) {
super(userService, systemOptions, errorOutputService);
this.userThemeService = userThemeService;
this.userPublicKeyService = userPublicKeyService;
this.hostGroupService = hostGroupService;
this.workHoursService = workHoursService;
this.cryptoService = cryptoService;
}
Expand Down Expand Up @@ -186,8 +193,16 @@ public String getUserSettings(Model model, HttpServletRequest request, HttpServl
Map<Integer, WorkHours> userWorkHours = workHoursList.stream()
.collect(Collectors.toMap(WorkHours::getDayOfWeek, wh -> wh));

// Get user's public keys
var publicKeys = userPublicKeyService.getPublicKeysForUser(user.getId());

// Get available host groups for this user
var hostGroups = hostGroupService.getHostGroupsForUser(user.getId());

// Pass data to Thymeleaf
model.addAttribute("userWorkHours", userWorkHours);
model.addAttribute("publicKeys", publicKeys);
model.addAttribute("hostGroups", hostGroups);
model.addAttribute("daysOfWeek", List.of(
new DayOfWeekDTO(0, "Sunday"),
new DayOfWeekDTO(1, "Monday"),
Expand Down
Loading