RED-7238 - Fix test SMTP connection

This commit is contained in:
Andrei Isvoran 2023-08-31 14:28:49 +03:00
parent 8bcd42990e
commit 2e5f8f4169
7 changed files with 112 additions and 21 deletions

View File

@ -6,11 +6,11 @@ import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import com.knecon.fforesight.tenantusermanagement.model.SMTPConfiguration;
import com.knecon.fforesight.tenantusermanagement.model.SMTPResponse;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
@ -38,11 +38,12 @@ public interface SMTPConfigurationResource {
void updateSMTPConfiguration(@RequestBody SMTPConfiguration smtpConfigurationModel);
@ResponseBody
@ResponseStatus(value = HttpStatus.OK)
@PostMapping(value = SMTP_PATH + TEST_PATH, consumes = MediaType.APPLICATION_JSON_VALUE)
@PostMapping(value = SMTP_PATH + TEST_PATH, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
@Operation(summary = "Test SMTP Settings to KeyCloak")
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "SMTP Configuration is valid."), @ApiResponse(responseCode = "400", description = "SMTP test failed.")})
void testSMTPConfiguration(@RequestBody SMTPConfiguration smtpConfigurationModel);
SMTPResponse testSMTPConfiguration(@RequestBody SMTPConfiguration smtpConfigurationModel);
@ResponseStatus(value = HttpStatus.NO_CONTENT)

View File

@ -6,6 +6,9 @@ import static com.knecon.fforesight.tenantusermanagement.permissions.UserManagem
import java.util.HashMap;
import java.util.Map;
import javax.ws.rs.core.Response;
import org.keycloak.admin.client.resource.UserResource;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
@ -16,10 +19,10 @@ import com.knecon.fforesight.tenantcommons.TenantContext;
import com.knecon.fforesight.tenantusermanagement.api.external.PublicResource;
import com.knecon.fforesight.tenantusermanagement.api.external.SMTPConfigurationResource;
import com.knecon.fforesight.tenantusermanagement.model.SMTPConfiguration;
import com.knecon.fforesight.tenantusermanagement.model.SMTPResponse;
import com.knecon.fforesight.tenantusermanagement.service.RealmService;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@ -74,13 +77,31 @@ public class SMTPConfigurationController implements SMTPConfigurationResource, P
}
@SneakyThrows
@Override
@PreAuthorize("hasAuthority('" + WRITE_SMTP_CONFIGURATION + "')")
public void testSMTPConfiguration(@RequestBody SMTPConfiguration smtpConfigurationModel) {
public SMTPResponse testSMTPConfiguration(@RequestBody SMTPConfiguration smtpConfigurationModel) {
var propertiesMap = convertSMTPConfigurationModelToMap(smtpConfigurationModel);
realmService.realm(TenantContext.getTenantId()).testSMTPConnection(propertiesMap);
// We set the service account email to what the user set in the "from" field because we need the service account email in order to send the test SMTP email.
// After we send the email we reset it back to empty.
// Will be replaced with an actual email coming from a different field in the future.
Response response = null;
try {
Map<String, String> propertiesMap = convertSMTPConfigurationModelToMap(smtpConfigurationModel);
UserResource serviceAccount = realmService.getServiceAccount("master");
realmService.setServiceAccountEmail(serviceAccount, smtpConfigurationModel.getFrom());
response = realmService.realm(TenantContext.getTenantId()).testSMTPConnection(propertiesMap);
log.info("Test SMTP response {}, reason {}", response.getStatus(), response.getStatusInfo().getReasonPhrase());
realmService.setServiceAccountEmail(serviceAccount, "");
return SMTPResponse.builder().statusCode(response.getStatusInfo().getStatusCode()).reasonPhrase(response.getStatusInfo().getReasonPhrase()).build();
} finally {
if (response != null) {
response.close();
}
}
}

View File

@ -12,9 +12,7 @@ import lombok.NoArgsConstructor;
@NoArgsConstructor
@Schema(description = "Object containing the SMTP configuration.")
public class SMTPConfiguration {
@Schema(description = "Parameter containing the ID of the SMTP configuration.")
private String id;
@Schema(description = "Parameter containing the email of the sender.")
private String from;
@Schema(description = "Parameter containing the display name of the sender.")

View File

@ -0,0 +1,21 @@
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 SMTP test connection response.")
public class SMTPResponse {
@Schema(description = "Parameter containing status code of the response.")
private int statusCode;
@Schema(description = "Parameter containing the reason phrase of the response.")
private String reasonPhrase;
}

View File

@ -1,13 +1,17 @@
package com.knecon.fforesight.tenantusermanagement.service;
import org.keycloak.admin.client.resource.RealmResource;
import org.keycloak.admin.client.resource.UserResource;
import org.keycloak.representations.idm.UserRepresentation;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import com.knecon.fforesight.tenantcommons.model.AuthDetails;
import com.knecon.fforesight.tenantusermanagement.properties.TenantUserManagementProperties;
import com.nimbusds.jwt.JWTParser;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
@Service
@ -19,12 +23,26 @@ public class RealmService {
private final TenantUserManagementProperties tenantUserManagementProperties;
public RealmResource realm(String tenantId) {
return keycloak.getAdminClient().realm(tenantId);
}
public void setServiceAccountEmail(UserResource serviceAccount, String email) {
UserRepresentation user = serviceAccount.toRepresentation();
user.setEmail(email);
serviceAccount.update(user);
}
@SneakyThrows
public UserResource getServiceAccount(String realm) {
String token = keycloak.getAdminClient().tokenManager().getAccessToken().getToken();
String userId = JWTParser.parse(token).getJWTClaimsSet().getSubject();
return realm(realm).users().get(userId);
}
public AuthDetails getOpenIdConnectDetails(String tenantId) {

View File

@ -299,7 +299,7 @@ public class UserService {
try {
changeEmailClient.tokenManager().getAccessTokenString();
} catch (NotAuthorizedException e) {
throw new ResponseStatusException(HttpStatus.BAD_REQUEST);
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Invalid password");
}
changeEmailClient.close();

View File

@ -9,12 +9,16 @@ import com.knecon.fforesight.AbstractTenantUserManagementIntegrationTest;
import com.knecon.fforesight.feigntestclients.external.SMTPConfigurationClient;
import com.knecon.fforesight.tenantcommons.TenantContext;
import com.knecon.fforesight.tenantusermanagement.model.SMTPConfiguration;
import com.knecon.fforesight.tenantusermanagement.service.RealmService;
public class SMTPConfigurationTest extends AbstractTenantUserManagementIntegrationTest {
@Autowired
private SMTPConfigurationClient smtpConfigurationClient;
@Autowired
private RealmService realmService;
@Test
public void testSMTPConfiguration() {
@ -27,14 +31,7 @@ public class SMTPConfigurationTest extends AbstractTenantUserManagementIntegrati
System.out.println(e.getMessage());
}
SMTPConfiguration newConfig = new SMTPConfiguration();
newConfig.setAuth(true);
newConfig.setFrom("from@knecon.com");
newConfig.setHost("test.knecon.com");
newConfig.setPassword("secret");
newConfig.setUser("user");
newConfig.setStarttls(true);
newConfig.setSsl(false);
SMTPConfiguration newConfig = provideSMTPConfiguration();
smtpConfigurationClient.updateSMTPConfiguration(newConfig);
var currentSMTPConfiguration = smtpConfigurationClient.getCurrentSMTPConfiguration();
@ -50,4 +47,39 @@ public class SMTPConfigurationTest extends AbstractTenantUserManagementIntegrati
}
@Test
public void testSMTPConnection() {
TenantContext.setTenantId(AbstractTenantUserManagementIntegrationTest.TEST_TENANT_ID);
SMTPConfiguration smtpConfiguration = provideSMTPConfiguration();
smtpConfigurationClient.updateSMTPConfiguration(smtpConfiguration);
var response = smtpConfigurationClient.testSMTPConfiguration(smtpConfiguration);
// Fails because we are not using a real email/pw
assertThat(response.getStatusCode()).isEqualTo(500);
assertThat(response.getReasonPhrase()).isEqualTo("Internal Server Error");
// Check the email was cleared
var serviceAccount = realmService.getServiceAccount("master");
assertThat(serviceAccount.toRepresentation().getEmail()).isNull();
TenantContext.clear();
}
private SMTPConfiguration provideSMTPConfiguration() {
SMTPConfiguration smtpConfiguration = new SMTPConfiguration();
smtpConfiguration.setAuth(true);
smtpConfiguration.setFrom("from@knecon.com");
smtpConfiguration.setHost("test.knecon.com");
smtpConfiguration.setPassword("secret");
smtpConfiguration.setUser("user");
smtpConfiguration.setStarttls(true);
smtpConfiguration.setSsl(false);
return smtpConfiguration;
}
}