Merge branch 'RED-9394' into 'main'

RED-9394: Global default SMTP configuration

See merge request fforesight/tenant-user-management-service!134
This commit is contained in:
Maverick Studer 2024-10-16 10:59:35 +02:00
commit 4e4a8d7089
5 changed files with 135 additions and 84 deletions

View File

@ -32,11 +32,7 @@ import lombok.extern.slf4j.Slf4j;
@RequiredArgsConstructor
public class SMTPConfigurationController implements SMTPConfigurationResource, PublicResource {
private final static String SMTP_PASSWORD_KEY = "FFORESIGHT_SMTP_PASSWORD";
private final static String DEFAULT_PASSWORD = "**********";
private final RealmService realmService;
private final ObjectMapper objectMapper;
private final EncryptionDecryptionService encryptionDecryptionService;
private final EmailService emailService;
private final SMTPService smtpService;
@ -45,9 +41,7 @@ public class SMTPConfigurationController implements SMTPConfigurationResource, P
@PreAuthorize("hasAuthority('" + READ_SMTP_CONFIGURATION + "')")
public SMTPConfiguration getCurrentSMTPConfiguration() {
var realm = realmService.realm(TenantContext.getTenantId()).toRepresentation();
SMTPConfiguration smtpConfiguration = objectMapper.convertValue(realm.getSmtpServer(), SMTPConfiguration.class);
return smtpService.generateSMTPConfiguration(smtpConfiguration);
return smtpService.getSMTPConfiguration();
}
@ -59,15 +53,7 @@ public class SMTPConfigurationController implements SMTPConfigurationResource, P
throw new BadRequestException("Current license does not allow updating the SMTP configuration!");
}
var realmRepresentation = realmService.realm(TenantContext.getTenantId()).toRepresentation();
var propertiesMap = convertSMTPConfigurationModelToMap(smtpConfigurationModel);
realmRepresentation.setSmtpServer(propertiesMap);
if (smtpConfigurationModel.getPassword() != null && !smtpConfigurationModel.getPassword().matches("\\**")) {
realmRepresentation.getAttributesOrEmpty().put(SMTP_PASSWORD_KEY, encryptionDecryptionService.encrypt(smtpConfigurationModel.getPassword()));
}
realmService.realm(TenantContext.getTenantId()).update(realmRepresentation);
smtpService.updateSMTPConfiguration(smtpConfigurationModel, TenantContext.getTenantId());
}
@ -84,10 +70,7 @@ public class SMTPConfigurationController implements SMTPConfigurationResource, P
adminEmail = false;
}
updatePassword(smtpConfiguration);
smtpConfiguration.setPassword(encryptionDecryptionService.decrypt(smtpConfiguration.getPassword()));
SMTPResponse.SMTPResponseBuilder smtpResponseBuilder = emailService.send(convertSMTPConfigurationModelToMap(smtpConfiguration),
SMTPResponse.SMTPResponseBuilder smtpResponseBuilder = emailService.send(smtpService.convertSMTPConfigToMap(smtpConfiguration),
targetEmail,
"Redaction Test message",
"This is a test message");
@ -100,44 +83,9 @@ public class SMTPConfigurationController implements SMTPConfigurationResource, P
@Override
@PreAuthorize("hasAuthority('" + WRITE_SMTP_CONFIGURATION + "')")
public void clearSMTPConfiguration() {
// also update in KC
var realmRepresentation = realmService.realm(TenantContext.getTenantId()).toRepresentation();
realmRepresentation.setSmtpServer(new HashMap<>());
realmRepresentation.getAttributesOrEmpty().remove(SMTP_PASSWORD_KEY);
realmService.realm(TenantContext.getTenantId()).update(realmRepresentation);
}
smtpService.clearSMTPConfiguration();
private Map<String, String> convertSMTPConfigurationModelToMap(SMTPConfiguration smtpConfigurationModel) {
Map<String, Object> propertiesMap = objectMapper.convertValue(smtpConfigurationModel, new TypeReference<>() {
});
Map<String, String> stringPropertiesMap = new HashMap<>();
propertiesMap.forEach((key, value) -> {
if (value != null) {
stringPropertiesMap.put(key, value.toString());
} else {
stringPropertiesMap.put(key, "");
}
});
return stringPropertiesMap;
}
private void updatePassword(SMTPConfiguration smtpConfiguration) {
if (DEFAULT_PASSWORD.equals(smtpConfiguration.getPassword())) {
try {
var password = realmService.realm(TenantContext.getTenantId()).toRepresentation().getAttributesOrEmpty()
.get(SMTP_PASSWORD_KEY);
smtpConfiguration.setPassword(password);
} catch (Exception e) {
log.info("No current SMTP Config exists", e);
}
} else {
smtpConfiguration.setPassword(encryptionDecryptionService.encrypt(smtpConfiguration.getPassword()));
}
}
}

View File

@ -1,14 +1,20 @@
package com.knecon.fforesight.tenantusermanagement.service;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import org.apache.commons.lang3.StringUtils;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Service;
import com.fasterxml.jackson.core.type.TypeReference;
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.License;
import com.iqser.red.service.persistence.service.v1.api.shared.model.license.RedactionLicenseModel;
import com.knecon.fforesight.tenantcommons.EncryptionDecryptionService;
import com.knecon.fforesight.tenantcommons.TenantContext;
import com.knecon.fforesight.tenantusermanagement.client.LicenseClient;
import com.knecon.fforesight.tenantusermanagement.model.SMTPConfiguration;
@ -22,6 +28,15 @@ public class SMTPService {
private final Environment environment;
private final LicenseClient licenseClient;
private final RealmService realmService;
private final EncryptionDecryptionService encryptionDecryptionService;
private final ObjectMapper objectMapper;
private final static String SMTP_PASSWORD_KEY = "FFORESIGHT_SMTP_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";
@ -37,28 +52,20 @@ public class SMTPService {
public static final String CONFIGURABLE_SMTP_SERVER_FEATURE = "configurableSMTPServer";
public SMTPConfiguration generateSMTPConfiguration(SMTPConfiguration smtpConfiguration) {
if (smtpConfiguration.getHost() == null) {
// SMTP is not configured, we use default values
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();
} else {
return smtpConfiguration;
}
public SMTPConfiguration getSMTPConfiguration() {
var realm = realmService.realm(TenantContext.getTenantId()).toRepresentation();
return objectMapper.convertValue(realm.getSmtpServer(), SMTPConfiguration.class);
}
public Map<String, String> convertSMTPConfigToMap(SMTPConfiguration smtpConfiguration) {
updatePassword(smtpConfiguration);
smtpConfiguration.setPassword(encryptionDecryptionService.decrypt(smtpConfiguration.getPassword()));
return convertSMTPConfigurationModelToMap(smtpConfiguration);
}
@ -85,4 +92,85 @@ public class SMTPService {
return false;
}
public void createDefaultSMTPConfiguration(String tenantId) {
SMTPConfiguration defaultConfig = generateDefaultSMTPConfiguration();
updateSMTPConfiguration(defaultConfig, tenantId);
}
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) {
var realmRepresentation = realmService.realm(tenantId).toRepresentation();
var propertiesMap = convertSMTPConfigurationModelToMap(smtpConfigurationModel);
realmRepresentation.setSmtpServer(propertiesMap);
if (smtpConfigurationModel.getPassword() != null && !smtpConfigurationModel.getPassword().matches("\\**")) {
realmRepresentation.getAttributesOrEmpty().put(SMTP_PASSWORD_KEY, encryptionDecryptionService.encrypt(smtpConfigurationModel.getPassword()));
}
realmService.realm(tenantId).update(realmRepresentation);
}
public void clearSMTPConfiguration() {
var realmRepresentation = realmService.realm(TenantContext.getTenantId()).toRepresentation();
realmRepresentation.setSmtpServer(new HashMap<>());
realmRepresentation.getAttributesOrEmpty().remove(SMTP_PASSWORD_KEY);
realmService.realm(TenantContext.getTenantId()).update(realmRepresentation);
}
private Map<String, String> convertSMTPConfigurationModelToMap(SMTPConfiguration smtpConfigurationModel) {
Map<String, Object> propertiesMap = objectMapper.convertValue(smtpConfigurationModel, new TypeReference<>() {
});
Map<String, String> stringPropertiesMap = new HashMap<>();
propertiesMap.forEach((key, value) -> {
if (value != null) {
stringPropertiesMap.put(key, value.toString());
} else {
stringPropertiesMap.put(key, "");
}
});
return stringPropertiesMap;
}
private void updatePassword(SMTPConfiguration smtpConfiguration) {
if (DEFAULT_PASSWORD.equals(smtpConfiguration.getPassword())) {
try {
var password = realmService.realm(TenantContext.getTenantId()).toRepresentation().getAttributesOrEmpty()
.get(SMTP_PASSWORD_KEY);
smtpConfiguration.setPassword(password);
} catch (Exception e) {
log.info("No current SMTP Config exists", e);
}
} else {
smtpConfiguration.setPassword(encryptionDecryptionService.encrypt(smtpConfiguration.getPassword()));
}
}
}

View File

@ -62,8 +62,8 @@ import com.knecon.fforesight.tenantusermanagement.entity.SearchConnectionEntity;
import com.knecon.fforesight.tenantusermanagement.entity.TenantEntity;
import com.knecon.fforesight.tenantusermanagement.events.TenantCreatedEvent;
import com.knecon.fforesight.tenantusermanagement.events.TenantSyncEvent;
import com.knecon.fforesight.tenantusermanagement.model.SearchConnectionRequest;
import com.knecon.fforesight.tenantusermanagement.model.CreateTenantRequest;
import com.knecon.fforesight.tenantusermanagement.model.SearchConnectionRequest;
import com.knecon.fforesight.tenantusermanagement.model.TenantUser;
import com.knecon.fforesight.tenantusermanagement.model.UpdateTenantRequest;
import com.knecon.fforesight.tenantusermanagement.properties.TenantUserManagementProperties;
@ -106,6 +106,7 @@ public class TenantManagementService implements TenantProvider {
private final RealmService realmService;
private final RabbitTemplate rabbitTemplate;
private final StorageConfiguration storageConfiguration;
private final SMTPService smtpService;
@Value("${fforesight.tenant-exchange.name}")
private String tenantExchangeName;
@ -209,6 +210,10 @@ public class TenantManagementService implements TenantProvider {
log.info("Updated roles for tenant: {}", tenantRequest.getTenantId());
smtpService.createDefaultSMTPConfiguration(tenantRequest.getTenantId());
log.info("Created default SMTP configuration.");
var saved = tenantPersistenceService.save(tenantEntity);
log.info("Persisted tenant: {}", tenantRequest.getTenantId());
@ -507,6 +512,9 @@ public class TenantManagementService implements TenantProvider {
var userRepresentationlist = users.stream()
.map(this::toUserRepresentation)
.toList();
if (existingRealm.getUsers() == null) {
existingRealm.setUsers(new ArrayList<>());
}
List<UserRepresentation> toUpdate = userRepresentationlist.stream()
.filter(existingRealm.getUsers()::contains)
.toList();
@ -517,11 +525,13 @@ public class TenantManagementService implements TenantProvider {
.stream()
.findFirst()
.ifPresent(userRepresentation -> {
getRealmResource(tenantId).users().get(userRepresentation.getId()).update(user);
getRealmResource(tenantId).users()
.get(userRepresentation.getId()).update(user);
}));
existingRealm.getUsers().addAll(toAdd);
} getRealmResource(tenantId).update(existingRealm);
}
getRealmResource(tenantId).update(existingRealm);
return true;
}
} catch (NotFoundException e) {
@ -529,7 +539,8 @@ public class TenantManagementService implements TenantProvider {
} catch (Exception e) {
log.warn("Failed to update realm: {}", tenantId, e);
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Failed to update realm: " + tenantId);
} return false;
}
return false;
}

View File

@ -114,6 +114,10 @@ public class SMTPConfigurationTest extends AbstractTenantUserManagementIntegrati
System.setProperty(SMTP_DEFAULT_STARTTLS, "true");
System.setProperty(SMTP_DEFAULT_AUTH, "true");
String newTenant = "NEW_TENANT";
testTenantService.createTestTenantWithoutStorageIfNotExist(newTenant);
TenantContext.setTenantId(newTenant);
var currentSMTPConfiguration = smtpConfigurationClient.getCurrentSMTPConfiguration();
assertThat(currentSMTPConfiguration.getHost()).isEqualTo("smtp.example.com");

View File

@ -45,13 +45,13 @@ public class TestTenantService {
} catch (Exception e) {
// not found
createUser(testTenantId, actualPort, true);
createTenant(testTenantId, actualPort, true);
}
}
private void createUser(String testTenantId, int actualPort, boolean withStorage) {
private void createTenant(String testTenantId, int actualPort, boolean withStorage) {
// not found
CreateTenantRequest tenantRequest;
var tenantRequestBuilder = CreateTenantRequest.builder()
@ -119,7 +119,7 @@ public class TestTenantService {
} catch (Exception e) {
// not found
createUser(testTenantId, 0, false);
createTenant(testTenantId, 0, false);
}
}