Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d5a8acc0fa | ||
|
|
028a26189d | ||
|
|
588a31f7ad | ||
|
|
f9f052b4c3 | ||
|
|
f33452c2a0 | ||
|
|
1071873be3 | ||
|
|
3e7606f2f7 | ||
|
|
5adb79aa3e |
@ -17,7 +17,6 @@ import com.fasterxml.jackson.databind.JsonNode;
|
|||||||
import com.knecon.fforesight.tenantcommons.model.TenantResponse;
|
import com.knecon.fforesight.tenantcommons.model.TenantResponse;
|
||||||
import com.knecon.fforesight.tenantcommons.model.UpdateDetailsRequest;
|
import com.knecon.fforesight.tenantcommons.model.UpdateDetailsRequest;
|
||||||
import com.knecon.fforesight.tenantusermanagement.model.DeploymentKeyResponse;
|
import com.knecon.fforesight.tenantusermanagement.model.DeploymentKeyResponse;
|
||||||
import com.knecon.fforesight.tenantusermanagement.model.SimpleTenantResponse;
|
|
||||||
import com.knecon.fforesight.tenantusermanagement.model.CreateTenantRequest;
|
import com.knecon.fforesight.tenantusermanagement.model.CreateTenantRequest;
|
||||||
import com.knecon.fforesight.tenantusermanagement.model.UpdateTenantRequest;
|
import com.knecon.fforesight.tenantusermanagement.model.UpdateTenantRequest;
|
||||||
|
|
||||||
@ -43,8 +42,7 @@ public interface TenantsResource {
|
|||||||
@ResponseBody
|
@ResponseBody
|
||||||
@ResponseStatus(value = HttpStatus.NO_CONTENT)
|
@ResponseStatus(value = HttpStatus.NO_CONTENT)
|
||||||
@Operation(summary = "Deletes given tenant", description = "None")
|
@Operation(summary = "Deletes given tenant", description = "None")
|
||||||
@ApiResponses(value = {@ApiResponse(responseCode = "204", description = "OK"), @ApiResponse(responseCode = "403", description = "Forbidden access, you dont have rights to delete tenants"), @ApiResponse(responseCode = "405", description = "Operation is not allowed."),
|
@ApiResponses(value = {@ApiResponse(responseCode = "204", description = "OK"), @ApiResponse(responseCode = "403", description = "Forbidden access, you dont have rights to delete tenants"), @ApiResponse(responseCode = "405", description = "Operation is not allowed."), @ApiResponse(responseCode = "409", description = "Conflict while deleting tenant.")})
|
||||||
@ApiResponse(responseCode = "409", description = "Conflict while deleting tenant.")})
|
|
||||||
@DeleteMapping(value = TENANTS_TENANT_ID_PATH)
|
@DeleteMapping(value = TENANTS_TENANT_ID_PATH)
|
||||||
void deleteTenant(@PathVariable("tenantId") String tenantId);
|
void deleteTenant(@PathVariable("tenantId") String tenantId);
|
||||||
|
|
||||||
@ -73,12 +71,6 @@ public interface TenantsResource {
|
|||||||
void updateDetails(@PathVariable("tenantId") String tenantId, @RequestBody UpdateDetailsRequest request);
|
void updateDetails(@PathVariable("tenantId") String tenantId, @RequestBody UpdateDetailsRequest request);
|
||||||
|
|
||||||
|
|
||||||
@GetMapping(value = TENANTS_PATH + "/simple", produces = MediaType.APPLICATION_JSON_VALUE)
|
|
||||||
@Operation(summary = "Gets all existing tenants in a simplified format", description = "None")
|
|
||||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK")})
|
|
||||||
List<SimpleTenantResponse> getSimpleTenants();
|
|
||||||
|
|
||||||
|
|
||||||
@GetMapping(value = "/deploymentKey" + TENANT_ID_PATH_PARAM, produces = MediaType.APPLICATION_JSON_VALUE)
|
@GetMapping(value = "/deploymentKey" + TENANT_ID_PATH_PARAM, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||||
@Operation(summary = "Returns the deployment key for a tenant", description = "None")
|
@Operation(summary = "Returns the deployment key for a tenant", description = "None")
|
||||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK")})
|
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK")})
|
||||||
|
|||||||
@ -15,7 +15,6 @@ import com.fasterxml.jackson.databind.JsonNode;
|
|||||||
import com.knecon.fforesight.tenantcommons.model.TenantResponse;
|
import com.knecon.fforesight.tenantcommons.model.TenantResponse;
|
||||||
import com.knecon.fforesight.tenantcommons.model.UpdateDetailsRequest;
|
import com.knecon.fforesight.tenantcommons.model.UpdateDetailsRequest;
|
||||||
import com.knecon.fforesight.tenantusermanagement.model.DeploymentKeyResponse;
|
import com.knecon.fforesight.tenantusermanagement.model.DeploymentKeyResponse;
|
||||||
import com.knecon.fforesight.tenantusermanagement.model.SimpleTenantResponse;
|
|
||||||
import com.knecon.fforesight.tenantusermanagement.model.CreateTenantRequest;
|
import com.knecon.fforesight.tenantusermanagement.model.CreateTenantRequest;
|
||||||
import com.knecon.fforesight.tenantusermanagement.model.UpdateTenantRequest;
|
import com.knecon.fforesight.tenantusermanagement.model.UpdateTenantRequest;
|
||||||
|
|
||||||
@ -60,12 +59,6 @@ public interface InternalTenantsResource {
|
|||||||
TenantResponse updateTenant(@PathVariable("tenantId") String tenantId, @RequestBody UpdateTenantRequest tenantRequest);
|
TenantResponse updateTenant(@PathVariable("tenantId") String tenantId, @RequestBody UpdateTenantRequest tenantRequest);
|
||||||
|
|
||||||
|
|
||||||
@GetMapping(value = "/tenants/simple", produces = MediaType.APPLICATION_JSON_VALUE)
|
|
||||||
@Operation(summary = "Gets all existing tenant in a simplified format", description = "None")
|
|
||||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK")})
|
|
||||||
List<SimpleTenantResponse> getSimpleTenants();
|
|
||||||
|
|
||||||
|
|
||||||
@GetMapping(value = "/deploymentKey" + TENANT_ID_PATH_PARAM, produces = MediaType.APPLICATION_JSON_VALUE)
|
@GetMapping(value = "/deploymentKey" + TENANT_ID_PATH_PARAM, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||||
@Operation(summary = "Returns the deployment key for a tenant", description = "None")
|
@Operation(summary = "Returns the deployment key for a tenant", description = "None")
|
||||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK")})
|
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK")})
|
||||||
|
|||||||
@ -53,7 +53,7 @@ public class SMTPConfigurationController implements SMTPConfigurationResource, P
|
|||||||
throw new BadRequestException("Current license does not allow updating the SMTP configuration!");
|
throw new BadRequestException("Current license does not allow updating the SMTP configuration!");
|
||||||
}
|
}
|
||||||
|
|
||||||
smtpService.updateSMTPConfiguration(smtpConfigurationModel, TenantContext.getTenantId());
|
smtpService.updateSMTPConfiguration(smtpConfigurationModel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -84,7 +84,7 @@ public class SMTPConfigurationController implements SMTPConfigurationResource, P
|
|||||||
@PreAuthorize("hasAuthority('" + WRITE_SMTP_CONFIGURATION + "')")
|
@PreAuthorize("hasAuthority('" + WRITE_SMTP_CONFIGURATION + "')")
|
||||||
public void clearSMTPConfiguration() {
|
public void clearSMTPConfiguration() {
|
||||||
|
|
||||||
smtpService.clearSMTPConfiguration();
|
smtpService.createDefaultSMTPConfiguration();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -22,7 +22,6 @@ import com.knecon.fforesight.tenantcommons.model.UpdateDetailsRequest;
|
|||||||
import com.knecon.fforesight.tenantusermanagement.api.external.PublicResource;
|
import com.knecon.fforesight.tenantusermanagement.api.external.PublicResource;
|
||||||
import com.knecon.fforesight.tenantusermanagement.api.external.TenantsResource;
|
import com.knecon.fforesight.tenantusermanagement.api.external.TenantsResource;
|
||||||
import com.knecon.fforesight.tenantusermanagement.model.DeploymentKeyResponse;
|
import com.knecon.fforesight.tenantusermanagement.model.DeploymentKeyResponse;
|
||||||
import com.knecon.fforesight.tenantusermanagement.model.SimpleTenantResponse;
|
|
||||||
import com.knecon.fforesight.tenantusermanagement.model.CreateTenantRequest;
|
import com.knecon.fforesight.tenantusermanagement.model.CreateTenantRequest;
|
||||||
import com.knecon.fforesight.tenantusermanagement.model.UpdateTenantRequest;
|
import com.knecon.fforesight.tenantusermanagement.model.UpdateTenantRequest;
|
||||||
import com.knecon.fforesight.tenantusermanagement.service.DeploymentKeyService;
|
import com.knecon.fforesight.tenantusermanagement.service.DeploymentKeyService;
|
||||||
@ -77,12 +76,6 @@ public class TenantsController implements TenantsResource, PublicResource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public List<SimpleTenantResponse> getSimpleTenants() {
|
|
||||||
|
|
||||||
return tenantManagementService.getTenants().stream().map(t -> new SimpleTenantResponse(t.getTenantId(), t.getDisplayName(), t.getGuid())).toList();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@PreAuthorize("hasAuthority('" + UPDATE_TENANT + "')")
|
@PreAuthorize("hasAuthority('" + UPDATE_TENANT + "')")
|
||||||
public TenantResponse updateTenant(String tenantId, @RequestBody UpdateTenantRequest tenantRequest) {
|
public TenantResponse updateTenant(String tenantId, @RequestBody UpdateTenantRequest tenantRequest) {
|
||||||
|
|
||||||
|
|||||||
@ -13,9 +13,8 @@ import com.knecon.fforesight.tenantcommons.model.TenantResponse;
|
|||||||
import com.knecon.fforesight.tenantcommons.model.UpdateDetailsRequest;
|
import com.knecon.fforesight.tenantcommons.model.UpdateDetailsRequest;
|
||||||
import com.knecon.fforesight.tenantusermanagement.api.internal.InternalResource;
|
import com.knecon.fforesight.tenantusermanagement.api.internal.InternalResource;
|
||||||
import com.knecon.fforesight.tenantusermanagement.api.internal.InternalTenantsResource;
|
import com.knecon.fforesight.tenantusermanagement.api.internal.InternalTenantsResource;
|
||||||
import com.knecon.fforesight.tenantusermanagement.model.DeploymentKeyResponse;
|
|
||||||
import com.knecon.fforesight.tenantusermanagement.model.SimpleTenantResponse;
|
|
||||||
import com.knecon.fforesight.tenantusermanagement.model.CreateTenantRequest;
|
import com.knecon.fforesight.tenantusermanagement.model.CreateTenantRequest;
|
||||||
|
import com.knecon.fforesight.tenantusermanagement.model.DeploymentKeyResponse;
|
||||||
import com.knecon.fforesight.tenantusermanagement.model.UpdateTenantRequest;
|
import com.knecon.fforesight.tenantusermanagement.model.UpdateTenantRequest;
|
||||||
import com.knecon.fforesight.tenantusermanagement.service.DeploymentKeyService;
|
import com.knecon.fforesight.tenantusermanagement.service.DeploymentKeyService;
|
||||||
import com.knecon.fforesight.tenantusermanagement.service.TenantManagementService;
|
import com.knecon.fforesight.tenantusermanagement.service.TenantManagementService;
|
||||||
@ -67,12 +66,6 @@ public class InternalTenantsController implements InternalTenantsResource, Inter
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public List<SimpleTenantResponse> getSimpleTenants() {
|
|
||||||
|
|
||||||
return tenantManagementService.getTenants().stream().map(t -> new SimpleTenantResponse(t.getTenantId(), t.getDisplayName(), t.getGuid())).toList();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public DeploymentKeyResponse getDeploymentKey(@PathVariable(TENANT_ID_PARAM) String tenantId) {
|
public DeploymentKeyResponse getDeploymentKey(@PathVariable(TENANT_ID_PARAM) String tenantId) {
|
||||||
|
|
||||||
return new DeploymentKeyResponse(deploymentKeyService.getDeploymentKey(tenantId));
|
return new DeploymentKeyResponse(deploymentKeyService.getDeploymentKey(tenantId));
|
||||||
|
|||||||
@ -0,0 +1,60 @@
|
|||||||
|
package com.knecon.fforesight.tenantusermanagement.entity;
|
||||||
|
|
||||||
|
import jakarta.persistence.Column;
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.Id;
|
||||||
|
import jakarta.persistence.Table;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
@Table(name = "global_smtp_configuration")
|
||||||
|
public class GlobalSMTPConfigurationEntity {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@Column(nullable = false, updatable = false)
|
||||||
|
private String id = "singleton";
|
||||||
|
|
||||||
|
@Column
|
||||||
|
private Boolean auth;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
private String envelopeFrom;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
private String fromEmail;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
private String fromDisplayName;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
private String host;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
private String password;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
private Integer port;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
private String replyTo;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
private String replyToDisplayName;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
private Boolean ssl;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
private Boolean starttls;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
private String userName;
|
||||||
|
}
|
||||||
|
|
||||||
@ -1,23 +0,0 @@
|
|||||||
package com.knecon.fforesight.tenantusermanagement.model;
|
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.Builder;
|
|
||||||
import lombok.Data;
|
|
||||||
import lombok.NoArgsConstructor;
|
|
||||||
|
|
||||||
@Data
|
|
||||||
@Builder
|
|
||||||
@AllArgsConstructor
|
|
||||||
@NoArgsConstructor
|
|
||||||
@Schema(description = "Object containing a simplified version of the tenant data.")
|
|
||||||
public class SimpleTenantResponse {
|
|
||||||
|
|
||||||
@Schema(description = "Parameter containing the ID of the tenant.")
|
|
||||||
private String tenantId;
|
|
||||||
@Schema(description = "Parameter containing the display name of the tenant.")
|
|
||||||
private String displayName;
|
|
||||||
@Schema(description = "Parameter containing the global unique ID of the tenant.")
|
|
||||||
private String guid;
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -0,0 +1,15 @@
|
|||||||
|
package com.knecon.fforesight.tenantusermanagement.repository;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
|
||||||
|
import com.knecon.fforesight.tenantusermanagement.entity.GlobalSMTPConfigurationEntity;
|
||||||
|
|
||||||
|
public interface GlobalSMTPConfigurationRepository extends JpaRepository<GlobalSMTPConfigurationEntity, String> {
|
||||||
|
|
||||||
|
default Optional<GlobalSMTPConfigurationEntity> findSingleton() {
|
||||||
|
|
||||||
|
return findById("singleton");
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,52 @@
|
|||||||
|
package com.knecon.fforesight.tenantusermanagement.service;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.springframework.core.env.Environment;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import com.knecon.fforesight.tenantusermanagement.model.SMTPConfiguration;
|
||||||
|
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class EnvironmentSMTPConfigurationProvider {
|
||||||
|
|
||||||
|
private final Environment environment;
|
||||||
|
|
||||||
|
public static final Integer KEYCLOAK_DEFAULT_PORT = 25;
|
||||||
|
public static final String SMTP_DEFAULT_HOST = "SMTP_DEFAULT_HOST";
|
||||||
|
public static final String SMTP_DEFAULT_PORT = "SMTP_DEFAULT_PORT";
|
||||||
|
public static final String SMTP_DEFAULT_SENDER_EMAIL = "SMTP_DEFAULT_SENDER_EMAIL";
|
||||||
|
public static final String SMTP_DEFAULT_SENDER_NAME = "SMTP_DEFAULT_SENDER_NAME";
|
||||||
|
public static final String SMTP_DEFAULT_REPLY_EMAIL = "SMTP_DEFAULT_REPLY_EMAIL";
|
||||||
|
public static final String SMTP_DEFAULT_REPLY_NAME = "SMTP_DEFAULT_REPLY_NAME";
|
||||||
|
public static final String SMTP_DEFAULT_SENDER_ENVELOPE = "SMTP_DEFAULT_SENDER_ENVELOPE";
|
||||||
|
public static final String SMTP_DEFAULT_SSL = "SMTP_DEFAULT_SSL";
|
||||||
|
public static final String SMTP_DEFAULT_STARTTLS = "SMTP_DEFAULT_STARTTLS";
|
||||||
|
public static final String SMTP_DEFAULT_AUTH = "SMTP_DEFAULT_AUTH";
|
||||||
|
public static final String SMTP_DEFAULT_AUTH_USER = "SMTP_DEFAULT_AUTH_USER";
|
||||||
|
public static final String SMTP_DEFAULT_AUTH_PASSWORD = "SMTP_DEFAULT_AUTH_PASSWORD";
|
||||||
|
|
||||||
|
|
||||||
|
public SMTPConfiguration get() {
|
||||||
|
|
||||||
|
String port = environment.getProperty(SMTP_DEFAULT_PORT, "");
|
||||||
|
return SMTPConfiguration.builder()
|
||||||
|
.id("singleton")
|
||||||
|
.host(environment.getProperty(SMTP_DEFAULT_HOST, ""))
|
||||||
|
.port(StringUtils.isEmpty(port) || !StringUtils.isNumeric(port) ? KEYCLOAK_DEFAULT_PORT : Integer.parseInt(port))
|
||||||
|
.from(environment.getProperty(SMTP_DEFAULT_SENDER_EMAIL, ""))
|
||||||
|
.fromDisplayName(environment.getProperty(SMTP_DEFAULT_SENDER_NAME, ""))
|
||||||
|
.replyTo(environment.getProperty(SMTP_DEFAULT_REPLY_EMAIL, ""))
|
||||||
|
.replyToDisplayName(environment.getProperty(SMTP_DEFAULT_REPLY_NAME, ""))
|
||||||
|
.envelopeFrom(environment.getProperty(SMTP_DEFAULT_SENDER_ENVELOPE, ""))
|
||||||
|
.ssl(Boolean.parseBoolean(environment.getProperty(SMTP_DEFAULT_SSL, "false")))
|
||||||
|
.starttls(Boolean.parseBoolean(environment.getProperty(SMTP_DEFAULT_STARTTLS, "false")))
|
||||||
|
.auth(Boolean.parseBoolean(environment.getProperty(SMTP_DEFAULT_AUTH, "false")))
|
||||||
|
.user(environment.getProperty(SMTP_DEFAULT_AUTH_USER, ""))
|
||||||
|
.password(environment.getProperty(SMTP_DEFAULT_AUTH_PASSWORD, ""))
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,37 @@
|
|||||||
|
package com.knecon.fforesight.tenantusermanagement.service;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import com.knecon.fforesight.tenantusermanagement.entity.GlobalSMTPConfigurationEntity;
|
||||||
|
import com.knecon.fforesight.tenantusermanagement.repository.GlobalSMTPConfigurationRepository;
|
||||||
|
|
||||||
|
import lombok.AccessLevel;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.experimental.FieldDefaults;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true)
|
||||||
|
public class GlobalSMTPConfigurationPersistenceService {
|
||||||
|
|
||||||
|
GlobalSMTPConfigurationRepository smtpConfigurationRepository;
|
||||||
|
|
||||||
|
|
||||||
|
@Transactional(readOnly = true)
|
||||||
|
public Optional<GlobalSMTPConfigurationEntity> get() {
|
||||||
|
|
||||||
|
return smtpConfigurationRepository.findSingleton();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
public GlobalSMTPConfigurationEntity createUpdate(GlobalSMTPConfigurationEntity smtpConfiguration) {
|
||||||
|
|
||||||
|
smtpConfiguration.setId("singleton");
|
||||||
|
return smtpConfigurationRepository.save(smtpConfiguration);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,34 +1,41 @@
|
|||||||
package com.knecon.fforesight.tenantusermanagement.service;
|
package com.knecon.fforesight.tenantusermanagement.service;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.springframework.core.env.Environment;
|
import org.springframework.boot.context.event.ApplicationReadyEvent;
|
||||||
|
import org.springframework.context.event.EventListener;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import com.fasterxml.jackson.core.type.TypeReference;
|
import com.fasterxml.jackson.core.type.TypeReference;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.license.Feature;
|
import com.iqser.red.service.persistence.service.v1.api.shared.model.license.Feature;
|
||||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.license.License;
|
|
||||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.license.RedactionLicenseModel;
|
import com.iqser.red.service.persistence.service.v1.api.shared.model.license.RedactionLicenseModel;
|
||||||
import com.knecon.fforesight.tenantcommons.EncryptionDecryptionService;
|
import com.knecon.fforesight.tenantcommons.EncryptionDecryptionService;
|
||||||
import com.knecon.fforesight.tenantcommons.TenantContext;
|
import com.knecon.fforesight.tenantcommons.TenantContext;
|
||||||
import com.knecon.fforesight.tenantusermanagement.client.LicenseClient;
|
import com.knecon.fforesight.tenantusermanagement.client.LicenseClient;
|
||||||
|
import com.knecon.fforesight.tenantusermanagement.entity.GlobalSMTPConfigurationEntity;
|
||||||
|
import com.knecon.fforesight.tenantusermanagement.entity.TenantEntity;
|
||||||
import com.knecon.fforesight.tenantusermanagement.model.SMTPConfiguration;
|
import com.knecon.fforesight.tenantusermanagement.model.SMTPConfiguration;
|
||||||
|
import com.knecon.fforesight.tenantusermanagement.repository.TenantRepository;
|
||||||
|
import com.knecon.fforesight.tenantusermanagement.utils.SMTPConfigurationMapper;
|
||||||
|
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
@RequiredArgsConstructor
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
|
@RequiredArgsConstructor
|
||||||
public class SMTPService {
|
public class SMTPService {
|
||||||
|
|
||||||
private final Environment environment;
|
private final GlobalSMTPConfigurationPersistenceService smtpConfigurationPersistenceService;
|
||||||
|
private final EnvironmentSMTPConfigurationProvider environmentSMTPConfigurationProvider;
|
||||||
private final LicenseClient licenseClient;
|
private final LicenseClient licenseClient;
|
||||||
private final RealmService realmService;
|
private final RealmService realmService;
|
||||||
|
private final TenantRepository tenantRepository;
|
||||||
|
|
||||||
private final EncryptionDecryptionService encryptionDecryptionService;
|
private final EncryptionDecryptionService encryptionDecryptionService;
|
||||||
|
|
||||||
@ -36,22 +43,121 @@ public class SMTPService {
|
|||||||
|
|
||||||
private final static String SMTP_PASSWORD_KEY = "FFORESIGHT_SMTP_PASSWORD";
|
private final static String SMTP_PASSWORD_KEY = "FFORESIGHT_SMTP_PASSWORD";
|
||||||
private final static String DEFAULT_PASSWORD = "**********";
|
private final static String DEFAULT_PASSWORD = "**********";
|
||||||
|
|
||||||
public static final String SMTP_DEFAULT_HOST = "SMTP_DEFAULT_HOST";
|
|
||||||
public static final String SMTP_DEFAULT_PORT = "SMTP_DEFAULT_PORT";
|
|
||||||
public static final String SMTP_DEFAULT_SENDER_EMAIL = "SMTP_DEFAULT_SENDER_EMAIL";
|
|
||||||
public static final String SMTP_DEFAULT_SENDER_NAME = "SMTP_DEFAULT_SENDER_NAME";
|
|
||||||
public static final String SMTP_DEFAULT_REPLY_EMAIL = "SMTP_DEFAULT_REPLY_EMAIL";
|
|
||||||
public static final String SMTP_DEFAULT_REPLY_NAME = "SMTP_DEFAULT_REPLY_NAME";
|
|
||||||
public static final String SMTP_DEFAULT_SENDER_ENVELOPE = "SMTP_DEFAULT_SENDER_ENVELOPE";
|
|
||||||
public static final String SMTP_DEFAULT_SSL = "SMTP_DEFAULT_SSL";
|
|
||||||
public static final String SMTP_DEFAULT_STARTTLS = "SMTP_DEFAULT_STARTTLS";
|
|
||||||
public static final String SMTP_DEFAULT_AUTH = "SMTP_DEFAULT_AUTH";
|
|
||||||
public static final String SMTP_DEFAULT_AUTH_USER = "SMTP_DEFAULT_AUTH_USER";
|
|
||||||
public static final String SMTP_DEFAULT_AUTH_PASSWORD = "SMTP_DEFAULT_AUTH_PASSWORD";
|
|
||||||
public static final String CONFIGURABLE_SMTP_SERVER_FEATURE = "configurableSMTPServer";
|
public static final String CONFIGURABLE_SMTP_SERVER_FEATURE = "configurableSMTPServer";
|
||||||
|
|
||||||
|
@EventListener(ApplicationReadyEvent.class)
|
||||||
|
public void synchronizeSMTPConfigurations() {
|
||||||
|
|
||||||
|
log.info("Starting SMTP configuration synchronization...");
|
||||||
|
|
||||||
|
try {
|
||||||
|
List<TenantEntity> tenants = tenantRepository.findAll();
|
||||||
|
log.info("Retrieved {} tenants for SMTP synchronization.", tenants.size());
|
||||||
|
|
||||||
|
Optional<GlobalSMTPConfigurationEntity> optionalLatestGlobalConfigEntity = smtpConfigurationPersistenceService.get();
|
||||||
|
|
||||||
|
if (optionalLatestGlobalConfigEntity.isEmpty()) {
|
||||||
|
log.info("Global SMTP configuration was newly added. Initializing all tenant SMTP configurations.");
|
||||||
|
initializeGlobalSmtpConfig(tenants);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
updateGlobalSmtpConfig(optionalLatestGlobalConfigEntity.get(), tenants);
|
||||||
|
}
|
||||||
|
log.info("SMTP configuration synchronization completed successfully.");
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Failed to synchronize SMTP configurations: {}", e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void initializeGlobalSmtpConfig(List<TenantEntity> tenants) {
|
||||||
|
|
||||||
|
SMTPConfiguration currentGlobalConfig = environmentSMTPConfigurationProvider.get();
|
||||||
|
|
||||||
|
initializeTenantsSmtpConfig(tenants, currentGlobalConfig);
|
||||||
|
|
||||||
|
currentGlobalConfig.setPassword(encryptionDecryptionService.encrypt(currentGlobalConfig.getPassword()));
|
||||||
|
GlobalSMTPConfigurationEntity updatedGlobalConfig = SMTPConfigurationMapper.toEntity(currentGlobalConfig);
|
||||||
|
smtpConfigurationPersistenceService.createUpdate(updatedGlobalConfig);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void updateGlobalSmtpConfig(GlobalSMTPConfigurationEntity latestGlobalConfigEntity, List<TenantEntity> tenants) {
|
||||||
|
|
||||||
|
SMTPConfiguration latestGlobalConfig = SMTPConfigurationMapper.toModel(latestGlobalConfigEntity);
|
||||||
|
latestGlobalConfig.setPassword(encryptionDecryptionService.decrypt(latestGlobalConfig.getPassword()));
|
||||||
|
log.info("Existing global SMTP configuration was loaded.");
|
||||||
|
|
||||||
|
// Generate the latest SMTP config from environment variables and compare it to the last/saved global config
|
||||||
|
SMTPConfiguration currentGlobalConfig = environmentSMTPConfigurationProvider.get();
|
||||||
|
if (!currentGlobalConfig.equals(latestGlobalConfig)) {
|
||||||
|
|
||||||
|
log.info("Environment SMTP configuration has changed. Updating global SMTP configuration.");
|
||||||
|
updateTenantsSmtpConfig(tenants, latestGlobalConfig, currentGlobalConfig);
|
||||||
|
|
||||||
|
currentGlobalConfig.setPassword(encryptionDecryptionService.encrypt(currentGlobalConfig.getPassword()));
|
||||||
|
GlobalSMTPConfigurationEntity updatedGlobalConfig = SMTPConfigurationMapper.toEntity(currentGlobalConfig);
|
||||||
|
smtpConfigurationPersistenceService.createUpdate(updatedGlobalConfig);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
log.info("No changes detected in environment SMTP configuration.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void initializeTenantsSmtpConfig(List<TenantEntity> tenants, SMTPConfiguration currentGlobalConfig) {
|
||||||
|
|
||||||
|
tenants.forEach(tenant -> processTenantSmtpConfig(tenant, currentGlobalConfig, null, true));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void updateTenantsSmtpConfig(List<TenantEntity> tenants, SMTPConfiguration latestGlobalConfig, SMTPConfiguration currentGlobalConfig) {
|
||||||
|
|
||||||
|
tenants.forEach(tenant -> processTenantSmtpConfig(tenant, currentGlobalConfig, latestGlobalConfig, false));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void processTenantSmtpConfig(TenantEntity tenant, SMTPConfiguration currentGlobalConfig, SMTPConfiguration latestGlobalConfig, boolean isInitialization) {
|
||||||
|
|
||||||
|
String tenantId = tenant.getTenantId();
|
||||||
|
log.info("Processing SMTP configuration for tenant: {}", tenantId);
|
||||||
|
|
||||||
|
try {
|
||||||
|
TenantContext.setTenantId(tenantId);
|
||||||
|
SMTPConfiguration tenantSMTPConfig = getSMTPConfiguration();
|
||||||
|
tenantSMTPConfig.setId("singleton");
|
||||||
|
updatePassword(tenantSMTPConfig);
|
||||||
|
|
||||||
|
if (!StringUtils.isBlank(tenantSMTPConfig.getPassword())) {
|
||||||
|
tenantSMTPConfig.setPassword(encryptionDecryptionService.decrypt(tenantSMTPConfig.getPassword()));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isInitialization) {
|
||||||
|
if (StringUtils.isBlank(tenantSMTPConfig.getHost())) {
|
||||||
|
log.info("Tenant '{}' SMTP configuration has not been set yet.", tenantId);
|
||||||
|
updateSMTPConfiguration(currentGlobalConfig);
|
||||||
|
log.info("Tenant '{}' SMTP configuration set successfully.", tenantId);
|
||||||
|
} else {
|
||||||
|
log.info("Tenant '{}' SMTP configuration was already set. No action taken.", tenantId);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (tenantSMTPConfig.equals(latestGlobalConfig)) {
|
||||||
|
log.info("Tenant '{}' SMTP configuration matches global. Updating to latest environment configuration.", tenantId);
|
||||||
|
updateSMTPConfiguration(currentGlobalConfig);
|
||||||
|
log.info("Tenant '{}' SMTP configuration updated successfully.", tenantId);
|
||||||
|
} else {
|
||||||
|
log.info("Tenant '{}' SMTP configuration differs from global. No action taken.", tenantId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Error processing SMTP configuration for tenant '{}': {}", tenantId, e.getMessage());
|
||||||
|
} finally {
|
||||||
|
TenantContext.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public SMTPConfiguration getSMTPConfiguration() {
|
public SMTPConfiguration getSMTPConfiguration() {
|
||||||
@ -73,54 +179,31 @@ public class SMTPService {
|
|||||||
|
|
||||||
RedactionLicenseModel licenseModel = licenseClient.getLicense();
|
RedactionLicenseModel licenseModel = licenseClient.getLicense();
|
||||||
String activeLicenseId = licenseModel.getActiveLicense();
|
String activeLicenseId = licenseModel.getActiveLicense();
|
||||||
Optional<License> license = licenseModel.getLicenses()
|
|
||||||
|
return licenseModel.getLicenses()
|
||||||
.stream()
|
.stream()
|
||||||
.filter(l -> l.getId().equals(activeLicenseId))
|
.filter(license -> license.getId().equals(activeLicenseId))
|
||||||
.findFirst();
|
.flatMap(license -> license.getFeatures()
|
||||||
if (license.isPresent()) {
|
.stream())
|
||||||
License activeLicense = license.get();
|
.filter(feature -> CONFIGURABLE_SMTP_SERVER_FEATURE.equals(feature.getName()))
|
||||||
Optional<Feature> optionalConfigurableSMTPFeature = activeLicense.getFeatures()
|
.map(Feature::getValue)
|
||||||
.stream()
|
.filter(Boolean.class::isInstance)
|
||||||
.filter(feature -> feature.getName().equals(CONFIGURABLE_SMTP_SERVER_FEATURE))
|
.map(Boolean.class::cast)
|
||||||
.findFirst();
|
.findFirst()
|
||||||
if (optionalConfigurableSMTPFeature.isPresent()) {
|
.orElse(false);
|
||||||
return (Boolean) optionalConfigurableSMTPFeature.get().getValue();
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void createDefaultSMTPConfiguration(String tenantId) {
|
public void createDefaultSMTPConfiguration() {
|
||||||
|
|
||||||
SMTPConfiguration defaultConfig = generateDefaultSMTPConfiguration();
|
SMTPConfiguration defaultConfig = environmentSMTPConfigurationProvider.get();
|
||||||
updateSMTPConfiguration(defaultConfig, tenantId);
|
updateSMTPConfiguration(defaultConfig);
|
||||||
}
|
|
||||||
|
|
||||||
private SMTPConfiguration generateDefaultSMTPConfiguration() {
|
|
||||||
|
|
||||||
String port = environment.getProperty(SMTP_DEFAULT_PORT, "1234");
|
|
||||||
return SMTPConfiguration.builder()
|
|
||||||
.host(environment.getProperty(SMTP_DEFAULT_HOST, ""))
|
|
||||||
.port(StringUtils.isEmpty(port) ? null : Integer.parseInt(port))
|
|
||||||
.from(environment.getProperty(SMTP_DEFAULT_SENDER_EMAIL, ""))
|
|
||||||
.fromDisplayName(environment.getProperty(SMTP_DEFAULT_SENDER_NAME, ""))
|
|
||||||
.replyTo(environment.getProperty(SMTP_DEFAULT_REPLY_EMAIL, ""))
|
|
||||||
.replyToDisplayName(environment.getProperty(SMTP_DEFAULT_REPLY_NAME, ""))
|
|
||||||
.envelopeFrom(environment.getProperty(SMTP_DEFAULT_SENDER_ENVELOPE, ""))
|
|
||||||
.ssl(Boolean.parseBoolean(environment.getProperty(SMTP_DEFAULT_SSL, "false")))
|
|
||||||
.starttls(Boolean.parseBoolean(environment.getProperty(SMTP_DEFAULT_STARTTLS, "false")))
|
|
||||||
.auth(Boolean.parseBoolean(environment.getProperty(SMTP_DEFAULT_AUTH, "false")))
|
|
||||||
.user(environment.getProperty(SMTP_DEFAULT_AUTH_USER, ""))
|
|
||||||
.password(environment.getProperty(SMTP_DEFAULT_AUTH_PASSWORD, ""))
|
|
||||||
.build();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void updateSMTPConfiguration(SMTPConfiguration smtpConfigurationModel, String tenantId) {
|
public void updateSMTPConfiguration(SMTPConfiguration smtpConfigurationModel) {
|
||||||
|
|
||||||
|
String tenantId = TenantContext.getTenantId();
|
||||||
var realmRepresentation = realmService.realm(tenantId).toRepresentation();
|
var realmRepresentation = realmService.realm(tenantId).toRepresentation();
|
||||||
var propertiesMap = convertSMTPConfigurationModelToMap(smtpConfigurationModel);
|
var propertiesMap = convertSMTPConfigurationModelToMap(smtpConfigurationModel);
|
||||||
realmRepresentation.setSmtpServer(propertiesMap);
|
realmRepresentation.setSmtpServer(propertiesMap);
|
||||||
@ -162,8 +245,7 @@ public class SMTPService {
|
|||||||
|
|
||||||
if (DEFAULT_PASSWORD.equals(smtpConfiguration.getPassword())) {
|
if (DEFAULT_PASSWORD.equals(smtpConfiguration.getPassword())) {
|
||||||
try {
|
try {
|
||||||
var password = realmService.realm(TenantContext.getTenantId()).toRepresentation().getAttributesOrEmpty()
|
var password = realmService.realm(TenantContext.getTenantId()).toRepresentation().getAttributesOrEmpty().getOrDefault(SMTP_PASSWORD_KEY, "");
|
||||||
.get(SMTP_PASSWORD_KEY);
|
|
||||||
smtpConfiguration.setPassword(password);
|
smtpConfiguration.setPassword(password);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.info("No current SMTP Config exists", e);
|
log.info("No current SMTP Config exists", e);
|
||||||
|
|||||||
@ -214,7 +214,8 @@ public class TenantManagementService implements TenantProvider {
|
|||||||
|
|
||||||
log.info("Updated roles for tenant: {}", tenantRequest.getTenantId());
|
log.info("Updated roles for tenant: {}", tenantRequest.getTenantId());
|
||||||
|
|
||||||
smtpService.createDefaultSMTPConfiguration(tenantRequest.getTenantId());
|
TenantContext.setTenantId(tenantEntity.getTenantId());
|
||||||
|
smtpService.createDefaultSMTPConfiguration();
|
||||||
|
|
||||||
log.info("Created default SMTP configuration.");
|
log.info("Created default SMTP configuration.");
|
||||||
|
|
||||||
@ -223,7 +224,6 @@ public class TenantManagementService implements TenantProvider {
|
|||||||
|
|
||||||
log.info("Persisted tenant: {}", tenantRequest.getTenantId());
|
log.info("Persisted tenant: {}", tenantRequest.getTenantId());
|
||||||
|
|
||||||
TenantContext.setTenantId(tenantEntity.getTenantId());
|
|
||||||
rabbitTemplate.convertAndSend(tenantExchangeName, "tenant.created", new TenantCreatedEvent(tenantEntity.getTenantId()));
|
rabbitTemplate.convertAndSend(tenantExchangeName, "tenant.created", new TenantCreatedEvent(tenantEntity.getTenantId()));
|
||||||
TenantContext.clear();
|
TenantContext.clear();
|
||||||
|
|
||||||
|
|||||||
@ -237,33 +237,67 @@ public class UserService {
|
|||||||
public void validateSufficientRoles(String userId, Set<String> userRoles, Set<String> newRoles, Set<String> currentUserRoles) {
|
public void validateSufficientRoles(String userId, Set<String> userRoles, Set<String> newRoles, Set<String> currentUserRoles) {
|
||||||
|
|
||||||
var roleMapping = tenantUserManagementProperties.getKcRoleMapping();
|
var roleMapping = tenantUserManagementProperties.getKcRoleMapping();
|
||||||
var maxRank = currentUserRoles.stream()
|
|
||||||
|
int maxCurrentUserRank = currentUserRoles.stream()
|
||||||
.map(r -> roleMapping.getRole(r).getRank())
|
.map(r -> roleMapping.getRole(r).getRank())
|
||||||
.max(Integer::compare)
|
.max(Integer::compare)
|
||||||
.orElse(-1);
|
.orElse(-1);
|
||||||
var newRolesRank = newRoles.stream()
|
|
||||||
.map(r -> roleMapping.getRole(r).getRank())
|
|
||||||
.toList();
|
|
||||||
var maxNewRolesRank = newRolesRank.stream()
|
|
||||||
.max(Integer::compare)
|
|
||||||
.orElse(-1);
|
|
||||||
|
|
||||||
var untouchableRoles = userRoles.stream()
|
Set<String> untouchableRoles = userRoles.stream()
|
||||||
.filter(roleMapping::isValidRole)
|
.filter(roleMapping::isValidRole)
|
||||||
.map(roleMapping::getRole)
|
.map(roleMapping::getRole)
|
||||||
.filter(r -> r.getRank() > maxRank || ApplicationRoles.isKneconRole(r.getName()))
|
.filter(r -> r.getRank() > maxCurrentUserRank && !ApplicationRoles.isKneconRole(r.getName()))
|
||||||
.map(KCRole::getName)
|
.map(KCRole::getName)
|
||||||
.collect(Collectors.toSet());
|
.collect(Collectors.toSet());
|
||||||
|
|
||||||
if (maxNewRolesRank > maxRank) {
|
Set<String> kneconRoles = userRoles.stream()
|
||||||
|
.filter(roleMapping::isValidRole)
|
||||||
|
.map(roleMapping::getRole)
|
||||||
|
.map(KCRole::getName)
|
||||||
|
.filter(ApplicationRoles::isKneconRole)
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
|
||||||
|
int maxNewRolesRank = newRoles.stream()
|
||||||
|
.map(r -> roleMapping.getRole(r).getRank())
|
||||||
|
.max(Integer::compare)
|
||||||
|
.orElse(-1);
|
||||||
|
|
||||||
|
newRoles.addAll(kneconRoles);
|
||||||
|
|
||||||
|
int maxNewRolesRankIncludingKnecon = newRoles.stream()
|
||||||
|
.map(r -> roleMapping.getRole(r).getRank())
|
||||||
|
.max(Integer::compare)
|
||||||
|
.orElse(-1);
|
||||||
|
|
||||||
|
ensureNoHigherRankAssigned(maxCurrentUserRank, maxNewRolesRank);
|
||||||
|
ensureUntouchableRolesPreserved(untouchableRoles, newRoles);
|
||||||
|
ensureHighestRankNotRemovedFromSelf(userId, maxCurrentUserRank, maxNewRolesRankIncludingKnecon, roleMapping.getMaxRank());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void ensureNoHigherRankAssigned(int maxCurrentUserRank, int maxNewRolesRank) {
|
||||||
|
|
||||||
|
if (maxNewRolesRank > maxCurrentUserRank) {
|
||||||
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Cannot assign this role to that user. Insufficient rights");
|
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Cannot assign this role to that user. Insufficient rights");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void ensureUntouchableRolesPreserved(Set<String> untouchableRoles, Set<String> newRoles) {
|
||||||
|
|
||||||
if (!newRoles.containsAll(untouchableRoles)) {
|
if (!newRoles.containsAll(untouchableRoles)) {
|
||||||
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Cannot modify some roles for this user. Insufficient rights");
|
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Cannot modify some roles for this user. Insufficient rights");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (userId.equalsIgnoreCase(KeycloakSecurity.getUserId()) && maxRank.equals(roleMapping.getMaxRank()) && !maxNewRolesRank.equals(maxRank)) {
|
|
||||||
|
private void ensureHighestRankNotRemovedFromSelf(String userId, int maxCurrentUserRank, int maxNewRolesRankIncludingKnecon, int overallMaxRank) {
|
||||||
|
|
||||||
|
boolean isSelf = userId.equalsIgnoreCase(KeycloakSecurity.getUserId());
|
||||||
|
boolean isUserHighestRank = maxCurrentUserRank == overallMaxRank;
|
||||||
|
boolean highestRankRemoved = !Integer.valueOf(maxNewRolesRankIncludingKnecon).equals(maxCurrentUserRank);
|
||||||
|
|
||||||
|
if (isSelf && isUserHighestRank && highestRankRemoved) {
|
||||||
throw new ResponseStatusException(HttpStatus.CONFLICT, "Cannot remove highest ranking role from self.");
|
throw new ResponseStatusException(HttpStatus.CONFLICT, "Cannot remove highest ranking role from self.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -653,6 +687,7 @@ public class UserService {
|
|||||||
.max(Integer::compare)
|
.max(Integer::compare)
|
||||||
.orElse(-1);
|
.orElse(-1);
|
||||||
var targetRank = userRoles.stream()
|
var targetRank = userRoles.stream()
|
||||||
|
.filter(ApplicationRoles::isNoKneconRole)
|
||||||
.map(r -> roleMapping.getRole(r).getRank())
|
.map(r -> roleMapping.getRole(r).getRank())
|
||||||
.max(Integer::compare)
|
.max(Integer::compare)
|
||||||
.orElse(-1);
|
.orElse(-1);
|
||||||
|
|||||||
@ -0,0 +1,60 @@
|
|||||||
|
package com.knecon.fforesight.tenantusermanagement.utils;
|
||||||
|
|
||||||
|
import com.knecon.fforesight.tenantusermanagement.entity.GlobalSMTPConfigurationEntity;
|
||||||
|
import com.knecon.fforesight.tenantusermanagement.model.SMTPConfiguration;
|
||||||
|
|
||||||
|
import lombok.experimental.UtilityClass;
|
||||||
|
|
||||||
|
@UtilityClass
|
||||||
|
public final class SMTPConfigurationMapper {
|
||||||
|
|
||||||
|
public static GlobalSMTPConfigurationEntity toEntity(SMTPConfiguration smtpConfig) {
|
||||||
|
|
||||||
|
if (smtpConfig == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return GlobalSMTPConfigurationEntity.builder()
|
||||||
|
.id("singleton")
|
||||||
|
.auth(smtpConfig.isAuth())
|
||||||
|
.envelopeFrom(smtpConfig.getEnvelopeFrom())
|
||||||
|
.fromEmail(smtpConfig.getFrom())
|
||||||
|
.fromDisplayName(smtpConfig.getFromDisplayName())
|
||||||
|
.host(smtpConfig.getHost())
|
||||||
|
.password(smtpConfig.getPassword())
|
||||||
|
.port(smtpConfig.getPort())
|
||||||
|
.replyTo(smtpConfig.getReplyTo())
|
||||||
|
.replyToDisplayName(smtpConfig.getReplyToDisplayName())
|
||||||
|
.ssl(smtpConfig.isSsl())
|
||||||
|
.starttls(smtpConfig.isStarttls())
|
||||||
|
.userName(smtpConfig.getUser())
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static SMTPConfiguration toModel(GlobalSMTPConfigurationEntity entity) {
|
||||||
|
|
||||||
|
if (entity == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
SMTPConfiguration smtpConfig = new SMTPConfiguration();
|
||||||
|
smtpConfig.setId(entity.getId());
|
||||||
|
smtpConfig.setAuth(entity.getAuth() != null && entity.getAuth());
|
||||||
|
smtpConfig.setEnvelopeFrom(entity.getEnvelopeFrom());
|
||||||
|
smtpConfig.setFrom(entity.getFromEmail());
|
||||||
|
smtpConfig.setFromDisplayName(entity.getFromDisplayName());
|
||||||
|
smtpConfig.setHost(entity.getHost());
|
||||||
|
smtpConfig.setPassword(entity.getPassword());
|
||||||
|
smtpConfig.setPort(entity.getPort());
|
||||||
|
smtpConfig.setReplyTo(entity.getReplyTo());
|
||||||
|
smtpConfig.setReplyToDisplayName(entity.getReplyToDisplayName());
|
||||||
|
smtpConfig.setSsl(entity.getSsl() != null && entity.getSsl());
|
||||||
|
smtpConfig.setStarttls(entity.getStarttls() != null && entity.getStarttls());
|
||||||
|
smtpConfig.setUser(entity.getUserName());
|
||||||
|
|
||||||
|
return smtpConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@ -101,7 +101,7 @@ spring:
|
|||||||
password: ${REDIS_PASSWORD:}
|
password: ${REDIS_PASSWORD:}
|
||||||
fforesight:
|
fforesight:
|
||||||
keycloak:
|
keycloak:
|
||||||
ignored-endpoints: [ '/actuator/health', '/actuator/health/**', '/tenant-user-management', '/tenant-user-management/', '/internal/**','/tenant-user-management/docs/**','/tenant-user-management/docs','/tenant-user-management/tenants/simple' ]
|
ignored-endpoints: [ '/actuator/health', '/actuator/health/**', '/tenant-user-management', '/tenant-user-management/', '/internal/**','/tenant-user-management/docs/**','/tenant-user-management/docs' ]
|
||||||
enabled: true
|
enabled: true
|
||||||
springdoc:
|
springdoc:
|
||||||
base-path: '/tenant-user-management'
|
base-path: '/tenant-user-management'
|
||||||
|
|||||||
@ -17,3 +17,5 @@ databaseChangeLog:
|
|||||||
file: db/changelog/master/9-add-mongodb-connection-columns.yaml
|
file: db/changelog/master/9-add-mongodb-connection-columns.yaml
|
||||||
- include:
|
- include:
|
||||||
file: db/changelog/master/10-add-application-type-to-tenant.yaml
|
file: db/changelog/master/10-add-application-type-to-tenant.yaml
|
||||||
|
- include:
|
||||||
|
file: db/changelog/master/11-add-global-smtp-config.yaml
|
||||||
|
|||||||
@ -0,0 +1,51 @@
|
|||||||
|
databaseChangeLog:
|
||||||
|
- changeSet:
|
||||||
|
id: add-global-smtp-config-table
|
||||||
|
author: dom
|
||||||
|
changes:
|
||||||
|
- createTable:
|
||||||
|
tableName: global_smtp_configuration
|
||||||
|
columns:
|
||||||
|
- column:
|
||||||
|
name: id
|
||||||
|
type: VARCHAR(255)
|
||||||
|
constraints:
|
||||||
|
nullable: false
|
||||||
|
primaryKey: true
|
||||||
|
primaryKeyName: global_smtp_configuration_pkey
|
||||||
|
- column:
|
||||||
|
name: auth
|
||||||
|
type: BOOLEAN
|
||||||
|
- column:
|
||||||
|
name: envelope_from
|
||||||
|
type: VARCHAR(255)
|
||||||
|
- column:
|
||||||
|
name: from_email
|
||||||
|
type: VARCHAR(255)
|
||||||
|
- column:
|
||||||
|
name: from_display_name
|
||||||
|
type: VARCHAR(255)
|
||||||
|
- column:
|
||||||
|
name: host
|
||||||
|
type: VARCHAR(255)
|
||||||
|
- column:
|
||||||
|
name: password
|
||||||
|
type: VARCHAR(255)
|
||||||
|
- column:
|
||||||
|
name: port
|
||||||
|
type: INTEGER
|
||||||
|
- column:
|
||||||
|
name: reply_to
|
||||||
|
type: VARCHAR(255)
|
||||||
|
- column:
|
||||||
|
name: reply_to_display_name
|
||||||
|
type: VARCHAR(255)
|
||||||
|
- column:
|
||||||
|
name: ssl
|
||||||
|
type: BOOLEAN
|
||||||
|
- column:
|
||||||
|
name: starttls
|
||||||
|
type: BOOLEAN
|
||||||
|
- column:
|
||||||
|
name: user_name
|
||||||
|
type: VARCHAR(255)
|
||||||
@ -1,15 +1,6 @@
|
|||||||
package com.knecon.fforesight.tenantusermanagement.tests;
|
package com.knecon.fforesight.tenantusermanagement.tests;
|
||||||
|
|
||||||
import static com.knecon.fforesight.tenantusermanagement.service.SMTPService.SMTP_DEFAULT_AUTH;
|
import static com.knecon.fforesight.tenantusermanagement.service.EnvironmentSMTPConfigurationProvider.*;
|
||||||
import static com.knecon.fforesight.tenantusermanagement.service.SMTPService.SMTP_DEFAULT_HOST;
|
|
||||||
import static com.knecon.fforesight.tenantusermanagement.service.SMTPService.SMTP_DEFAULT_PORT;
|
|
||||||
import static com.knecon.fforesight.tenantusermanagement.service.SMTPService.SMTP_DEFAULT_REPLY_EMAIL;
|
|
||||||
import static com.knecon.fforesight.tenantusermanagement.service.SMTPService.SMTP_DEFAULT_REPLY_NAME;
|
|
||||||
import static com.knecon.fforesight.tenantusermanagement.service.SMTPService.SMTP_DEFAULT_SENDER_EMAIL;
|
|
||||||
import static com.knecon.fforesight.tenantusermanagement.service.SMTPService.SMTP_DEFAULT_SENDER_ENVELOPE;
|
|
||||||
import static com.knecon.fforesight.tenantusermanagement.service.SMTPService.SMTP_DEFAULT_SENDER_NAME;
|
|
||||||
import static com.knecon.fforesight.tenantusermanagement.service.SMTPService.SMTP_DEFAULT_SSL;
|
|
||||||
import static com.knecon.fforesight.tenantusermanagement.service.SMTPService.SMTP_DEFAULT_STARTTLS;
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||||
|
|||||||
@ -0,0 +1,353 @@
|
|||||||
|
package com.knecon.fforesight.tenantusermanagement.tests;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
import static org.mockito.Mockito.anyString;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.never;
|
||||||
|
import static org.mockito.Mockito.times;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
import static org.mockito.quality.Strictness.LENIENT;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
|
import org.keycloak.admin.client.resource.RealmResource;
|
||||||
|
import org.keycloak.representations.idm.RealmRepresentation;
|
||||||
|
import org.mockito.ArgumentCaptor;
|
||||||
|
import org.mockito.ArgumentMatchers;
|
||||||
|
import org.mockito.InjectMocks;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.junit.jupiter.MockitoSettings;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import com.knecon.fforesight.tenantcommons.EncryptionDecryptionService;
|
||||||
|
import com.knecon.fforesight.tenantusermanagement.entity.GlobalSMTPConfigurationEntity;
|
||||||
|
import com.knecon.fforesight.tenantusermanagement.entity.TenantEntity;
|
||||||
|
import com.knecon.fforesight.tenantusermanagement.model.SMTPConfiguration;
|
||||||
|
import com.knecon.fforesight.tenantusermanagement.repository.TenantRepository;
|
||||||
|
import com.knecon.fforesight.tenantusermanagement.service.EnvironmentSMTPConfigurationProvider;
|
||||||
|
import com.knecon.fforesight.tenantusermanagement.service.GlobalSMTPConfigurationPersistenceService;
|
||||||
|
import com.knecon.fforesight.tenantusermanagement.service.RealmService;
|
||||||
|
import com.knecon.fforesight.tenantusermanagement.service.SMTPService;
|
||||||
|
|
||||||
|
@MockitoSettings(strictness = LENIENT)
|
||||||
|
@ExtendWith(org.mockito.junit.jupiter.MockitoExtension.class)
|
||||||
|
public class SMTPServiceTest {
|
||||||
|
|
||||||
|
public static final String NEW_SMTP_HOST = "new.smtp.host";
|
||||||
|
public static final int NEW_SMTP_PORT = 465;
|
||||||
|
public static final String NEW_SMTP_USER = "newUser";
|
||||||
|
public static final String NEW_SMTP_PASSWORD = "newPassword";
|
||||||
|
public static final String OLD_SMTP_HOST = "old.smtp.host";
|
||||||
|
public static final int OLD_SMTP_PORT = 587;
|
||||||
|
public static final String OLD_SMTP_USER = "globalUser";
|
||||||
|
public static final String OLD_SMTP_PASSWORD = "oldPassword";
|
||||||
|
public static final String FFORESIGHT_SMTP_PASSWORD = "FFORESIGHT_SMTP_PASSWORD";
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private GlobalSMTPConfigurationPersistenceService smtpConfigurationPersistenceService;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private EnvironmentSMTPConfigurationProvider environmentSMTPConfigurationProvider;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private RealmService realmService;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private TenantRepository tenantRepository;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private EncryptionDecryptionService encryptionDecryptionService;
|
||||||
|
|
||||||
|
@InjectMocks
|
||||||
|
private SMTPService smtpService;
|
||||||
|
|
||||||
|
private SMTPConfiguration oldGlobalConfig;
|
||||||
|
private SMTPConfiguration overriddenConfig;
|
||||||
|
private List<TenantEntity> tenantEntities;
|
||||||
|
private final static String DEFAULT_PASSWORD = "**********";
|
||||||
|
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
public void setUp() {
|
||||||
|
|
||||||
|
smtpService = new SMTPService(smtpConfigurationPersistenceService,
|
||||||
|
environmentSMTPConfigurationProvider,
|
||||||
|
null,
|
||||||
|
realmService,
|
||||||
|
tenantRepository,
|
||||||
|
encryptionDecryptionService,
|
||||||
|
new ObjectMapper());
|
||||||
|
|
||||||
|
oldGlobalConfig = new SMTPConfiguration();
|
||||||
|
oldGlobalConfig.setId("singleton");
|
||||||
|
oldGlobalConfig.setHost(OLD_SMTP_HOST);
|
||||||
|
oldGlobalConfig.setPort(OLD_SMTP_PORT);
|
||||||
|
oldGlobalConfig.setUser(OLD_SMTP_USER);
|
||||||
|
oldGlobalConfig.setPassword(OLD_SMTP_PASSWORD);
|
||||||
|
|
||||||
|
overriddenConfig = new SMTPConfiguration();
|
||||||
|
overriddenConfig.setHost("custom.smtp.host");
|
||||||
|
overriddenConfig.setPort(2525);
|
||||||
|
overriddenConfig.setUser("customUser");
|
||||||
|
overriddenConfig.setPassword("encrypted_customPassword");
|
||||||
|
|
||||||
|
TenantEntity tenant1 = new TenantEntity();
|
||||||
|
tenant1.setTenantId("tenant1");
|
||||||
|
|
||||||
|
TenantEntity tenant2 = new TenantEntity();
|
||||||
|
tenant2.setTenantId("tenant2");
|
||||||
|
|
||||||
|
TenantEntity tenant3 = new TenantEntity();
|
||||||
|
tenant3.setTenantId("tenant3");
|
||||||
|
|
||||||
|
tenantEntities = Arrays.asList(tenant1, tenant2, tenant3);
|
||||||
|
when(tenantRepository.findAll()).thenReturn(tenantEntities);
|
||||||
|
|
||||||
|
GlobalSMTPConfigurationEntity globalEntity = new GlobalSMTPConfigurationEntity();
|
||||||
|
globalEntity.setHost(oldGlobalConfig.getHost());
|
||||||
|
globalEntity.setPort(oldGlobalConfig.getPort());
|
||||||
|
globalEntity.setUserName(oldGlobalConfig.getUser());
|
||||||
|
globalEntity.setPassword(oldGlobalConfig.getPassword());
|
||||||
|
when(smtpConfigurationPersistenceService.get()).thenReturn(Optional.of(globalEntity));
|
||||||
|
|
||||||
|
for (TenantEntity tenant : tenantEntities) {
|
||||||
|
RealmResource tenantRealmResource = mock(RealmResource.class);
|
||||||
|
when(realmService.realm(tenant.getTenantId())).thenReturn(tenantRealmResource);
|
||||||
|
}
|
||||||
|
|
||||||
|
when(encryptionDecryptionService.encrypt(ArgumentMatchers.<String>any())).thenAnswer(invocation -> {
|
||||||
|
String argument = invocation.getArgument(0);
|
||||||
|
return argument != null ? "encrypted_" + argument : null;
|
||||||
|
});
|
||||||
|
|
||||||
|
when(encryptionDecryptionService.decrypt(anyString())).thenAnswer(invocation -> {
|
||||||
|
String encrypted = invocation.getArgument(0);
|
||||||
|
if (encrypted.startsWith("encrypted_")) {
|
||||||
|
return encrypted.substring("encrypted_".length());
|
||||||
|
}
|
||||||
|
return encrypted;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSynchronizeSMTPConfigurations() {
|
||||||
|
|
||||||
|
for (TenantEntity tenant : tenantEntities) {
|
||||||
|
RealmResource tenantRealmResource = mock(RealmResource.class);
|
||||||
|
when(realmService.realm(tenant.getTenantId())).thenReturn(tenantRealmResource);
|
||||||
|
// for this test also mock toRepresentation
|
||||||
|
RealmRepresentation realm = getRealmRepresentation(tenant, overriddenConfig, oldGlobalConfig);
|
||||||
|
when(tenantRealmResource.toRepresentation()).thenReturn(realm);
|
||||||
|
}
|
||||||
|
|
||||||
|
SMTPConfiguration newEnvConfig = new SMTPConfiguration();
|
||||||
|
newEnvConfig.setId("singleton");
|
||||||
|
newEnvConfig.setHost(NEW_SMTP_HOST);
|
||||||
|
newEnvConfig.setPort(NEW_SMTP_PORT);
|
||||||
|
newEnvConfig.setUser(NEW_SMTP_USER);
|
||||||
|
newEnvConfig.setPassword(NEW_SMTP_PASSWORD);
|
||||||
|
when(environmentSMTPConfigurationProvider.get()).thenReturn(newEnvConfig);
|
||||||
|
|
||||||
|
smtpService.synchronizeSMTPConfigurations();
|
||||||
|
|
||||||
|
ArgumentCaptor<GlobalSMTPConfigurationEntity> globalConfigCaptor = ArgumentCaptor.forClass(GlobalSMTPConfigurationEntity.class);
|
||||||
|
verify(smtpConfigurationPersistenceService).createUpdate(globalConfigCaptor.capture());
|
||||||
|
|
||||||
|
GlobalSMTPConfigurationEntity updatedGlobalConfig = globalConfigCaptor.getValue();
|
||||||
|
assertEquals(NEW_SMTP_HOST, updatedGlobalConfig.getHost());
|
||||||
|
assertEquals(NEW_SMTP_PORT, updatedGlobalConfig.getPort());
|
||||||
|
assertEquals(NEW_SMTP_USER, updatedGlobalConfig.getUserName());
|
||||||
|
assertEquals("encrypted_" + NEW_SMTP_PASSWORD, updatedGlobalConfig.getPassword());
|
||||||
|
|
||||||
|
// Verify that tenant1 and tenant3 were not updated, and tenant2 was
|
||||||
|
for (TenantEntity tenant : tenantEntities) {
|
||||||
|
RealmResource tenantRealmResource = realmService.realm(tenant.getTenantId());
|
||||||
|
|
||||||
|
if ("tenant1".equals(tenant.getTenantId()) || "tenant3".equals(tenant.getTenantId())) {
|
||||||
|
// Verify that update() was called once for tenant1 and tenant3
|
||||||
|
verify(tenantRealmResource, times(1)).update(any(RealmRepresentation.class));
|
||||||
|
|
||||||
|
ArgumentCaptor<RealmRepresentation> realmCaptor = ArgumentCaptor.forClass(RealmRepresentation.class);
|
||||||
|
verify(tenantRealmResource).update(realmCaptor.capture());
|
||||||
|
|
||||||
|
RealmRepresentation updatedRealm = realmCaptor.getValue();
|
||||||
|
Map<String, String> smtpServer = updatedRealm.getSmtpServer();
|
||||||
|
smtpServer.putAll(updatedRealm.getAttributes());
|
||||||
|
assertEquals(NEW_SMTP_HOST, smtpServer.get("host"));
|
||||||
|
assertEquals(String.valueOf(NEW_SMTP_PORT), smtpServer.get("port"));
|
||||||
|
assertEquals(NEW_SMTP_USER, smtpServer.get("user"));
|
||||||
|
assertEquals("encrypted_" + NEW_SMTP_PASSWORD, smtpServer.get(FFORESIGHT_SMTP_PASSWORD));
|
||||||
|
assertEquals(NEW_SMTP_PASSWORD, smtpServer.get("password"));
|
||||||
|
} else if ("tenant2".equals(tenant.getTenantId())) {
|
||||||
|
// Verify that update() was never called for tenant2
|
||||||
|
verify(tenantRealmResource, never()).update(any(RealmRepresentation.class));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSynchronizeSMTPConfigurationsWithoutGlobalChanges() {
|
||||||
|
|
||||||
|
SMTPConfiguration newEnvConfig = new SMTPConfiguration();
|
||||||
|
newEnvConfig.setId("singleton");
|
||||||
|
newEnvConfig.setHost(OLD_SMTP_HOST);
|
||||||
|
newEnvConfig.setPort(OLD_SMTP_PORT);
|
||||||
|
newEnvConfig.setUser(OLD_SMTP_USER);
|
||||||
|
newEnvConfig.setPassword(OLD_SMTP_PASSWORD);
|
||||||
|
when(environmentSMTPConfigurationProvider.get()).thenReturn(newEnvConfig);
|
||||||
|
|
||||||
|
smtpService.synchronizeSMTPConfigurations();
|
||||||
|
|
||||||
|
verify(smtpConfigurationPersistenceService, never()).createUpdate(any(GlobalSMTPConfigurationEntity.class));
|
||||||
|
|
||||||
|
// Verify that all tenants are unchanged
|
||||||
|
for (TenantEntity tenant : tenantEntities) {
|
||||||
|
RealmResource tenantRealmResource = realmService.realm(tenant.getTenantId());
|
||||||
|
|
||||||
|
verify(tenantRealmResource, never()).update(any(RealmRepresentation.class));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testInitializeGlobalSMTPConfiguration() {
|
||||||
|
|
||||||
|
|
||||||
|
TenantEntity tenant1 = new TenantEntity();
|
||||||
|
tenant1.setTenantId("tenant1");
|
||||||
|
|
||||||
|
TenantEntity tenant2 = new TenantEntity();
|
||||||
|
tenant2.setTenantId("tenant2");
|
||||||
|
|
||||||
|
List<TenantEntity> tenantEntities = Arrays.asList(tenant1, tenant2);
|
||||||
|
|
||||||
|
when(tenantRepository.findAll()).thenReturn(tenantEntities);
|
||||||
|
|
||||||
|
when(smtpConfigurationPersistenceService.get()).thenReturn(Optional.empty());
|
||||||
|
|
||||||
|
String host = "global.smtp.host";
|
||||||
|
int port = 25;
|
||||||
|
String globalUser = "globalUser";
|
||||||
|
String globalPassword = "globalPassword";
|
||||||
|
|
||||||
|
SMTPConfiguration currentGlobalConfig = new SMTPConfiguration();
|
||||||
|
currentGlobalConfig.setId("singleton");
|
||||||
|
currentGlobalConfig.setHost(host);
|
||||||
|
currentGlobalConfig.setPort(port);
|
||||||
|
currentGlobalConfig.setUser(globalUser);
|
||||||
|
currentGlobalConfig.setPassword(globalPassword);
|
||||||
|
|
||||||
|
when(environmentSMTPConfigurationProvider.get()).thenReturn(currentGlobalConfig);
|
||||||
|
|
||||||
|
// Tenant1: Predefined SMTP configuration
|
||||||
|
RealmResource tenantRealmResource1 = mock(RealmResource.class);
|
||||||
|
when(realmService.realm("tenant1")).thenReturn(tenantRealmResource1);
|
||||||
|
RealmRepresentation realmRepresentation1 = getRealmRepresentationPredefined();
|
||||||
|
|
||||||
|
when(tenantRealmResource1.toRepresentation()).thenReturn(realmRepresentation1);
|
||||||
|
|
||||||
|
// Tenant2: No SMTP configuration
|
||||||
|
RealmResource tenantRealmResource2 = mock(RealmResource.class);
|
||||||
|
when(realmService.realm("tenant2")).thenReturn(tenantRealmResource2);
|
||||||
|
RealmRepresentation realmRepresentation2 = new RealmRepresentation();
|
||||||
|
|
||||||
|
Map<String, String> smtpServer2 = new HashMap<>();
|
||||||
|
smtpServer2.put("host", "");
|
||||||
|
realmRepresentation2.setSmtpServer(smtpServer2);
|
||||||
|
realmRepresentation2.setAttributes(new HashMap<>());
|
||||||
|
|
||||||
|
when(tenantRealmResource2.toRepresentation()).thenReturn(realmRepresentation2);
|
||||||
|
|
||||||
|
smtpService.synchronizeSMTPConfigurations();
|
||||||
|
|
||||||
|
ArgumentCaptor<GlobalSMTPConfigurationEntity> globalConfigCaptor = ArgumentCaptor.forClass(GlobalSMTPConfigurationEntity.class);
|
||||||
|
verify(smtpConfigurationPersistenceService).createUpdate(globalConfigCaptor.capture());
|
||||||
|
|
||||||
|
GlobalSMTPConfigurationEntity updatedGlobalConfig = globalConfigCaptor.getValue();
|
||||||
|
assertEquals(host, updatedGlobalConfig.getHost());
|
||||||
|
assertEquals(port, updatedGlobalConfig.getPort());
|
||||||
|
assertEquals(globalUser, updatedGlobalConfig.getUserName());
|
||||||
|
String encryptedGlobalPassword = "encrypted_" + globalPassword;
|
||||||
|
assertEquals(encryptedGlobalPassword, updatedGlobalConfig.getPassword());
|
||||||
|
|
||||||
|
// Verify that tenant1's SMTP configuration remains unchanged
|
||||||
|
verify(tenantRealmResource1, never()).update(any(RealmRepresentation.class));
|
||||||
|
|
||||||
|
// Verify that tenant2's SMTP configuration is updated
|
||||||
|
ArgumentCaptor<RealmRepresentation> realmCaptor2 = ArgumentCaptor.forClass(RealmRepresentation.class);
|
||||||
|
verify(tenantRealmResource2, times(1)).update(realmCaptor2.capture());
|
||||||
|
|
||||||
|
RealmRepresentation updatedRealm2 = realmCaptor2.getValue();
|
||||||
|
Map<String, String> updatedSmtpServer2 = updatedRealm2.getSmtpServer();
|
||||||
|
|
||||||
|
assertEquals(host, updatedSmtpServer2.get("host"));
|
||||||
|
assertEquals(String.valueOf(port), updatedSmtpServer2.get("port"));
|
||||||
|
assertEquals(globalUser, updatedSmtpServer2.get("user"));
|
||||||
|
assertEquals(globalPassword, updatedSmtpServer2.get("password"));
|
||||||
|
|
||||||
|
Map<String, String> updatedAttributes2 = updatedRealm2.getAttributes();
|
||||||
|
assertEquals(encryptedGlobalPassword, updatedAttributes2.get(FFORESIGHT_SMTP_PASSWORD));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private static RealmRepresentation getRealmRepresentationPredefined() {
|
||||||
|
|
||||||
|
RealmRepresentation realmRepresentation1 = new RealmRepresentation();
|
||||||
|
|
||||||
|
Map<String, String> smtpServer1 = new HashMap<>();
|
||||||
|
smtpServer1.put("host", "predefined.smtp.host");
|
||||||
|
smtpServer1.put("port", "587");
|
||||||
|
smtpServer1.put("user", "user1");
|
||||||
|
smtpServer1.put("password", DEFAULT_PASSWORD);
|
||||||
|
Map<String, String> attributes = new HashMap<>();
|
||||||
|
attributes.put(FFORESIGHT_SMTP_PASSWORD, "encrypted_predefined_pass");
|
||||||
|
|
||||||
|
realmRepresentation1.setSmtpServer(smtpServer1);
|
||||||
|
realmRepresentation1.setAttributes(attributes);
|
||||||
|
return realmRepresentation1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private static RealmRepresentation getRealmRepresentation(TenantEntity tenant, SMTPConfiguration overriddenConfig, SMTPConfiguration oldGlobalConfig) {
|
||||||
|
|
||||||
|
RealmRepresentation realm = new RealmRepresentation();
|
||||||
|
Map<String, String> smtpMap = new HashMap<>();
|
||||||
|
smtpMap.put("password", DEFAULT_PASSWORD);
|
||||||
|
Map<String, String> attributes = new HashMap<>();
|
||||||
|
|
||||||
|
if ("tenant2".equals(tenant.getTenantId())) {
|
||||||
|
// tenant2 has overridden SMTP config
|
||||||
|
smtpMap.put("host", overriddenConfig.getHost());
|
||||||
|
smtpMap.put("port", String.valueOf(overriddenConfig.getPort()));
|
||||||
|
smtpMap.put("user", overriddenConfig.getUser());
|
||||||
|
attributes.put(FFORESIGHT_SMTP_PASSWORD, overriddenConfig.getPassword());
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// tenant1 and tenant3 have SMTP config matching global
|
||||||
|
smtpMap.put("host", oldGlobalConfig.getHost());
|
||||||
|
smtpMap.put("port", String.valueOf(oldGlobalConfig.getPort()));
|
||||||
|
smtpMap.put("user", oldGlobalConfig.getUser());
|
||||||
|
attributes.put(FFORESIGHT_SMTP_PASSWORD, oldGlobalConfig.getPassword());
|
||||||
|
|
||||||
|
}
|
||||||
|
realm.setSmtpServer(smtpMap);
|
||||||
|
|
||||||
|
realm.setAttributes(attributes);
|
||||||
|
return realm;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -17,8 +17,8 @@ public class StartupTest extends AbstractTenantUserManagementIntegrationTest {
|
|||||||
@Test
|
@Test
|
||||||
public void testStartup() {
|
public void testStartup() {
|
||||||
|
|
||||||
var simpleTenants = internalTenantsClient.getSimpleTenants();
|
var tenants = internalTenantsClient.getTenants();
|
||||||
assertThat(simpleTenants).isNotEmpty();
|
assertThat(tenants).isNotEmpty();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -29,8 +29,10 @@ import com.knecon.fforesight.tenantusermanagement.model.User;
|
|||||||
import com.knecon.fforesight.tenantusermanagement.permissions.ApplicationRoles;
|
import com.knecon.fforesight.tenantusermanagement.permissions.ApplicationRoles;
|
||||||
import com.knecon.fforesight.tenantusermanagement.properties.TenantUserManagementProperties;
|
import com.knecon.fforesight.tenantusermanagement.properties.TenantUserManagementProperties;
|
||||||
import com.knecon.fforesight.tenantusermanagement.service.RealmService;
|
import com.knecon.fforesight.tenantusermanagement.service.RealmService;
|
||||||
|
import com.knecon.fforesight.tenantusermanagement.service.UserService;
|
||||||
|
|
||||||
import feign.FeignException;
|
import feign.FeignException;
|
||||||
|
import lombok.NonNull;
|
||||||
import lombok.SneakyThrows;
|
import lombok.SneakyThrows;
|
||||||
|
|
||||||
public class UserTest extends AbstractTenantUserManagementIntegrationTest {
|
public class UserTest extends AbstractTenantUserManagementIntegrationTest {
|
||||||
@ -44,6 +46,9 @@ public class UserTest extends AbstractTenantUserManagementIntegrationTest {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private TenantUserManagementProperties tenantUserManagementProperties;
|
private TenantUserManagementProperties tenantUserManagementProperties;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private UserService userService;
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testUsers() {
|
public void testUsers() {
|
||||||
@ -501,11 +506,11 @@ public class UserTest extends AbstractTenantUserManagementIntegrationTest {
|
|||||||
tokenService.setUser("admin@knecon.com", "secret");
|
tokenService.setUser("admin@knecon.com", "secret");
|
||||||
|
|
||||||
// this should still not be possible
|
// this should still not be possible
|
||||||
e = assertThrows(FeignException.class, () -> userClient.setRoles(onlyKneconUser.getUserId(), allRoles));
|
e = assertThrows(FeignException.class, () -> userClient.setRoles(onlyKneconUser.getUserId(), allRoles));
|
||||||
assertEquals(404, e.status());
|
assertEquals(404, e.status());
|
||||||
|
|
||||||
// and also not this
|
// and also not this
|
||||||
e = assertThrows(FeignException.class, () -> userClient.setRoles(user.getUserId(), allRoles));
|
e = assertThrows(FeignException.class, () -> userClient.setRoles(user.getUserId(), allRoles));
|
||||||
assertEquals(400, e.status());
|
assertEquals(400, e.status());
|
||||||
|
|
||||||
// we can also poll the user
|
// we can also poll the user
|
||||||
@ -584,12 +589,16 @@ public class UserTest extends AbstractTenantUserManagementIntegrationTest {
|
|||||||
addRoles(user4.getUserId(), allButKneconRoles);
|
addRoles(user4.getUserId(), allButKneconRoles);
|
||||||
|
|
||||||
allUsers = userClient.getAllUsers(true);
|
allUsers = userClient.getAllUsers(true);
|
||||||
var user4AfterShenanigansOpt = allUsers.stream().filter(u -> u.getUserId().equals(user4.getUserId())).findFirst();
|
var user4AfterShenanigansOpt = allUsers.stream()
|
||||||
|
.filter(u -> u.getUserId().equals(user4.getUserId()))
|
||||||
|
.findFirst();
|
||||||
assertTrue(user4AfterShenanigansOpt.isPresent());
|
assertTrue(user4AfterShenanigansOpt.isPresent());
|
||||||
user4AfterShenanigansOpt.get().setRoles(new HashSet<>());
|
user4AfterShenanigansOpt.get().setRoles(new HashSet<>());
|
||||||
assertEquals(user4AfterShenanigansOpt.get(), user4);
|
assertEquals(user4AfterShenanigansOpt.get(), user4);
|
||||||
|
|
||||||
var stillOnlyKneconUserOpt = allUsers.stream().filter(u -> u.getUserId().equals(onlyKneconUser.getUserId())).findFirst();
|
var stillOnlyKneconUserOpt = allUsers.stream()
|
||||||
|
.filter(u -> u.getUserId().equals(onlyKneconUser.getUserId()))
|
||||||
|
.findFirst();
|
||||||
assertTrue(stillOnlyKneconUserOpt.isPresent());
|
assertTrue(stillOnlyKneconUserOpt.isPresent());
|
||||||
stillOnlyKneconUserOpt.get().setRoles(new HashSet<>());
|
stillOnlyKneconUserOpt.get().setRoles(new HashSet<>());
|
||||||
assertEquals(stillOnlyKneconUserOpt.get(), onlyKneconUser);
|
assertEquals(stillOnlyKneconUserOpt.get(), onlyKneconUser);
|
||||||
@ -704,6 +713,113 @@ public class UserTest extends AbstractTenantUserManagementIntegrationTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUpdateProfileForUserWithAllRoles() {
|
||||||
|
|
||||||
|
TenantContext.setTenantId(AbstractTenantUserManagementIntegrationTest.TEST_TENANT_ID);
|
||||||
|
tokenService.setUser("admin@knecon.com", "secret");
|
||||||
|
|
||||||
|
var allRoles = tenantUserManagementProperties.getKcRoleMapping().getAllRoles();
|
||||||
|
Set<String> allButKneconRoles = allRoles.stream()
|
||||||
|
.filter(ApplicationRoles::isNoKneconRole)
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
|
||||||
|
CreateUserRequest createUserRequest = new CreateUserRequest();
|
||||||
|
createUserRequest.setEmail("all.roles.user@knecon.com");
|
||||||
|
createUserRequest.setUsername("all.roles.user@knecon.com");
|
||||||
|
createUserRequest.setFirstName("All");
|
||||||
|
createUserRequest.setLastName("Roles");
|
||||||
|
|
||||||
|
var allRolesuser = userClient.createUser(createUserRequest);
|
||||||
|
addRoles(allRolesuser.getUserId(), allRoles);
|
||||||
|
assertThat(allRolesuser).isNotNull();
|
||||||
|
|
||||||
|
UpdateProfileRequest updateProfileRequest = UpdateProfileRequest.builder()
|
||||||
|
.email("all.roles.user@knecon.com")
|
||||||
|
.firstName("All")
|
||||||
|
.lastName("NewLastName")
|
||||||
|
.roles(allButKneconRoles)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
var updatedUser = userClient.updateProfile(allRolesuser.getUserId(), updateProfileRequest);
|
||||||
|
|
||||||
|
assertThat(updatedUser).isNotNull();
|
||||||
|
assertThat(updatedUser.getLastName()).isEqualTo("NewLastName");
|
||||||
|
|
||||||
|
tokenService.setUser("test@fforesight.com", "secret");
|
||||||
|
|
||||||
|
updateProfileRequest.setLastName("AnotherNewLastName");
|
||||||
|
updatedUser = userClient.updateProfile(allRolesuser.getUserId(), updateProfileRequest);
|
||||||
|
|
||||||
|
assertThat(updatedUser).isNotNull();
|
||||||
|
assertThat(updatedUser.getLastName()).isEqualTo("AnotherNewLastName");
|
||||||
|
|
||||||
|
createUserRequest.setEmail("less.super.user.1@knecon.com");
|
||||||
|
createUserRequest.setUsername(createUserRequest.getEmail());
|
||||||
|
createUserRequest.setRoles(Set.of("LESS_SUPER_USER"));
|
||||||
|
var lessSuperUser = userClient.createUser(createUserRequest);
|
||||||
|
|
||||||
|
userClient.resetPassword(lessSuperUser.getUserId(), ResetPasswordRequest.builder().password("Secret@secured!23").build());
|
||||||
|
tokenService.setUser("less.super.user.1@knecon.com", "Secret@secured!23");
|
||||||
|
|
||||||
|
FeignException feignException = assertThrows(FeignException.class, () -> userClient.updateProfile(allRolesuser.getUserId(), updateProfileRequest));
|
||||||
|
assertEquals(400, feignException.status());
|
||||||
|
assertTrue(feignException.getMessage().contains("Cannot assign this role to that user. Insufficient rights"));
|
||||||
|
|
||||||
|
tokenService.setUser("admin@knecon.com", "secret");
|
||||||
|
userClient.deleteUser(lessSuperUser.getUserId());
|
||||||
|
userClient.deleteUser(allRolesuser.getUserId());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDeleteKneconRolesUserAsNormalAdmin() {
|
||||||
|
|
||||||
|
TenantContext.setTenantId(AbstractTenantUserManagementIntegrationTest.TEST_TENANT_ID);
|
||||||
|
tokenService.setUser("admin@knecon.com", "secret");
|
||||||
|
|
||||||
|
var allRoles = tenantUserManagementProperties.getKcRoleMapping().getAllRoles();
|
||||||
|
Set<String> allButKneconRoles = allRoles.stream()
|
||||||
|
.filter(ApplicationRoles::isNoKneconRole)
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
|
||||||
|
CreateUserRequest createUserRequest = new CreateUserRequest();
|
||||||
|
createUserRequest.setEmail("normalAdmin@knecon.com");
|
||||||
|
createUserRequest.setUsername("normalAdmin@knecon.com");
|
||||||
|
createUserRequest.setFirstName("Mister");
|
||||||
|
createUserRequest.setLastName("Admin");
|
||||||
|
|
||||||
|
var adminUser = userClient.createUser(createUserRequest);
|
||||||
|
addRoles(adminUser.getUserId(), allButKneconRoles);
|
||||||
|
assertThat(adminUser).isNotNull();
|
||||||
|
|
||||||
|
createUserRequest = new CreateUserRequest();
|
||||||
|
createUserRequest.setEmail("kneconAdmin@knecon.com");
|
||||||
|
createUserRequest.setUsername("kneconAdmin@knecon.com");
|
||||||
|
createUserRequest.setFirstName("Knecon");
|
||||||
|
createUserRequest.setLastName("Admin");
|
||||||
|
|
||||||
|
var kneconAdminuser = userClient.createUser(createUserRequest);
|
||||||
|
addRoles(kneconAdminuser.getUserId(), allRoles);
|
||||||
|
assertThat(kneconAdminuser).isNotNull();
|
||||||
|
|
||||||
|
userClient.resetPassword(adminUser.getUserId(), ResetPasswordRequest.builder().password("Secret@secured!23").build());
|
||||||
|
tokenService.setUser("normalAdmin@knecon.com", "Secret@secured!23");
|
||||||
|
|
||||||
|
userClient.deleteUser(kneconAdminuser.getUserId());
|
||||||
|
|
||||||
|
List<User> allUsers = userClient.getAllUsers(true);
|
||||||
|
assertTrue(allUsers.stream()
|
||||||
|
.noneMatch(u -> u.getUserId().equals(kneconAdminuser.getUserId())));
|
||||||
|
List<User> unfilteredUsers = userService.getAllUsers();
|
||||||
|
assertTrue(unfilteredUsers.stream()
|
||||||
|
.anyMatch(u -> u.getUserId().equals(kneconAdminuser.getUserId())));
|
||||||
|
|
||||||
|
tokenService.setUser("admin@knecon.com", "secret");
|
||||||
|
userClient.deleteUser(adminUser.getUserId());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private UsersResource getTenantUsersResource() {
|
private UsersResource getTenantUsersResource() {
|
||||||
|
|
||||||
return realmService.realm(TenantContext.getTenantId()).users();
|
return realmService.realm(TenantContext.getTenantId()).users();
|
||||||
@ -726,7 +842,11 @@ public class UserTest extends AbstractTenantUserManagementIntegrationTest {
|
|||||||
|
|
||||||
private void addRoles(String userId, Set<String> roles) {
|
private void addRoles(String userId, Set<String> roles) {
|
||||||
|
|
||||||
getUserResource(userId).roles().realmLevel().add(roles.stream().map(this::getRoleRepresentation).toList());
|
getUserResource(userId).roles()
|
||||||
|
.realmLevel()
|
||||||
|
.add(roles.stream()
|
||||||
|
.map(this::getRoleRepresentation)
|
||||||
|
.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -87,7 +87,7 @@ spring:
|
|||||||
password: ${REDIS_PASSWORD:}
|
password: ${REDIS_PASSWORD:}
|
||||||
fforesight:
|
fforesight:
|
||||||
keycloak:
|
keycloak:
|
||||||
ignored-endpoints: [ '/actuator/health', '/tenant-user-management','/internal/**','/tenant-user-management/docs/**','/tenant-user-management/docs','/tenant-user-management/tenants/simple' ]
|
ignored-endpoints: [ '/actuator/health', '/tenant-user-management','/internal/**','/tenant-user-management/docs/**','/tenant-user-management/docs' ]
|
||||||
enabled: true
|
enabled: true
|
||||||
springdoc:
|
springdoc:
|
||||||
base-path: '/tenant-user-management'
|
base-path: '/tenant-user-management'
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user