RED-5504 - Prevent using exact same database schema/buckets/index for multiple tenants

- remove tenantsHostAndSchemaMap
- update junit test
This commit is contained in:
devplant 2023-04-04 14:43:20 +03:00
parent de8d1178e7
commit 663770bf9b
2 changed files with 27 additions and 34 deletions

View File

@ -12,7 +12,6 @@ import java.sql.DriverManager;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.UUID; import java.util.UUID;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -87,8 +86,6 @@ public class TenantManagementService {
private final GeneralConfigurationService generalConfigurationService; private final GeneralConfigurationService generalConfigurationService;
private final KeyCloakRoleManagerService keyCloakRoleManagerService; private final KeyCloakRoleManagerService keyCloakRoleManagerService;
private final KeyCloakAdminClientService keycloak; private final KeyCloakAdminClientService keycloak;
private final Map<String, String> tenantsHostAndSchemaMap = new HashMap<>();
public TenantManagementService(EncryptionDecryptionService encryptionService, public TenantManagementService(EncryptionDecryptionService encryptionService,
@Qualifier("tenantLiquibaseProperties") LiquibaseProperties liquibaseProperties, @Qualifier("tenantLiquibaseProperties") LiquibaseProperties liquibaseProperties,
@ -203,16 +200,8 @@ public class TenantManagementService {
} }
private void checkDuplicateHostAndSchema(String hostAndSchemaName) {
if (tenantsHostAndSchemaMap.containsValue(hostAndSchemaName)) {
throw ConflictException.withObjectName("host and schema");
}
}
private void createSchema(TenantRequest tenantRequest) { private void createSchema(TenantRequest tenantRequest) {
checkDuplicateHostAndSchema(buildHostAndSchemaName(tenantRequest.getDatabaseConnection()));
var jdbcUrl = JDBCUtils.buildJdbcUrl(tenantRequest.getDatabaseConnection()); var jdbcUrl = JDBCUtils.buildJdbcUrl(tenantRequest.getDatabaseConnection());
try (Connection connection = DriverManager.getConnection(jdbcUrl, try (Connection connection = DriverManager.getConnection(jdbcUrl,
tenantRequest.getDatabaseConnection().getUsername(), tenantRequest.getDatabaseConnection().getUsername(),
@ -222,20 +211,11 @@ public class TenantManagementService {
jdbcTemplate.execute((StatementCallback<Boolean>) stmt -> stmt.execute("CREATE SCHEMA " + tenantRequest.getDatabaseConnection().getSchema())); jdbcTemplate.execute((StatementCallback<Boolean>) stmt -> stmt.execute("CREATE SCHEMA " + tenantRequest.getDatabaseConnection().getSchema()));
jdbcTemplate.execute((StatementCallback<Boolean>) stmt -> stmt.execute("GRANT USAGE ON SCHEMA " + tenantRequest.getDatabaseConnection() jdbcTemplate.execute((StatementCallback<Boolean>) stmt -> stmt.execute("GRANT USAGE ON SCHEMA " + tenantRequest.getDatabaseConnection()
.getSchema() + " TO " + tenantRequest.getDatabaseConnection().getUsername())); .getSchema() + " TO " + tenantRequest.getDatabaseConnection().getUsername()));
tenantsHostAndSchemaMap.put(tenantRequest.getTenantId(), buildHostAndSchemaName(tenantRequest.getDatabaseConnection()));
} catch (Exception e) { } catch (Exception e) {
log.info("Could not create schema, ignoring"); log.info("Could not create schema, ignoring");
} }
} }
private String buildHostAndSchemaName(DatabaseConnection databaseConnection) {
StringBuilder sb = new StringBuilder(databaseConnection.getHost())
.append("currentSchema=")
.append(databaseConnection.getSchema());
return sb.toString();
}
private boolean tryToAccessRealm(String tenantId) { private boolean tryToAccessRealm(String tenantId) {

View File

@ -6,6 +6,7 @@ import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.UUID; import java.util.UUID;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@ -30,6 +31,8 @@ public class TenantsTest extends AbstractPersistenceServerServiceTest {
@Test @Test
public void testCreateTenantWithSameHostAndSchema() { public void testCreateTenantWithSameHostAndSchema() {
TenantResponse firstTenant = tenantsClient.getTenants().get(0);
var tenantRequest = TenantRequest.builder() var tenantRequest = TenantRequest.builder()
.tenantId("redaction2") .tenantId("redaction2")
.displayName("Redaction default2") .displayName("Redaction default2")
@ -37,7 +40,7 @@ public class TenantsTest extends AbstractPersistenceServerServiceTest {
.databaseConnection(DatabaseConnection.builder() .databaseConnection(DatabaseConnection.builder()
.driver("postgresql") .driver("postgresql")
.host("localhost") .host("localhost")
.port("port") .port(firstTenant.getDatabaseConnection().getPort())
.database("redaction") .database("redaction")
.schema("myschema") .schema("myschema")
.username("redaction") .username("redaction")
@ -64,11 +67,15 @@ public class TenantsTest extends AbstractPersistenceServerServiceTest {
RedUser.builder().username("manageradmin2@test.com").password("secret").redRoles(ApplicationRoles.ROLE_DATA.keySet()).build())) RedUser.builder().username("manageradmin2@test.com").password("secret").redRoles(ApplicationRoles.ROLE_DATA.keySet()).build()))
.build(); .build();
try { Exception exception = Assertions.assertThrows(FeignException.Conflict.class, () -> {
tenantsClient.createTenant(tenantRequest); tenantsClient.createTenant(tenantRequest);
} catch(FeignException e) { });
assertThat(e.status()).isEqualTo(409);
} String expectedMessage = "An object of type tenant already exists";
String actualMessage = exception.getMessage();
assertThat(actualMessage).contains(expectedMessage);
} }
@Test @Test
@ -110,11 +117,14 @@ public class TenantsTest extends AbstractPersistenceServerServiceTest {
RedUser.builder().username("manageradmin2@test.com").password("secret").redRoles(ApplicationRoles.ROLE_DATA.keySet()).build())) RedUser.builder().username("manageradmin2@test.com").password("secret").redRoles(ApplicationRoles.ROLE_DATA.keySet()).build()))
.build(); .build();
try { Exception exception = Assertions.assertThrows(FeignException.Conflict.class, () -> {
tenantsClient.createTenant(tenantRequest); tenantsClient.createTenant(tenantRequest);
} catch(FeignException e) { });
assertThat(e.status()).isEqualTo(409);
} String expectedMessage = "An object of type tenant already exists";
String actualMessage = exception.getMessage();
assertThat(actualMessage).contains(expectedMessage);
} }
@Test @Test
@ -185,10 +195,13 @@ public class TenantsTest extends AbstractPersistenceServerServiceTest {
RedUser.builder().username("manageradmin2@test.com").password("secret").redRoles(ApplicationRoles.ROLE_DATA.keySet()).build())) RedUser.builder().username("manageradmin2@test.com").password("secret").redRoles(ApplicationRoles.ROLE_DATA.keySet()).build()))
.build(); .build();
try { Exception exception = Assertions.assertThrows(FeignException.Conflict.class, () -> {
tenantsClient.createTenant(tenantRequest2); tenantsClient.createTenant(tenantRequest);
} catch(FeignException e) { });
assertThat(e.status()).isEqualTo(409);
} String expectedMessage = "An object of type tenant already exists";
String actualMessage = exception.getMessage();
assertThat(actualMessage).contains(expectedMessage);
} }
} }