diff --git a/src/main/java/net/siegeln/cameleer/saas/portal/TenantPortalController.java b/src/main/java/net/siegeln/cameleer/saas/portal/TenantPortalController.java index 6cbafb6..91a7a4e 100644 --- a/src/main/java/net/siegeln/cameleer/saas/portal/TenantPortalController.java +++ b/src/main/java/net/siegeln/cameleer/saas/portal/TenantPortalController.java @@ -107,12 +107,8 @@ public class TenantPortalController { @PostMapping("/password") public ResponseEntity changeOwnPassword(@AuthenticationPrincipal Jwt jwt, @RequestBody PasswordChangeRequest body) { - try { - portalService.changePassword(jwt.getSubject(), body.password()); - return ResponseEntity.noContent().build(); - } catch (IllegalArgumentException e) { - return ResponseEntity.badRequest().build(); - } + portalService.changePassword(jwt.getSubject(), body.password()); + return ResponseEntity.noContent().build(); } @PostMapping("/team/{userId}/password") @@ -203,23 +199,15 @@ public class TenantPortalController { if (name == null || name.isBlank()) { return ResponseEntity.badRequest().build(); } - try { - portalService.renamePasskey(jwt.getSubject(), id, name); - return ResponseEntity.noContent().build(); - } catch (IllegalArgumentException e) { - return ResponseEntity.notFound().build(); - } + portalService.renamePasskey(jwt.getSubject(), id, name); + return ResponseEntity.noContent().build(); } @DeleteMapping("/mfa/webauthn/{id}") public ResponseEntity deletePasskey(@AuthenticationPrincipal Jwt jwt, @PathVariable String id) { - try { - portalService.deletePasskey(jwt.getSubject(), id); - return ResponseEntity.noContent().build(); - } catch (IllegalArgumentException e) { - return ResponseEntity.notFound().build(); - } + portalService.deletePasskey(jwt.getSubject(), id); + return ResponseEntity.noContent().build(); } @PostMapping("/mfa/method-preference") diff --git a/src/main/java/net/siegeln/cameleer/saas/vendor/VendorAdminService.java b/src/main/java/net/siegeln/cameleer/saas/vendor/VendorAdminService.java index 7969390..30fa455 100644 --- a/src/main/java/net/siegeln/cameleer/saas/vendor/VendorAdminService.java +++ b/src/main/java/net/siegeln/cameleer/saas/vendor/VendorAdminService.java @@ -2,6 +2,7 @@ package net.siegeln.cameleer.saas.vendor; import net.siegeln.cameleer.saas.account.AccountService; import net.siegeln.cameleer.saas.identity.LogtoManagementClient; +import net.siegeln.cameleer.saas.notification.PasswordResetNotificationService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.http.HttpStatus; @@ -20,13 +21,16 @@ public class VendorAdminService { private final LogtoManagementClient logtoClient; private final AccountService accountService; private final EmailConnectorService emailConnectorService; + private final PasswordResetNotificationService passwordNotificationService; public VendorAdminService(LogtoManagementClient logtoClient, AccountService accountService, - EmailConnectorService emailConnectorService) { + EmailConnectorService emailConnectorService, + PasswordResetNotificationService passwordNotificationService) { this.logtoClient = logtoClient; this.accountService = accountService; this.emailConnectorService = emailConnectorService; + this.passwordNotificationService = passwordNotificationService; } // --- Records --- @@ -107,13 +111,36 @@ public class VendorAdminService { } public void resetAdminPassword(String userId, String newPassword) { + verifyIsVendorAdmin(userId); accountService.validatePassword(newPassword); logtoClient.updateUserPassword(userId, newPassword); log.info("Reset password for vendor admin {}", userId); + + // Send notification email + try { + var user = logtoClient.getUser(userId); + if (user != null) { + String email = String.valueOf(user.getOrDefault("primaryEmail", "")); + if (!email.isBlank()) { + passwordNotificationService.sendNotification(email); + } + } + } catch (Exception e) { + log.warn("Failed to send password reset notification: {}", e.getMessage()); + } } public void resetAdminMfa(String userId) { + verifyIsVendorAdmin(userId); logtoClient.deleteAllMfaVerifications(userId); log.info("Reset MFA for vendor admin {}", userId); } + + private void verifyIsVendorAdmin(String userId) { + boolean isAdmin = listAdmins().stream() + .anyMatch(a -> userId.equals(a.userId())); + if (!isAdmin) { + throw new ResponseStatusException(HttpStatus.NOT_FOUND, "User is not a platform administrator"); + } + } }