Pull request #657: RED-5504

Merge in RED/persistence-service from RED-5504 to master

* commit '663770bf9b262c30af3f5c9ccf034bea65100dc2':
  RED-5504 - Prevent using exact same database schema/buckets/index for multiple tenants - remove tenantsHostAndSchemaMap - update junit test
  RED-5504 - Prevent using exact same database schema/buckets/index for multiple tenants - update junit test
  RED-5504 - Prevent using exact same database schema/buckets/index for multiple tenants - add junit test
  RED-5504 - Prevent using exact same database schema/buckets/index for multiple tenants - add unique constraints to tenants table
This commit is contained in:
Corina Olariu 2023-04-04 14:21:46 +02:00
commit 4c3e116447
4 changed files with 226 additions and 1 deletions

View File

@ -87,7 +87,6 @@ public class TenantManagementService {
private final KeyCloakRoleManagerService keyCloakRoleManagerService;
private final KeyCloakAdminClientService keycloak;
public TenantManagementService(EncryptionDecryptionService encryptionService,
@Qualifier("tenantLiquibaseProperties") LiquibaseProperties liquibaseProperties,
ResourceLoader resourceLoader,

View File

@ -5,3 +5,5 @@ databaseChangeLog:
file: db/changelog/master/2-quartz.changelog.yaml
- include:
file: db/changelog/master/3-detailed-db-connection.changelog.yaml
- include:
file: db/changelog/master/4-add-unique-constraint-for-tenants-table.yaml

View File

@ -0,0 +1,17 @@
databaseChangeLog:
- changeSet:
id: add-unique-constraint-for-tenants-table
author: corinaolariu
changes:
- addUniqueConstraint:
columnNames: db_host, db_schema
constraintName: unique_constraint_tenant_host_shema
tableName: tenant
- addUniqueConstraint:
columnNames: storage_s3_endpoint, storage_s3_region, storage_s3_bucket_name
constraintName: unique_constraint_tenant_s3_storage
tableName: tenant
- addUniqueConstraint:
columnNames: storage_azure_connection_string, storage_azure_container_name
constraintName: unique_constraint_tenant_azure_storage
tableName: tenant

View File

@ -0,0 +1,207 @@
package com.iqser.red.service.peristence.v1.server.integration.tests;
import static org.assertj.core.api.Assertions.assertThat;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import com.iqser.red.keycloak.commons.roles.ApplicationRoles;
import com.iqser.red.service.peristence.v1.server.integration.client.TenantsClient;
import com.iqser.red.service.peristence.v1.server.integration.utils.AbstractPersistenceServerServiceTest;
import com.iqser.red.service.persistence.service.v1.api.shared.model.multitenancy.AzureStorageConnection;
import com.iqser.red.service.persistence.service.v1.api.shared.model.multitenancy.DatabaseConnection;
import com.iqser.red.service.persistence.service.v1.api.shared.model.multitenancy.RedUser;
import com.iqser.red.service.persistence.service.v1.api.shared.model.multitenancy.S3StorageConnection;
import com.iqser.red.service.persistence.service.v1.api.shared.model.multitenancy.SearchConnection;
import com.iqser.red.service.persistence.service.v1.api.shared.model.multitenancy.TenantRequest;
import com.iqser.red.service.persistence.service.v1.api.shared.model.multitenancy.TenantResponse;
import feign.FeignException;
public class TenantsTest extends AbstractPersistenceServerServiceTest {
@Autowired
private TenantsClient tenantsClient;
@Test
public void testCreateTenantWithSameHostAndSchema() {
TenantResponse firstTenant = tenantsClient.getTenants().get(0);
var tenantRequest = TenantRequest.builder()
.tenantId("redaction2")
.displayName("Redaction default2")
.guid(UUID.randomUUID().toString())
.databaseConnection(DatabaseConnection.builder()
.driver("postgresql")
.host("localhost")
.port(firstTenant.getDatabaseConnection().getPort())
.database("redaction")
.schema("myschema")
.username("redaction")
.password("redaction")
.build())
.searchConnection(SearchConnection.builder()
.hosts(Set.of("elasticsearchHost2"))
.port(9200)
.scheme("https2")
.username("elastic")
.numberOfShards("1")
.numberOfReplicas("5")
.build())
.s3StorageConnection(S3StorageConnection.builder()
.key("key")
.secret("secret")
.signerType("signerType")
.bucketName("bucketName2")
.region("eu")
.endpoint("endpoint2")
.build())
.redUsers(List.of(RedUser.builder().username("user").password("password").redRoles(ApplicationRoles.ROLE_DATA.keySet()).build(),
RedUser.builder().username("manageradmin1@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();
Exception exception = Assertions.assertThrows(FeignException.Conflict.class, () -> {
tenantsClient.createTenant(tenantRequest);
});
String expectedMessage = "An object of type tenant already exists";
String actualMessage = exception.getMessage();
assertThat(actualMessage).contains(expectedMessage);
}
@Test
public void testCreateTenantWithDuplicateStorageS3() {
TenantResponse firstTenant = tenantsClient.getTenants().get(0);
var tenantRequest = TenantRequest.builder()
.tenantId("redaction2")
.displayName("Redaction default2")
.guid(UUID.randomUUID().toString())
.databaseConnection(DatabaseConnection.builder()
.driver("postgresql")
.host("localhost")
.port(firstTenant.getDatabaseConnection().getPort())
.database("redaction")
.schema("myschema2")
.username("redaction")
.password("redaction")
.build())
.searchConnection(SearchConnection.builder()
.hosts(Set.of("elasticsearchHost2"))
.port(9200)
.scheme("https2")
.username("elastic")
.numberOfShards("1")
.numberOfReplicas("5")
.build())
.s3StorageConnection(S3StorageConnection.builder()
.key("key")
.secret("secret")
.signerType("signerType")
.bucketName("bucketName")
.region("eu")
.endpoint("endpoint")
.build())
.redUsers(List.of(RedUser.builder().username("user").password("password").redRoles(ApplicationRoles.ROLE_DATA.keySet()).build(),
RedUser.builder().username("manageradmin1@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();
Exception exception = Assertions.assertThrows(FeignException.Conflict.class, () -> {
tenantsClient.createTenant(tenantRequest);
});
String expectedMessage = "An object of type tenant already exists";
String actualMessage = exception.getMessage();
assertThat(actualMessage).contains(expectedMessage);
}
@Test
public void testCreateTenantWithDuplicateAzure() {
TenantResponse firstTenant = tenantsClient.getTenants().get(0);
var tenantRequest = TenantRequest.builder()
.tenantId("redaction2")
.displayName("Redaction default2")
.guid(UUID.randomUUID().toString())
.databaseConnection(DatabaseConnection.builder()
.driver("postgresql")
.host("localhost")
.port(firstTenant.getDatabaseConnection().getPort())
.database("redaction")
.schema("myschema2")
.username("redaction")
.password("redaction")
.build())
.searchConnection(SearchConnection.builder()
.hosts(Set.of("elasticsearchHost2"))
.port(9200)
.scheme("https2")
.username("elastic")
.numberOfShards("1")
.numberOfReplicas("5")
.build())
.azureStorageConnection(AzureStorageConnection.builder()
.connectionString("connection")
.containerName("container")
.build())
.redUsers(List.of(RedUser.builder().username("user").password("password").redRoles(ApplicationRoles.ROLE_DATA.keySet()).build(),
RedUser.builder().username("manageradmin1@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();
tenantsClient.createTenant(tenantRequest);
assertThat(tenantsClient.getTenants().size()).isEqualTo(2);
var tenantRequest2 = TenantRequest.builder()
.tenantId("redaction2")
.displayName("Redaction default2")
.guid(UUID.randomUUID().toString())
.databaseConnection(DatabaseConnection.builder()
.driver("postgresql")
.host("localhost")
.port(firstTenant.getDatabaseConnection().getPort())
.database("redaction")
.schema("myschema3")
.username("redaction")
.password("redaction")
.build())
.searchConnection(SearchConnection.builder()
.hosts(Set.of("elasticsearchHost2"))
.port(9200)
.scheme("https2")
.username("elastic")
.numberOfShards("1")
.numberOfReplicas("5")
.build())
.azureStorageConnection(AzureStorageConnection.builder()
.connectionString("connection")
.containerName("container")
.build())
.redUsers(List.of(RedUser.builder().username("user").password("password").redRoles(ApplicationRoles.ROLE_DATA.keySet()).build(),
RedUser.builder().username("manageradmin1@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();
Exception exception = Assertions.assertThrows(FeignException.Conflict.class, () -> {
tenantsClient.createTenant(tenantRequest);
});
String expectedMessage = "An object of type tenant already exists";
String actualMessage = exception.getMessage();
assertThat(actualMessage).contains(expectedMessage);
}
}