From 710a2f88ac883e09ff3d01160afb78027614333e Mon Sep 17 00:00:00 2001 From: deiflaender Date: Wed, 22 Mar 2023 13:08:29 +0100 Subject: [PATCH 01/10] RED-4515: Create realm on createTenant --- .../keycloak/commons/UserListingService.java | 4 + .../service/TenantManagementService.java | 95 ++++++++++++++++++- 2 files changed, 97 insertions(+), 2 deletions(-) diff --git a/persistence-service-v1/keycloak-commons/src/main/java/com/iqser/red/keycloak/commons/UserListingService.java b/persistence-service-v1/keycloak-commons/src/main/java/com/iqser/red/keycloak/commons/UserListingService.java index 379738085..ac234c242 100644 --- a/persistence-service-v1/keycloak-commons/src/main/java/com/iqser/red/keycloak/commons/UserListingService.java +++ b/persistence-service-v1/keycloak-commons/src/main/java/com/iqser/red/keycloak/commons/UserListingService.java @@ -36,6 +36,10 @@ public class UserListingService { @Cacheable(value = USERS_CACHE, key = "'tenantId'") public List getAllUsers(String tenantId) { + if(tenantId == "master"){ + return new ArrayList<>(); + } + return retryTemplate.execute(context -> { var realm = realmService.realm(tenantId); diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/TenantManagementService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/TenantManagementService.java index 454bc1bfc..7e7121567 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/TenantManagementService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/TenantManagementService.java @@ -1,9 +1,15 @@ package com.iqser.red.service.persistence.management.v1.processor.service; +import static com.iqser.red.keycloak.commons.roles.ApplicationRoles.RED_ADMIN_ROLE; +import static com.iqser.red.keycloak.commons.roles.ApplicationRoles.RED_MANAGER_ROLE; +import static com.iqser.red.keycloak.commons.roles.ApplicationRoles.RED_USER_ADMIN_ROLE; +import static com.iqser.red.keycloak.commons.roles.ApplicationRoles.RED_USER_ROLE; + import java.net.URI; import java.net.URISyntaxException; import java.sql.Connection; import java.sql.DriverManager; +import java.util.HashMap; import java.util.List; import java.util.Set; import java.util.UUID; @@ -11,6 +17,12 @@ import java.util.stream.Collectors; import javax.sql.DataSource; +import org.keycloak.representations.idm.ClientRepresentation; +import org.keycloak.representations.idm.CredentialRepresentation; +import org.keycloak.representations.idm.RealmRepresentation; +import org.keycloak.representations.idm.RoleRepresentation; +import org.keycloak.representations.idm.RolesRepresentation; +import org.keycloak.representations.idm.UserRepresentation; import org.postgresql.util.PSQLException; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.autoconfigure.liquibase.LiquibaseProperties; @@ -19,6 +31,7 @@ import org.springframework.core.io.ResourceLoader; import org.springframework.jdbc.datasource.SingleConnectionDataSource; import org.springframework.stereotype.Service; +import com.iqser.red.keycloak.commons.KeyCloakAdminClientService; import com.iqser.red.service.persistence.management.v1.processor.exception.ConflictException; import com.iqser.red.service.persistence.management.v1.processor.exception.NotFoundException; import com.iqser.red.service.persistence.management.v1.processor.migration.AsyncMigrationStarterService; @@ -65,13 +78,17 @@ public class TenantManagementService { private final AsyncMigrationStarterService asyncMigrationStarterService; private final GeneralConfigurationService generalConfigurationService; private final KeyCloakRoleManagerService keyCloakRoleManagerService; + private final KeyCloakAdminClientService keycloak; public TenantManagementService(EncryptionDecryptionService encryptionService, @Qualifier("tenantLiquibaseProperties") LiquibaseProperties liquibaseProperties, ResourceLoader resourceLoader, TenantRepository tenantRepository, - AsyncMigrationStarterService asyncMigrationStarterService, GeneralConfigurationService generalConfigurationService, KeyCloakRoleManagerService keyCloakRoleManagerService) { + AsyncMigrationStarterService asyncMigrationStarterService, + GeneralConfigurationService generalConfigurationService, + KeyCloakRoleManagerService keyCloakRoleManagerService, + KeyCloakAdminClientService keycloak) { this.encryptionService = encryptionService; this.liquibaseProperties = liquibaseProperties; @@ -80,6 +97,7 @@ public class TenantManagementService { this.asyncMigrationStarterService = asyncMigrationStarterService; this.generalConfigurationService = generalConfigurationService; this.keyCloakRoleManagerService = keyCloakRoleManagerService; + this.keycloak = keycloak; } @@ -145,6 +163,8 @@ public class TenantManagementService { tenantRepository.save(tenantEntity); + createRealm(tenantRequest.getTenantId()); + generalConfigurationService.initGeneralConfiguration(tenantRequest.getTenantId()); keyCloakRoleManagerService.updateRoles(tenantRequest.getTenantId()); asyncMigrationStarterService.runForTenant(tenantRequest.getTenantId()); @@ -155,6 +175,78 @@ public class TenantManagementService { } + private void createRealm(String tenantId) { + + var redaction = new RealmRepresentation(); + redaction.setId(tenantId); + redaction.setRealm(tenantId); + redaction.setEnabled(true); + + var redactionClient = new ClientRepresentation(); + redactionClient.setId("redaction"); + redactionClient.setEnabled(true); + redactionClient.setName("redaction"); + redactionClient.setStandardFlowEnabled(true); + redactionClient.setImplicitFlowEnabled(true); + redactionClient.setDirectAccessGrantsEnabled(true); + + var redactionSystemClient = new ClientRepresentation(); + redactionSystemClient.setId("redaction-system"); + redactionSystemClient.setEnabled(true); + redactionSystemClient.setName("redaction-system"); + redactionSystemClient.setSecret("Gc0WcXOPcefzLyRJ5BiYk169V7VvzXxT"); + redactionSystemClient.setDirectAccessGrantsEnabled(true); + redactionSystemClient.setStandardFlowEnabled(true); + redactionSystemClient.setImplicitFlowEnabled(true); + redactionSystemClient.setDirectAccessGrantsEnabled(true); + + redaction.setClients(List.of(redactionClient, redactionSystemClient)); + + var redUserRole = new RoleRepresentation(); + redUserRole.setComposite(true); + redUserRole.setName(RED_USER_ROLE); + redUserRole.setContainerId("redaction"); + + var redManagerRole = new RoleRepresentation(); + redManagerRole.setComposite(true); + redManagerRole.setName(RED_MANAGER_ROLE); + redManagerRole.setContainerId("redaction"); + + var redAdminRole = new RoleRepresentation(); + redAdminRole.setComposite(true); + redAdminRole.setName(RED_ADMIN_ROLE); + redAdminRole.setContainerId("redaction"); + + var redUserAdminRole = new RoleRepresentation(); + redUserAdminRole.setComposite(true); + redUserAdminRole.setName(RED_USER_ADMIN_ROLE); + redUserAdminRole.setContainerId("redaction"); + + RolesRepresentation rolesRepresentation = new RolesRepresentation(); + rolesRepresentation.setRealm(List.of(redUserRole, redManagerRole, redAdminRole, redUserAdminRole)); + redaction.setRoles(rolesRepresentation); + + var credentialRepresentation = new CredentialRepresentation(); + credentialRepresentation.setType("password"); + credentialRepresentation.setValue("OsloImWinter!23"); + + var defaultUser = new UserRepresentation(); + defaultUser.setUsername("manageradmin"); + defaultUser.setCredentials(List.of(credentialRepresentation)); + defaultUser.setEmailVerified(true); + defaultUser.setRealmRoles(List.of(RED_USER_ROLE, RED_MANAGER_ROLE, RED_ADMIN_ROLE, RED_USER_ADMIN_ROLE, "uma_authorization", "offline_access")); + + var clientRoles = new HashMap>(); + clientRoles.put("account", List.of("manage-account", "view-profile")); + + defaultUser.setClientRoles(clientRoles); + defaultUser.setEnabled(true); + redaction.setUsers(List.of(defaultUser)); + + keycloak.getAdminClient().realms().create(redaction); + } + + @SneakyThrows private void validateJdbcUrl(String jdbcUrl) { @@ -173,7 +265,6 @@ public class TenantManagementService { } - private void runLiquibase(DataSource dataSource) throws LiquibaseException { SpringLiquibase liquibase = getSpringLiquibase(dataSource); From e69a988e394063258f6e068fe60cad4de4a5c526 Mon Sep 17 00:00:00 2001 From: deiflaender Date: Thu, 23 Mar 2023 15:53:50 +0100 Subject: [PATCH 02/10] RED-4515: Create realm on create tenant --- .../HeaderBasedKeycloakRealmResolver.java | 1 + .../service/TenantManagementService.java | 65 ++++++++------ .../src/main/resources/application.yml | 6 +- .../AbstractPersistenceServerServiceTest.java | 13 ++- .../utils/KeyCloakTestContainer.java | 90 +++++++++++++++---- .../src/test/resources/application.yml | 8 +- 6 files changed, 128 insertions(+), 55 deletions(-) diff --git a/persistence-service-v1/persistence-service-external-api-impl-v1/src/main/java/com/iqser/red/persistence/service/v1/external/api/impl/multitenacy/HeaderBasedKeycloakRealmResolver.java b/persistence-service-v1/persistence-service-external-api-impl-v1/src/main/java/com/iqser/red/persistence/service/v1/external/api/impl/multitenacy/HeaderBasedKeycloakRealmResolver.java index fc60bab83..576088edd 100644 --- a/persistence-service-v1/persistence-service-external-api-impl-v1/src/main/java/com/iqser/red/persistence/service/v1/external/api/impl/multitenacy/HeaderBasedKeycloakRealmResolver.java +++ b/persistence-service-v1/persistence-service-external-api-impl-v1/src/main/java/com/iqser/red/persistence/service/v1/external/api/impl/multitenacy/HeaderBasedKeycloakRealmResolver.java @@ -49,6 +49,7 @@ public class HeaderBasedKeycloakRealmResolver implements KeycloakConfigResolver var config = MagicConverter.convert(adapterConfig, AdapterConfig.class); config.setRealm(tenant); + config.setResource(tenant); return KeycloakDeploymentBuilder.build(config); } diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/TenantManagementService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/TenantManagementService.java index 7e7121567..a03c4f3ed 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/TenantManagementService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/TenantManagementService.java @@ -9,7 +9,6 @@ import java.net.URI; import java.net.URISyntaxException; import java.sql.Connection; import java.sql.DriverManager; -import java.util.HashMap; import java.util.List; import java.util.Set; import java.util.UUID; @@ -22,7 +21,6 @@ import org.keycloak.representations.idm.CredentialRepresentation; import org.keycloak.representations.idm.RealmRepresentation; import org.keycloak.representations.idm.RoleRepresentation; import org.keycloak.representations.idm.RolesRepresentation; -import org.keycloak.representations.idm.UserRepresentation; import org.postgresql.util.PSQLException; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.autoconfigure.liquibase.LiquibaseProperties; @@ -32,6 +30,7 @@ import org.springframework.jdbc.datasource.SingleConnectionDataSource; import org.springframework.stereotype.Service; import com.iqser.red.keycloak.commons.KeyCloakAdminClientService; +import com.iqser.red.keycloak.commons.KeyCloakSettings; import com.iqser.red.service.persistence.management.v1.processor.exception.ConflictException; import com.iqser.red.service.persistence.management.v1.processor.exception.NotFoundException; import com.iqser.red.service.persistence.management.v1.processor.migration.AsyncMigrationStarterService; @@ -79,6 +78,7 @@ public class TenantManagementService { private final GeneralConfigurationService generalConfigurationService; private final KeyCloakRoleManagerService keyCloakRoleManagerService; private final KeyCloakAdminClientService keycloak; + private final KeyCloakSettings keyCloakSettings; public TenantManagementService(EncryptionDecryptionService encryptionService, @@ -88,7 +88,7 @@ public class TenantManagementService { AsyncMigrationStarterService asyncMigrationStarterService, GeneralConfigurationService generalConfigurationService, KeyCloakRoleManagerService keyCloakRoleManagerService, - KeyCloakAdminClientService keycloak) { + KeyCloakAdminClientService keycloak, KeyCloakSettings keyCloakSettings) { this.encryptionService = encryptionService; this.liquibaseProperties = liquibaseProperties; @@ -98,6 +98,7 @@ public class TenantManagementService { this.generalConfigurationService = generalConfigurationService; this.keyCloakRoleManagerService = keyCloakRoleManagerService; this.keycloak = keycloak; + this.keyCloakSettings = keyCloakSettings; } @@ -164,6 +165,7 @@ public class TenantManagementService { tenantRepository.save(tenantEntity); createRealm(tenantRequest.getTenantId()); + Thread.sleep(30_000); generalConfigurationService.initGeneralConfiguration(tenantRequest.getTenantId()); keyCloakRoleManagerService.updateRoles(tenantRequest.getTenantId()); @@ -183,25 +185,38 @@ public class TenantManagementService { redaction.setEnabled(true); var redactionClient = new ClientRepresentation(); - redactionClient.setId("redaction"); redactionClient.setEnabled(true); redactionClient.setName("redaction"); + redactionClient.setClientId("redaction"); redactionClient.setStandardFlowEnabled(true); redactionClient.setImplicitFlowEnabled(true); redactionClient.setDirectAccessGrantsEnabled(true); + + var swaggerClient = new ClientRepresentation(); + swaggerClient.setEnabled(true); + swaggerClient.setName("swagger-ui-client"); + swaggerClient.setClientId("swagger-ui-client"); + swaggerClient.setStandardFlowEnabled(true); + swaggerClient.setImplicitFlowEnabled(false); + swaggerClient.setDirectAccessGrantsEnabled(false); + swaggerClient.setServiceAccountsEnabled(true); + swaggerClient.setAuthorizationServicesEnabled(true); + swaggerClient.setSecret("OsloImWinter!23"); + + var redactionSystemClient = new ClientRepresentation(); - redactionSystemClient.setId("redaction-system"); redactionSystemClient.setEnabled(true); - redactionSystemClient.setName("redaction-system"); - redactionSystemClient.setSecret("Gc0WcXOPcefzLyRJ5BiYk169V7VvzXxT"); - redactionSystemClient.setDirectAccessGrantsEnabled(true); - redactionSystemClient.setStandardFlowEnabled(true); - redactionSystemClient.setImplicitFlowEnabled(true); - redactionSystemClient.setDirectAccessGrantsEnabled(true); - - redaction.setClients(List.of(redactionClient, redactionSystemClient)); + redactionSystemClient.setName(keyCloakSettings.getClientId()); + redactionSystemClient.setClientId(keyCloakSettings.getClientId()); + redactionSystemClient.setSecret(keyCloakSettings.getClientSecret()); + swaggerClient.setStandardFlowEnabled(true); + swaggerClient.setImplicitFlowEnabled(true); + swaggerClient.setDirectAccessGrantsEnabled(true); + swaggerClient.setServiceAccountsEnabled(true); + swaggerClient.setAuthorizationServicesEnabled(true); + redaction.setClients(List.of(redactionClient, redactionSystemClient, swaggerClient)); var redUserRole = new RoleRepresentation(); redUserRole.setComposite(true); redUserRole.setName(RED_USER_ROLE); @@ -230,18 +245,18 @@ public class TenantManagementService { credentialRepresentation.setType("password"); credentialRepresentation.setValue("OsloImWinter!23"); - var defaultUser = new UserRepresentation(); - defaultUser.setUsername("manageradmin"); - defaultUser.setCredentials(List.of(credentialRepresentation)); - defaultUser.setEmailVerified(true); - defaultUser.setRealmRoles(List.of(RED_USER_ROLE, RED_MANAGER_ROLE, RED_ADMIN_ROLE, RED_USER_ADMIN_ROLE, "uma_authorization", "offline_access")); - - var clientRoles = new HashMap>(); - clientRoles.put("account", List.of("manage-account", "view-profile")); - - defaultUser.setClientRoles(clientRoles); - defaultUser.setEnabled(true); - redaction.setUsers(List.of(defaultUser)); +// var defaultUser = new UserRepresentation(); +// defaultUser.setUsername("manageradmin"); +// defaultUser.setCredentials(List.of(credentialRepresentation)); +// defaultUser.setEmailVerified(true); +// defaultUser.setRealmRoles(List.of(RED_USER_ROLE, RED_MANAGER_ROLE, RED_ADMIN_ROLE, RED_USER_ADMIN_ROLE, "uma_authorization", "offline_access")); +// +// var clientRoles = new HashMap>(); +// clientRoles.put("account", List.of("manage-account", "view-profile")); +// +// defaultUser.setClientRoles(clientRoles); +// defaultUser.setEnabled(true); +// redaction.setUsers(List.of(defaultUser)); keycloak.getAdminClient().realms().create(redaction); } diff --git a/persistence-service-v1/persistence-service-server-v1/src/main/resources/application.yml b/persistence-service-v1/persistence-service-server-v1/src/main/resources/application.yml index c0a1e0fbb..5a574783e 100644 --- a/persistence-service-v1/persistence-service-server-v1/src/main/resources/application.yml +++ b/persistence-service-v1/persistence-service-server-v1/src/main/resources/application.yml @@ -131,15 +131,15 @@ bucket4j: keycloak: sslRequired: none auth-server-url: https://red-staging.iqser.cloud/auth - realm: redaction - resource: redaction + realm: master + resource: redaction-system disableTrustManager: true useResourceRoleMappings: true enabled: true commons: keycloak: - applicationClientId: ${keycloak.resource:redaction} + applicationClientId: ${keycloak.resource:redaction-system} clientId: ${keycloak.client.id} clientSecret: ${keycloak.client.secret} realm: ${keycloak.realm} diff --git a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/utils/AbstractPersistenceServerServiceTest.java b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/utils/AbstractPersistenceServerServiceTest.java index 525d98b73..177b08c4f 100644 --- a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/utils/AbstractPersistenceServerServiceTest.java +++ b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/utils/AbstractPersistenceServerServiceTest.java @@ -120,8 +120,6 @@ public abstract class AbstractPersistenceServerServiceTest { @MockBean protected RedactionLogMergeService redactionLogMergeService; @MockBean - protected KeyCloakAdminClientService keyCloakAdminClientService; - @MockBean protected PDFTronClient pdfTronRedactionClient; @Autowired protected ApplicationConfigClient appConfigClient; @@ -232,7 +230,7 @@ public abstract class AbstractPersistenceServerServiceTest { TenantContext.setTenantId("redaction"); - when(keyCloakAdminClientService.getAdminClient()).thenReturn(KeyCloakTestContainer.getInstance().getKeycloakAdminClient()); +// when(keyCloakAdminClientService.getAdminClient()).thenReturn(KeyCloakTestContainer.getInstance().getKeycloakAdminClient()); userService.evictUserCache(); var allUsers = userService.getAllUsers(); @@ -432,14 +430,13 @@ public abstract class AbstractPersistenceServerServiceTest { var connectionStringDetails = "?serverTimezone=UTC&cachePrepStmts=true&useServerPrepStmts=true&rewriteBatchedStatements=true"; + var kcInstance = KeyCloakTestContainer.getInstance(); + TestPropertyValues.of("spring.redis.port=" + redisContainer.getFirstMappedPort(), "multitenancy.master.datasource.url=" + postgreSQLContainerMaster.getJdbcUrl() + connectionStringDetails, "multitenancy.master.datasource.username=" + postgreSQLContainerMaster.getUsername(), - "multitenancy.master.datasource.password=" + postgreSQLContainerMaster.getPassword()).applyTo(configurableApplicationContext.getEnvironment()); + "multitenancy.master.datasource.password=" + postgreSQLContainerMaster.getPassword(), "keycloak.auth-server-url=" + kcInstance.getAuthServerUrl(), "commons.keycloak.serverUrl=" + kcInstance.getAuthServerUrl()).applyTo(configurableApplicationContext.getEnvironment()); - var kcInstance = KeyCloakTestContainer.getInstance(); - - TestPropertyValues.of("keycloak.auth-server-url=" + kcInstance.getAuthServerUrl()); } } @@ -464,7 +461,7 @@ public abstract class AbstractPersistenceServerServiceTest { var instance = KeyCloakTestContainer.getInstance(); - when(cloakAdminClientService.getAdminClient()).thenReturn(instance.getKeycloakAdminClient()); +// when(cloakAdminClientService.getAdminClient()).thenReturn(instance.getKeycloakAdminClient()); keycloakSpringBootProperties.setAuthServerUrl(instance.getAuthServerUrl()); keyCloakSettings.setServerUrl(instance.getAuthServerUrl()); diff --git a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/utils/KeyCloakTestContainer.java b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/utils/KeyCloakTestContainer.java index 5b72aa1a1..028d37f12 100644 --- a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/utils/KeyCloakTestContainer.java +++ b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/utils/KeyCloakTestContainer.java @@ -1,9 +1,13 @@ package com.iqser.red.service.peristence.v1.server.integration.utils; +import java.util.ArrayList; +import java.util.List; + +import org.keycloak.admin.client.resource.ClientResource; +import org.keycloak.admin.client.resource.RealmResource; +import org.keycloak.admin.client.resource.UserResource; import org.keycloak.representations.idm.ClientRepresentation; -import org.keycloak.representations.idm.RealmRepresentation; -import org.keycloak.representations.idm.UserRepresentation; -import org.testcontainers.containers.PostgreSQLContainer; +import org.keycloak.representations.idm.RoleRepresentation; import dasniko.testcontainers.keycloak.KeycloakContainer; @@ -26,35 +30,91 @@ public class KeyCloakTestContainer { keycloak.start(); var adminClient = keycloak.getKeycloakAdminClient(); - var redaction = new RealmRepresentation(); - redaction.setId("redaction"); - redaction.setRealm("redaction"); - redaction.setEnabled(true); - adminClient.realms().create(redaction); + var redaction = adminClient.realm("master"); - var redactionRealm = adminClient.realm("redaction"); var redactionClient = new ClientRepresentation(); - redactionClient.setId("redaction"); redactionClient.setEnabled(true); redactionClient.setName("redaction"); redactionClient.setStandardFlowEnabled(true); redactionClient.setImplicitFlowEnabled(true); redactionClient.setDirectAccessGrantsEnabled(true); - redactionRealm.clients().create(redactionClient); - - - var redactionSystemClient = new ClientRepresentation(); +// +// RoleRepresentation createRealm = new RoleRepresentation(); +// createRealm.setName("create-realm"); +// +// RoleRepresentation viewRealm = new RoleRepresentation(); +// viewRealm.setName("view-realm"); +// +// RoleRepresentation manageRealm = new RoleRepresentation(); +// manageRealm.setName("manage-realm"); +// +// RoleRepresentation manageUsers = new RoleRepresentation(); +// manageUsers.setName("manage-users"); +// +// RoleRepresentation manageClients = new RoleRepresentation(); +// manageClients.setName("manage-clients"); + +// RolesRepresentation rolesRepresentation = new RolesRepresentation(); +// rolesRepresentation.setRealm(List.of(createRealm)); +// redaction.setRoles(rolesRepresentation); + redactionSystemClient.setId("redaction-system"); redactionSystemClient.setEnabled(true); redactionSystemClient.setName("redaction-system"); redactionSystemClient.setSecret("redaction-system"); + redactionSystemClient.setServiceAccountsEnabled(true); redactionSystemClient.setDirectAccessGrantsEnabled(true); redactionSystemClient.setStandardFlowEnabled(true); redactionSystemClient.setImplicitFlowEnabled(true); redactionSystemClient.setDirectAccessGrantsEnabled(true); - redactionRealm.clients().create(redactionSystemClient); + redaction.clients().create(redactionClient); + redaction.clients().create(redactionSystemClient); + + RealmResource myRealm = adminClient.realm("master"); + String userId = myRealm.clients().get("redaction-system").getServiceAccountUser().getId(); + UserResource serviceAccountUser = myRealm.users().get(userId); + +// ClientRepresentation clientThatOwnsRole = myRealm.clients() +// .findByClientId("realm-management").get(0); + + ClientRepresentation clientThatOwnsRole = myRealm.clients() + .findByClientId("master-realm").get(0); + + String clientIdOfRoleOwner = clientThatOwnsRole.getId(); + ClientResource clientResourceOfRoleOwner = myRealm.clients().get(clientIdOfRoleOwner); +// myRealm.clients().get(clientIdOfRoleOwner).roles().list(); +// List rolesToAssign = new ArrayList<>(); +// +// rolesToAssign.add(clientResourceOfRoleOwner.roles().get("view-users").toRepresentation()); +// rolesToAssign.add(clientResourceOfRoleOwner.roles().get("manage-realm").toRepresentation()); +// rolesToAssign.add(clientResourceOfRoleOwner.roles().get("create-realm").toRepresentation()); +// +// myRealm.clients().get(clientIdOfRoleOwner).roles().list().forEach(role -> { +// serviceAccountUser.roles().clientLevel(clientIdOfRoleOwner).add(role); +// }); + + List roles = new ArrayList<>(); + roles.addAll(myRealm.clients().get(clientIdOfRoleOwner).roles().list()); +// roles.add(myRealm.roles().get("create-realm").toRepresentation()); + serviceAccountUser.roles().clientLevel(clientIdOfRoleOwner).add(roles); + serviceAccountUser.roles().realmLevel().add(List.of(myRealm.roles().get("create-realm").toRepresentation())); + +// System.out.println(KeycloakBuilder.builder() +// .serverUrl(keycloak.getAuthServerUrl()) +// .realm("management") +// .clientId("redaction-system") +// .clientSecret("redaction-system") +// .grantType(OAuth2Constants.CLIENT_CREDENTIALS) +// .resteasyClient(new ResteasyClientBuilderImpl().connectionTTL(2, TimeUnit.SECONDS) +// .hostnameVerification(ResteasyClientBuilder.HostnameVerificationPolicy.ANY) +// .connectionPoolSize(10) +// .disableTrustManager() +// .build()) +// .build() +// .realm("management") +// .toRepresentation()); } diff --git a/persistence-service-v1/persistence-service-server-v1/src/test/resources/application.yml b/persistence-service-v1/persistence-service-server-v1/src/test/resources/application.yml index 6ff024556..fb6bb961a 100644 --- a/persistence-service-v1/persistence-service-server-v1/src/test/resources/application.yml +++ b/persistence-service-v1/persistence-service-server-v1/src/test/resources/application.yml @@ -118,15 +118,15 @@ multitenancy: keycloak: enabled: true sslRequired: none - realm: redaction - resource: redaction + realm: master + resource: master disableTrustManager: true useResourceRoleMappings: true commons: keycloak: - application-client-id: redaction - realm: redaction + application-client-id: redaction-system + realm: master client-id: redaction-system client-secret: redaction-system From 91efd63311768ae31822d446d1e64605c9b737d3 Mon Sep 17 00:00:00 2001 From: Timo Bejan Date: Thu, 23 Mar 2023 17:15:22 +0200 Subject: [PATCH 03/10] RED-4515 - kc createRealm --- .../service/KeyCloakRoleManagerService.java | 1 + .../service/TenantManagementService.java | 36 +++++++- .../v1/server/DevConfiguration.java | 83 +++++++++++++++++-- .../tests/DossierTemplateImportTest.java | 3 +- .../src/test/resources/application.yml | 2 +- 5 files changed, 109 insertions(+), 16 deletions(-) diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/KeyCloakRoleManagerService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/KeyCloakRoleManagerService.java index 079efa20b..d0c108bcc 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/KeyCloakRoleManagerService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/KeyCloakRoleManagerService.java @@ -89,6 +89,7 @@ public class KeyCloakRoleManagerService { realm.roles().create(role); } + var applicationRoleResource = realm.roles().get(applicationRole); Set composites = realm.rolesById() .getClientRoleComposites(applicationRoleResource.toRepresentation().getId(), redactionClient.toRepresentation().getId()); diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/TenantManagementService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/TenantManagementService.java index a03c4f3ed..6e9b7d8ec 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/TenantManagementService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/TenantManagementService.java @@ -32,6 +32,7 @@ import org.springframework.stereotype.Service; import com.iqser.red.keycloak.commons.KeyCloakAdminClientService; import com.iqser.red.keycloak.commons.KeyCloakSettings; import com.iqser.red.service.persistence.management.v1.processor.exception.ConflictException; +import com.iqser.red.service.persistence.management.v1.processor.exception.InternalServerErrorException; import com.iqser.red.service.persistence.management.v1.processor.exception.NotFoundException; import com.iqser.red.service.persistence.management.v1.processor.migration.AsyncMigrationStarterService; import com.iqser.red.service.persistence.management.v1.processor.multitenancy.entity.AzureStorageConnectionEntity; @@ -58,6 +59,8 @@ import lombok.extern.slf4j.Slf4j; @EnableConfigurationProperties(LiquibaseProperties.class) public class TenantManagementService { + private static final Long MAX_WAIT_TIME = 60_000L; // 60 seconds + private static final Set SUPPORTED_DATABASES = Set.of("postgresql"); private static final Set SQL_CONNECTION_ERROR_CODES = Set.of( // connection_exception @@ -88,7 +91,8 @@ public class TenantManagementService { AsyncMigrationStarterService asyncMigrationStarterService, GeneralConfigurationService generalConfigurationService, KeyCloakRoleManagerService keyCloakRoleManagerService, - KeyCloakAdminClientService keycloak, KeyCloakSettings keyCloakSettings) { + KeyCloakAdminClientService keycloak, + KeyCloakSettings keyCloakSettings) { this.encryptionService = encryptionService; this.liquibaseProperties = liquibaseProperties; @@ -165,7 +169,23 @@ public class TenantManagementService { tenantRepository.save(tenantEntity); createRealm(tenantRequest.getTenantId()); - Thread.sleep(30_000); + + var waitTime = 0; + boolean realmReady; + do { + realmReady = tryToAccessRealm(tenantRequest.getTenantId()); + if (realmReady) { + break; + } else { + Thread.sleep(1_000L); + waitTime += 1_000L; + } + + } while (waitTime < MAX_WAIT_TIME); + + if (!realmReady) { + throw new InternalServerErrorException("Failed to create KC realm"); + } generalConfigurationService.initGeneralConfiguration(tenantRequest.getTenantId()); keyCloakRoleManagerService.updateRoles(tenantRequest.getTenantId()); @@ -177,6 +197,16 @@ public class TenantManagementService { } + private boolean tryToAccessRealm(String tenantId) { + + try { + return keycloak.getAdminClient().realms().findAll().stream().anyMatch(r -> r.getRealm().equals(tenantId)); + } catch (Exception e) { + return false; + } + } + + private void createRealm(String tenantId) { var redaction = new RealmRepresentation(); @@ -192,7 +222,6 @@ public class TenantManagementService { redactionClient.setImplicitFlowEnabled(true); redactionClient.setDirectAccessGrantsEnabled(true); - var swaggerClient = new ClientRepresentation(); swaggerClient.setEnabled(true); swaggerClient.setName("swagger-ui-client"); @@ -204,7 +233,6 @@ public class TenantManagementService { swaggerClient.setAuthorizationServicesEnabled(true); swaggerClient.setSecret("OsloImWinter!23"); - var redactionSystemClient = new ClientRepresentation(); redactionSystemClient.setEnabled(true); redactionSystemClient.setName(keyCloakSettings.getClientId()); diff --git a/persistence-service-v1/persistence-service-server-v1/src/main/java/com/iqser/red/service/peristence/v1/server/DevConfiguration.java b/persistence-service-v1/persistence-service-server-v1/src/main/java/com/iqser/red/service/peristence/v1/server/DevConfiguration.java index 1ca279079..13fee5f79 100644 --- a/persistence-service-v1/persistence-service-server-v1/src/main/java/com/iqser/red/service/peristence/v1/server/DevConfiguration.java +++ b/persistence-service-v1/persistence-service-server-v1/src/main/java/com/iqser/red/service/peristence/v1/server/DevConfiguration.java @@ -1,13 +1,23 @@ package com.iqser.red.service.peristence.v1.server; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; import java.sql.Connection; import java.sql.DriverManager; import java.util.Set; import java.util.UUID; +import java.util.stream.Stream; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; import javax.annotation.PostConstruct; import javax.sql.DataSource; +import org.junit.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; @@ -17,7 +27,11 @@ import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.StatementCallback; import org.springframework.jdbc.datasource.SingleConnectionDataSource; +import com.iqser.red.service.persistence.management.v1.processor.service.DossierTemplateImportService; import com.iqser.red.service.persistence.management.v1.processor.service.TenantManagementService; +import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.DossierTemplateRepository; +import com.iqser.red.service.persistence.management.v1.processor.utils.multitenancy.TenantContext; +import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.importexport.ImportDossierTemplateRequest; 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.S3StorageConnection; import com.iqser.red.service.persistence.service.v1.api.shared.model.multitenancy.SearchConnection; @@ -70,30 +84,81 @@ public class DevConfiguration { .password("redaction") .build()) .searchConnection(SearchConnection.builder() - .hosts(Set.of("elasticsearchHost")) + .hosts(Set.of("localhost")) .port(9200) - .scheme("https") + .scheme("http") .username("elastic") - .password("changeMe") .numberOfShards("1") .numberOfReplicas("5") .build()) .s3StorageConnection(S3StorageConnection.builder() - .key("key") - .secret("secret") - .signerType("signerType") - .bucketName("bucketName") - .region("eu") - .endpoint("endpoint") + .key("minioadmin") + .secret("minioadmin") + .bucketName("redaction") + .endpoint("http://localhost:9000") .build()) .build(); tenantManagementService.createTenant(tenantRequest); } + + TenantContext.setTenantId("redaction"); + if(dossierTemplateRepository.count() == 0) { + testDossierTemplateImport(); + } } + @Autowired + private DossierTemplateImportService dossierTemplateImportService; + + @Autowired + private DossierTemplateRepository dossierTemplateRepository; + + public byte[] pack(String sourceDirPath) throws IOException { + + var bos = new ByteArrayOutputStream(); + var p = Paths.get(sourceDirPath); + try (ZipOutputStream zs = new ZipOutputStream(bos)) { + Stream paths = Files.walk(p); + { + paths.filter(path -> !Files.isDirectory(path)).forEach(path -> { + ZipEntry zipEntry = new ZipEntry(p.relativize(path).toString()); + try { + zs.putNextEntry(zipEntry); + Files.copy(path, zs); + zs.closeEntry(); + } catch (IOException e) { + System.err.println(e); + } + }); + } + } + + return bos.toByteArray(); + + } + + @SneakyThrows + public void testDossierTemplateImport() { + + var importDir = new File("/Users/timobejan/work/dossier-templates-v2/dev"); + + TenantContext.setTenantId("redaction"); + for (var file : importDir.listFiles()) { + if(file.isDirectory()){ + var archive = pack(file.getAbsolutePath()); + log.info("Importing file: " + file.getName() + " " + " with size: " + archive.length); + var request = new ImportDossierTemplateRequest(); + request.setArchive(archive); + request.setUpdateExistingDossierTemplate(false); + request.setUserId("system"); + dossierTemplateImportService.importDossierTemplate(request); + } + } + } + @SneakyThrows public void createSchema(String jdbcUrl, String username, String password) { diff --git a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/DossierTemplateImportTest.java b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/DossierTemplateImportTest.java index bcbf49ff6..80532da41 100644 --- a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/DossierTemplateImportTest.java +++ b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/DossierTemplateImportTest.java @@ -32,10 +32,9 @@ public class DossierTemplateImportTest extends AbstractPersistenceServerServiceT @SneakyThrows @Test - @Disabled public void testDossierTemplateImport() { - var importDir = new File("/path/to/git/repo/dossier-templates-v2/dev"); + var importDir = new File("/Users/timobejan/work/dossier-templates-v2/dev"); TenantContext.setTenantId("redaction"); for (var file : importDir.listFiles()) { diff --git a/persistence-service-v1/persistence-service-server-v1/src/test/resources/application.yml b/persistence-service-v1/persistence-service-server-v1/src/test/resources/application.yml index fb6bb961a..37310a6aa 100644 --- a/persistence-service-v1/persistence-service-server-v1/src/test/resources/application.yml +++ b/persistence-service-v1/persistence-service-server-v1/src/test/resources/application.yml @@ -125,7 +125,7 @@ keycloak: commons: keycloak: - application-client-id: redaction-system + application-client-id: redaction realm: master client-id: redaction-system client-secret: redaction-system From 883ecf6461ebdf023e26091a605d853ed65f20d5 Mon Sep 17 00:00:00 2001 From: Timo Bejan Date: Thu, 23 Mar 2023 17:24:26 +0200 Subject: [PATCH 04/10] RED-4515 - kc createRealm --- .../swagger/SwaggerAutoConfiguration.java | 2 +- .../service/TenantManagementService.java | 23 +------------------ .../src/main/resources/application.yml | 2 +- .../AbstractPersistenceServerServiceTest.java | 12 ++++++++++ .../integration/utils/TokenService.java | 4 ++++ 5 files changed, 19 insertions(+), 24 deletions(-) diff --git a/persistence-service-v1/persistence-service-external-api-impl-v1/src/main/java/com/iqser/red/persistence/service/v1/external/api/impl/swagger/SwaggerAutoConfiguration.java b/persistence-service-v1/persistence-service-external-api-impl-v1/src/main/java/com/iqser/red/persistence/service/v1/external/api/impl/swagger/SwaggerAutoConfiguration.java index 0466f3847..55ebb2387 100644 --- a/persistence-service-v1/persistence-service-external-api-impl-v1/src/main/java/com/iqser/red/persistence/service/v1/external/api/impl/swagger/SwaggerAutoConfiguration.java +++ b/persistence-service-v1/persistence-service-external-api-impl-v1/src/main/java/com/iqser/red/persistence/service/v1/external/api/impl/swagger/SwaggerAutoConfiguration.java @@ -119,7 +119,7 @@ public class SwaggerAutoConfiguration { OAuthFlow flow = createAuthorizationCodeFlow(); - return new OAuthFlows().authorizationCode(flow); + return new OAuthFlows().implicit(flow); } diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/TenantManagementService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/TenantManagementService.java index 6e9b7d8ec..88fd99f70 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/TenantManagementService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/TenantManagementService.java @@ -222,29 +222,8 @@ public class TenantManagementService { redactionClient.setImplicitFlowEnabled(true); redactionClient.setDirectAccessGrantsEnabled(true); - var swaggerClient = new ClientRepresentation(); - swaggerClient.setEnabled(true); - swaggerClient.setName("swagger-ui-client"); - swaggerClient.setClientId("swagger-ui-client"); - swaggerClient.setStandardFlowEnabled(true); - swaggerClient.setImplicitFlowEnabled(false); - swaggerClient.setDirectAccessGrantsEnabled(false); - swaggerClient.setServiceAccountsEnabled(true); - swaggerClient.setAuthorizationServicesEnabled(true); - swaggerClient.setSecret("OsloImWinter!23"); - var redactionSystemClient = new ClientRepresentation(); - redactionSystemClient.setEnabled(true); - redactionSystemClient.setName(keyCloakSettings.getClientId()); - redactionSystemClient.setClientId(keyCloakSettings.getClientId()); - redactionSystemClient.setSecret(keyCloakSettings.getClientSecret()); - swaggerClient.setStandardFlowEnabled(true); - swaggerClient.setImplicitFlowEnabled(true); - swaggerClient.setDirectAccessGrantsEnabled(true); - swaggerClient.setServiceAccountsEnabled(true); - swaggerClient.setAuthorizationServicesEnabled(true); - - redaction.setClients(List.of(redactionClient, redactionSystemClient, swaggerClient)); + redaction.setClients(List.of(redactionClient)); var redUserRole = new RoleRepresentation(); redUserRole.setComposite(true); redUserRole.setName(RED_USER_ROLE); diff --git a/persistence-service-v1/persistence-service-server-v1/src/main/resources/application.yml b/persistence-service-v1/persistence-service-server-v1/src/main/resources/application.yml index 5a574783e..258ef16e5 100644 --- a/persistence-service-v1/persistence-service-server-v1/src/main/resources/application.yml +++ b/persistence-service-v1/persistence-service-server-v1/src/main/resources/application.yml @@ -154,7 +154,7 @@ springdoc: operations-sorter: alpha tags-sorter: alpha oauth: - client-id: swagger-ui-client + client-id: redaction doc-expansion: none enabled: ${swagger.enabled} config-url: /redaction-gateway-v1/docs/swagger-config diff --git a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/utils/AbstractPersistenceServerServiceTest.java b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/utils/AbstractPersistenceServerServiceTest.java index 177b08c4f..aa6fd1ec8 100644 --- a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/utils/AbstractPersistenceServerServiceTest.java +++ b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/utils/AbstractPersistenceServerServiceTest.java @@ -16,6 +16,7 @@ import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.extension.ExtendWith; import org.keycloak.adapters.springboot.KeycloakSpringBootProperties; +import org.keycloak.representations.idm.ClientRepresentation; import org.mockito.Mockito; import org.springframework.amqp.core.AmqpAdmin; import org.springframework.amqp.rabbit.core.RabbitTemplate; @@ -210,6 +211,8 @@ public abstract class AbstractPersistenceServerServiceTest { private UserService userService; @Autowired private TokenService tokenService; + @Autowired + private KeyCloakSettings keyCloakSettings; @BeforeEach @@ -237,6 +240,15 @@ public abstract class AbstractPersistenceServerServiceTest { if (allUsers.isEmpty()) { + + var redactionSystemClient = new ClientRepresentation(); + redactionSystemClient.setEnabled(true); + redactionSystemClient.setName(keyCloakSettings.getClientId()); + redactionSystemClient.setClientId(keyCloakSettings.getClientId()); + redactionSystemClient.setSecret(keyCloakSettings.getClientSecret()); + + KeyCloakTestContainer.getInstance().getKeycloakAdminClient().realm("redaction").clients().create(redactionSystemClient); + var admin1 = createUser("manageradmin1@test.com"); var admin2 = createUser("manageradmin2@test.com"); diff --git a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/utils/TokenService.java b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/utils/TokenService.java index cb873ee2d..21fc138d1 100644 --- a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/utils/TokenService.java +++ b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/utils/TokenService.java @@ -2,6 +2,7 @@ package com.iqser.red.service.peristence.v1.server.integration.utils; import java.util.concurrent.TimeUnit; +import javax.ws.rs.BadRequestException; import javax.ws.rs.NotAuthorizedException; import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder; @@ -48,6 +49,9 @@ public class TokenService { try { return tokenClient.tokenManager().getAccessTokenString(); + } catch (BadRequestException e) { + var response = e.getResponse().getEntity(); + System.out.println(response); } catch (NotAuthorizedException e) { throw new AuthenticationFailedException(e); } finally { From 336a34a55e309a9450669377f8c5f9e06d2cb951 Mon Sep 17 00:00:00 2001 From: Timo Bejan Date: Thu, 23 Mar 2023 17:29:13 +0200 Subject: [PATCH 05/10] RED-4515 - kc createRealm --- .../integration/utils/AbstractPersistenceServerServiceTest.java | 2 ++ .../peristence/v1/server/integration/utils/TokenService.java | 1 + 2 files changed, 3 insertions(+) diff --git a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/utils/AbstractPersistenceServerServiceTest.java b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/utils/AbstractPersistenceServerServiceTest.java index aa6fd1ec8..15562307d 100644 --- a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/utils/AbstractPersistenceServerServiceTest.java +++ b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/utils/AbstractPersistenceServerServiceTest.java @@ -246,6 +246,8 @@ public abstract class AbstractPersistenceServerServiceTest { redactionSystemClient.setName(keyCloakSettings.getClientId()); redactionSystemClient.setClientId(keyCloakSettings.getClientId()); redactionSystemClient.setSecret(keyCloakSettings.getClientSecret()); + redactionSystemClient.setDirectAccessGrantsEnabled(true); + redactionSystemClient.setServiceAccountsEnabled(true); KeyCloakTestContainer.getInstance().getKeycloakAdminClient().realm("redaction").clients().create(redactionSystemClient); diff --git a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/utils/TokenService.java b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/utils/TokenService.java index 21fc138d1..5596c1912 100644 --- a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/utils/TokenService.java +++ b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/utils/TokenService.java @@ -52,6 +52,7 @@ public class TokenService { } catch (BadRequestException e) { var response = e.getResponse().getEntity(); System.out.println(response); + return null; } catch (NotAuthorizedException e) { throw new AuthenticationFailedException(e); } finally { From 09291ea39d96807d9379b7276069fb9d3ff64b0b Mon Sep 17 00:00:00 2001 From: deiflaender Date: Fri, 24 Mar 2023 09:17:02 +0100 Subject: [PATCH 06/10] RED-4515: Fixed kc config --- .../com/iqser/red/keycloak/commons/UserListingService.java | 4 ---- .../src/main/resources/application.yml | 2 +- .../server/integration/tests/DossierTemplateImportTest.java | 2 +- 3 files changed, 2 insertions(+), 6 deletions(-) diff --git a/persistence-service-v1/keycloak-commons/src/main/java/com/iqser/red/keycloak/commons/UserListingService.java b/persistence-service-v1/keycloak-commons/src/main/java/com/iqser/red/keycloak/commons/UserListingService.java index ac234c242..379738085 100644 --- a/persistence-service-v1/keycloak-commons/src/main/java/com/iqser/red/keycloak/commons/UserListingService.java +++ b/persistence-service-v1/keycloak-commons/src/main/java/com/iqser/red/keycloak/commons/UserListingService.java @@ -36,10 +36,6 @@ public class UserListingService { @Cacheable(value = USERS_CACHE, key = "'tenantId'") public List getAllUsers(String tenantId) { - if(tenantId == "master"){ - return new ArrayList<>(); - } - return retryTemplate.execute(context -> { var realm = realmService.realm(tenantId); diff --git a/persistence-service-v1/persistence-service-server-v1/src/main/resources/application.yml b/persistence-service-v1/persistence-service-server-v1/src/main/resources/application.yml index 258ef16e5..21e41940f 100644 --- a/persistence-service-v1/persistence-service-server-v1/src/main/resources/application.yml +++ b/persistence-service-v1/persistence-service-server-v1/src/main/resources/application.yml @@ -139,7 +139,7 @@ keycloak: commons: keycloak: - applicationClientId: ${keycloak.resource:redaction-system} + applicationClientId: ${keycloak.resource:redaction} clientId: ${keycloak.client.id} clientSecret: ${keycloak.client.secret} realm: ${keycloak.realm} diff --git a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/DossierTemplateImportTest.java b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/DossierTemplateImportTest.java index 80532da41..89f7723fd 100644 --- a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/DossierTemplateImportTest.java +++ b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/DossierTemplateImportTest.java @@ -10,7 +10,6 @@ import java.util.stream.Stream; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; -import org.junit.Ignore; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -32,6 +31,7 @@ public class DossierTemplateImportTest extends AbstractPersistenceServerServiceT @SneakyThrows @Test + @Disabled public void testDossierTemplateImport() { var importDir = new File("/Users/timobejan/work/dossier-templates-v2/dev"); From 1a41edbef9ce7f16709115994e30949c800160b7 Mon Sep 17 00:00:00 2001 From: deiflaender Date: Fri, 24 Mar 2023 10:34:14 +0100 Subject: [PATCH 07/10] RED-4515: Changed swagger back to authorizationCode flow --- .../api/impl/swagger/SwaggerAutoConfiguration.java | 4 +--- .../processor/service/TenantManagementService.java | 13 ++++++++++++- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/persistence-service-v1/persistence-service-external-api-impl-v1/src/main/java/com/iqser/red/persistence/service/v1/external/api/impl/swagger/SwaggerAutoConfiguration.java b/persistence-service-v1/persistence-service-external-api-impl-v1/src/main/java/com/iqser/red/persistence/service/v1/external/api/impl/swagger/SwaggerAutoConfiguration.java index 55ebb2387..6cd3db109 100644 --- a/persistence-service-v1/persistence-service-external-api-impl-v1/src/main/java/com/iqser/red/persistence/service/v1/external/api/impl/swagger/SwaggerAutoConfiguration.java +++ b/persistence-service-v1/persistence-service-external-api-impl-v1/src/main/java/com/iqser/red/persistence/service/v1/external/api/impl/swagger/SwaggerAutoConfiguration.java @@ -5,8 +5,6 @@ import java.util.Arrays; import java.util.Collection; import java.util.List; -import org.keycloak.adapters.springboot.KeycloakSpringBootProperties; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.actuate.autoconfigure.endpoint.web.CorsEndpointProperties; import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointProperties; import org.springframework.boot.actuate.autoconfigure.web.server.ManagementPortType; @@ -119,7 +117,7 @@ public class SwaggerAutoConfiguration { OAuthFlow flow = createAuthorizationCodeFlow(); - return new OAuthFlows().implicit(flow); + return new OAuthFlows().authorizationCode(flow); } diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/TenantManagementService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/TenantManagementService.java index 88fd99f70..31fbd7a98 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/TenantManagementService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/TenantManagementService.java @@ -222,8 +222,19 @@ public class TenantManagementService { redactionClient.setImplicitFlowEnabled(true); redactionClient.setDirectAccessGrantsEnabled(true); + var swaggerClient = new ClientRepresentation(); + swaggerClient.setEnabled(true); + swaggerClient.setName("swagger-ui-client"); + swaggerClient.setClientId("swagger-ui-client"); + swaggerClient.setStandardFlowEnabled(true); + swaggerClient.setImplicitFlowEnabled(false); + swaggerClient.setDirectAccessGrantsEnabled(false); + swaggerClient.setServiceAccountsEnabled(true); + swaggerClient.setAuthorizationServicesEnabled(true); + swaggerClient.setSecret("OsloImWinter!23"); - redaction.setClients(List.of(redactionClient)); + + redaction.setClients(List.of(redactionClient, swaggerClient)); var redUserRole = new RoleRepresentation(); redUserRole.setComposite(true); redUserRole.setName(RED_USER_ROLE); From ac5955ca6b803b5c8923009c1c361589c46a96a1 Mon Sep 17 00:00:00 2001 From: deiflaender Date: Fri, 24 Mar 2023 11:29:00 +0100 Subject: [PATCH 08/10] RED-4515: Create default user set valid redirect uis --- .../service/TenantManagementService.java | 33 +++++++++++-------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/TenantManagementService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/TenantManagementService.java index 31fbd7a98..6693f193f 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/TenantManagementService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/TenantManagementService.java @@ -9,6 +9,7 @@ import java.net.URI; import java.net.URISyntaxException; import java.sql.Connection; import java.sql.DriverManager; +import java.util.HashMap; import java.util.List; import java.util.Set; import java.util.UUID; @@ -21,6 +22,7 @@ import org.keycloak.representations.idm.CredentialRepresentation; import org.keycloak.representations.idm.RealmRepresentation; import org.keycloak.representations.idm.RoleRepresentation; import org.keycloak.representations.idm.RolesRepresentation; +import org.keycloak.representations.idm.UserRepresentation; import org.postgresql.util.PSQLException; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.autoconfigure.liquibase.LiquibaseProperties; @@ -213,6 +215,9 @@ public class TenantManagementService { redaction.setId(tenantId); redaction.setRealm(tenantId); redaction.setEnabled(true); + redaction.setLoginTheme("redaction"); + redaction.setEmailTheme("redaction"); + redaction.setAccountTheme("redaction"); var redactionClient = new ClientRepresentation(); redactionClient.setEnabled(true); @@ -221,6 +226,8 @@ public class TenantManagementService { redactionClient.setStandardFlowEnabled(true); redactionClient.setImplicitFlowEnabled(true); redactionClient.setDirectAccessGrantsEnabled(true); + redactionClient.setRedirectUris(List.of("/ui/*")); + redactionClient.setPublicClient(true); var swaggerClient = new ClientRepresentation(); swaggerClient.setEnabled(true); @@ -232,7 +239,7 @@ public class TenantManagementService { swaggerClient.setServiceAccountsEnabled(true); swaggerClient.setAuthorizationServicesEnabled(true); swaggerClient.setSecret("OsloImWinter!23"); - + swaggerClient.setRedirectUris(List.of("/redaction-gateway-v1/*")); redaction.setClients(List.of(redactionClient, swaggerClient)); var redUserRole = new RoleRepresentation(); @@ -263,18 +270,18 @@ public class TenantManagementService { credentialRepresentation.setType("password"); credentialRepresentation.setValue("OsloImWinter!23"); -// var defaultUser = new UserRepresentation(); -// defaultUser.setUsername("manageradmin"); -// defaultUser.setCredentials(List.of(credentialRepresentation)); -// defaultUser.setEmailVerified(true); -// defaultUser.setRealmRoles(List.of(RED_USER_ROLE, RED_MANAGER_ROLE, RED_ADMIN_ROLE, RED_USER_ADMIN_ROLE, "uma_authorization", "offline_access")); -// -// var clientRoles = new HashMap>(); -// clientRoles.put("account", List.of("manage-account", "view-profile")); -// -// defaultUser.setClientRoles(clientRoles); -// defaultUser.setEnabled(true); -// redaction.setUsers(List.of(defaultUser)); + var defaultUser = new UserRepresentation(); + defaultUser.setUsername("manageradmin"); + defaultUser.setCredentials(List.of(credentialRepresentation)); + defaultUser.setEmailVerified(true); + defaultUser.setRealmRoles(List.of(RED_USER_ROLE, RED_MANAGER_ROLE, RED_ADMIN_ROLE, RED_USER_ADMIN_ROLE, "uma_authorization", "offline_access")); + + var clientRoles = new HashMap>(); + clientRoles.put("account", List.of("manage-account", "view-profile")); + + defaultUser.setClientRoles(clientRoles); + defaultUser.setEnabled(true); + redaction.setUsers(List.of(defaultUser)); keycloak.getAdminClient().realms().create(redaction); } From 94aa4287ba3df1f2aa64f595fa3cb76a0a96c44c Mon Sep 17 00:00:00 2001 From: deiflaender Date: Fri, 24 Mar 2023 13:18:56 +0100 Subject: [PATCH 09/10] RED-4515: Rename master realm client to redaction as this make configuration much easier --- .../service/TenantManagementService.java | 1 - .../src/main/resources/application-dev.yml | 2 +- .../src/main/resources/application.yml | 2 +- .../AbstractPersistenceServerServiceTest.java | 3 +- .../utils/KeyCloakTestContainer.java | 74 ++----------------- .../src/test/resources/application.yml | 4 +- 6 files changed, 13 insertions(+), 73 deletions(-) diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/TenantManagementService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/TenantManagementService.java index 6693f193f..aae64b511 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/TenantManagementService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/TenantManagementService.java @@ -238,7 +238,6 @@ public class TenantManagementService { swaggerClient.setDirectAccessGrantsEnabled(false); swaggerClient.setServiceAccountsEnabled(true); swaggerClient.setAuthorizationServicesEnabled(true); - swaggerClient.setSecret("OsloImWinter!23"); swaggerClient.setRedirectUris(List.of("/redaction-gateway-v1/*")); redaction.setClients(List.of(redactionClient, swaggerClient)); diff --git a/persistence-service-v1/persistence-service-server-v1/src/main/resources/application-dev.yml b/persistence-service-v1/persistence-service-server-v1/src/main/resources/application-dev.yml index 9ecfa872f..6132a6dda 100644 --- a/persistence-service-v1/persistence-service-server-v1/src/main/resources/application-dev.yml +++ b/persistence-service-v1/persistence-service-server-v1/src/main/resources/application-dev.yml @@ -60,7 +60,7 @@ keycloak: commons: keycloak: applicationClientId: redaction - clientId: redaction-system + clientId: redaction clientSecret: G5E1qLU8ZNdDv7HY5BNLPdt5nXdeF7cU realm: redaction serverUrl: http://localhost:8080 diff --git a/persistence-service-v1/persistence-service-server-v1/src/main/resources/application.yml b/persistence-service-v1/persistence-service-server-v1/src/main/resources/application.yml index 21e41940f..b92394b2a 100644 --- a/persistence-service-v1/persistence-service-server-v1/src/main/resources/application.yml +++ b/persistence-service-v1/persistence-service-server-v1/src/main/resources/application.yml @@ -132,7 +132,7 @@ keycloak: sslRequired: none auth-server-url: https://red-staging.iqser.cloud/auth realm: master - resource: redaction-system + resource: redaction disableTrustManager: true useResourceRoleMappings: true enabled: true diff --git a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/utils/AbstractPersistenceServerServiceTest.java b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/utils/AbstractPersistenceServerServiceTest.java index 15562307d..0b8e84f8e 100644 --- a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/utils/AbstractPersistenceServerServiceTest.java +++ b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/utils/AbstractPersistenceServerServiceTest.java @@ -238,8 +238,7 @@ public abstract class AbstractPersistenceServerServiceTest { userService.evictUserCache(); var allUsers = userService.getAllUsers(); - if (allUsers.isEmpty()) { - + if (allUsers.size() == 1) { var redactionSystemClient = new ClientRepresentation(); redactionSystemClient.setEnabled(true); diff --git a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/utils/KeyCloakTestContainer.java b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/utils/KeyCloakTestContainer.java index 028d37f12..844214775 100644 --- a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/utils/KeyCloakTestContainer.java +++ b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/utils/KeyCloakTestContainer.java @@ -3,7 +3,6 @@ package com.iqser.red.service.peristence.v1.server.integration.utils; import java.util.ArrayList; import java.util.List; -import org.keycloak.admin.client.resource.ClientResource; import org.keycloak.admin.client.resource.RealmResource; import org.keycloak.admin.client.resource.UserResource; import org.keycloak.representations.idm.ClientRepresentation; @@ -33,89 +32,32 @@ public class KeyCloakTestContainer { var redaction = adminClient.realm("master"); var redactionClient = new ClientRepresentation(); + + redactionClient.setId("redaction"); redactionClient.setEnabled(true); redactionClient.setName("redaction"); + redactionClient.setSecret("redaction"); + redactionClient.setServiceAccountsEnabled(true); + redactionClient.setDirectAccessGrantsEnabled(true); redactionClient.setStandardFlowEnabled(true); redactionClient.setImplicitFlowEnabled(true); redactionClient.setDirectAccessGrantsEnabled(true); - - var redactionSystemClient = new ClientRepresentation(); -// -// RoleRepresentation createRealm = new RoleRepresentation(); -// createRealm.setName("create-realm"); -// -// RoleRepresentation viewRealm = new RoleRepresentation(); -// viewRealm.setName("view-realm"); -// -// RoleRepresentation manageRealm = new RoleRepresentation(); -// manageRealm.setName("manage-realm"); -// -// RoleRepresentation manageUsers = new RoleRepresentation(); -// manageUsers.setName("manage-users"); -// -// RoleRepresentation manageClients = new RoleRepresentation(); -// manageClients.setName("manage-clients"); - -// RolesRepresentation rolesRepresentation = new RolesRepresentation(); -// rolesRepresentation.setRealm(List.of(createRealm)); -// redaction.setRoles(rolesRepresentation); - - redactionSystemClient.setId("redaction-system"); - redactionSystemClient.setEnabled(true); - redactionSystemClient.setName("redaction-system"); - redactionSystemClient.setSecret("redaction-system"); - redactionSystemClient.setServiceAccountsEnabled(true); - redactionSystemClient.setDirectAccessGrantsEnabled(true); - redactionSystemClient.setStandardFlowEnabled(true); - redactionSystemClient.setImplicitFlowEnabled(true); - redactionSystemClient.setDirectAccessGrantsEnabled(true); redaction.clients().create(redactionClient); - redaction.clients().create(redactionSystemClient); + redaction.clients().create(redactionClient); RealmResource myRealm = adminClient.realm("master"); - String userId = myRealm.clients().get("redaction-system").getServiceAccountUser().getId(); + String userId = myRealm.clients().get("redaction").getServiceAccountUser().getId(); UserResource serviceAccountUser = myRealm.users().get(userId); -// ClientRepresentation clientThatOwnsRole = myRealm.clients() -// .findByClientId("realm-management").get(0); - - ClientRepresentation clientThatOwnsRole = myRealm.clients() - .findByClientId("master-realm").get(0); + ClientRepresentation clientThatOwnsRole = myRealm.clients().findByClientId("master-realm").get(0); String clientIdOfRoleOwner = clientThatOwnsRole.getId(); - ClientResource clientResourceOfRoleOwner = myRealm.clients().get(clientIdOfRoleOwner); -// myRealm.clients().get(clientIdOfRoleOwner).roles().list(); -// List rolesToAssign = new ArrayList<>(); -// -// rolesToAssign.add(clientResourceOfRoleOwner.roles().get("view-users").toRepresentation()); -// rolesToAssign.add(clientResourceOfRoleOwner.roles().get("manage-realm").toRepresentation()); -// rolesToAssign.add(clientResourceOfRoleOwner.roles().get("create-realm").toRepresentation()); -// -// myRealm.clients().get(clientIdOfRoleOwner).roles().list().forEach(role -> { -// serviceAccountUser.roles().clientLevel(clientIdOfRoleOwner).add(role); -// }); List roles = new ArrayList<>(); roles.addAll(myRealm.clients().get(clientIdOfRoleOwner).roles().list()); -// roles.add(myRealm.roles().get("create-realm").toRepresentation()); serviceAccountUser.roles().clientLevel(clientIdOfRoleOwner).add(roles); serviceAccountUser.roles().realmLevel().add(List.of(myRealm.roles().get("create-realm").toRepresentation())); -// System.out.println(KeycloakBuilder.builder() -// .serverUrl(keycloak.getAuthServerUrl()) -// .realm("management") -// .clientId("redaction-system") -// .clientSecret("redaction-system") -// .grantType(OAuth2Constants.CLIENT_CREDENTIALS) -// .resteasyClient(new ResteasyClientBuilderImpl().connectionTTL(2, TimeUnit.SECONDS) -// .hostnameVerification(ResteasyClientBuilder.HostnameVerificationPolicy.ANY) -// .connectionPoolSize(10) -// .disableTrustManager() -// .build()) -// .build() -// .realm("management") -// .toRepresentation()); - } return keycloak; diff --git a/persistence-service-v1/persistence-service-server-v1/src/test/resources/application.yml b/persistence-service-v1/persistence-service-server-v1/src/test/resources/application.yml index 37310a6aa..564764660 100644 --- a/persistence-service-v1/persistence-service-server-v1/src/test/resources/application.yml +++ b/persistence-service-v1/persistence-service-server-v1/src/test/resources/application.yml @@ -127,6 +127,6 @@ commons: keycloak: application-client-id: redaction realm: master - client-id: redaction-system - client-secret: redaction-system + client-id: redaction + client-secret: redaction From 8a0591d4b967b3c7880a4e04584d259b7499af7d Mon Sep 17 00:00:00 2001 From: deiflaender Date: Fri, 24 Mar 2023 15:26:09 +0100 Subject: [PATCH 10/10] RED-4515: Create schema on createTenant --- .../service/TenantManagementService.java | 23 ++++++++++++++++++- .../v1/processor/utils/jdbc/JDBCUtils.java | 17 ++++++++++++++ .../AbstractPersistenceServerServiceTest.java | 21 +++-------------- 3 files changed, 42 insertions(+), 19 deletions(-) diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/TenantManagementService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/TenantManagementService.java index aae64b511..93ff7c5be 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/TenantManagementService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/TenantManagementService.java @@ -28,6 +28,8 @@ import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.autoconfigure.liquibase.LiquibaseProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.core.io.ResourceLoader; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.core.StatementCallback; import org.springframework.jdbc.datasource.SingleConnectionDataSource; import org.springframework.stereotype.Service; @@ -113,7 +115,9 @@ public class TenantManagementService { if (tenantRepository.findById(tenantRequest.getTenantId()).isEmpty()) { - var jdbcUrl = JDBCUtils.buildJdbcUrl(tenantRequest.getDatabaseConnection()); + createSchema(tenantRequest); + + var jdbcUrl = JDBCUtils.buildJdbcUrlWithSchema(tenantRequest.getDatabaseConnection()); validateJdbcUrl(jdbcUrl); try (Connection connection = DriverManager.getConnection(jdbcUrl, @@ -199,6 +203,23 @@ public class TenantManagementService { } + + private void createSchema(TenantRequest tenantRequest){ + + var jdbcUrl = JDBCUtils.buildJdbcUrl(tenantRequest.getDatabaseConnection()); + try (Connection connection = DriverManager.getConnection(jdbcUrl, + tenantRequest.getDatabaseConnection().getUsername(), + tenantRequest.getDatabaseConnection().getPassword())) { + DataSource tenantDataSource = new SingleConnectionDataSource(connection, false); + JdbcTemplate jdbcTemplate = new JdbcTemplate(tenantDataSource); + jdbcTemplate.execute((StatementCallback) stmt -> stmt.execute("CREATE SCHEMA " + tenantRequest.getDatabaseConnection().getSchema())); + jdbcTemplate.execute((StatementCallback) stmt -> stmt.execute("GRANT USAGE ON SCHEMA " + tenantRequest.getDatabaseConnection().getSchema() + " TO " + tenantRequest.getDatabaseConnection().getUsername())); + } catch (Exception e) { + log.info("Could not create schema, ignoring"); + } + } + + private boolean tryToAccessRealm(String tenantId) { try { diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/utils/jdbc/JDBCUtils.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/utils/jdbc/JDBCUtils.java index 9d5ed8b16..28e969139 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/utils/jdbc/JDBCUtils.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/utils/jdbc/JDBCUtils.java @@ -28,6 +28,23 @@ public class JDBCUtils { public String buildJdbcUrl(DatabaseConnection databaseConnection){ + StringBuilder sb = new StringBuilder("jdbc:") + .append(databaseConnection.getDriver()) + .append("://") + .append(databaseConnection.getHost()) + .append(':') + .append(databaseConnection.getPort()) + .append('/') + .append(databaseConnection.getDatabase()); + if(databaseConnection.getParams() != null) { + sb.append('?'); + databaseConnection.getParams().forEach((k, v) -> sb.append('&').append(k).append(v)); + } + return sb.toString(); + } + + + public String buildJdbcUrlWithSchema(DatabaseConnection databaseConnection){ StringBuilder sb = new StringBuilder("jdbc:") .append(databaseConnection.getDriver()) .append("://") diff --git a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/utils/AbstractPersistenceServerServiceTest.java b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/utils/AbstractPersistenceServerServiceTest.java index 0b8e84f8e..41afa7040 100644 --- a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/utils/AbstractPersistenceServerServiceTest.java +++ b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/utils/AbstractPersistenceServerServiceTest.java @@ -2,8 +2,6 @@ package com.iqser.red.service.peristence.v1.server.integration.utils; import static org.mockito.Mockito.when; -import java.sql.Connection; -import java.sql.DriverManager; import java.util.ArrayList; import java.util.Set; import java.util.UUID; @@ -37,7 +35,6 @@ import org.springframework.context.annotation.Import; import org.springframework.context.annotation.Primary; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.StatementCallback; -import org.springframework.jdbc.datasource.SingleConnectionDataSource; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit.jupiter.SpringExtension; @@ -103,7 +100,6 @@ import com.iqser.red.storage.commons.StorageAutoConfiguration; import com.iqser.red.storage.commons.service.StorageService; import io.micrometer.prometheus.PrometheusMeterRegistry; -import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; @Slf4j @@ -312,7 +308,6 @@ public abstract class AbstractPersistenceServerServiceTest { var port = postgreSQLContainerMaster.getJdbcUrl().substring(0, postgreSQLContainerMaster.getJdbcUrl().lastIndexOf('/')).split(":")[3]; createDatabase("redaction", "redaction"); - createSchema(jdbcUrl, "redaction", "redaction"); var tenantRequest = TenantRequest.builder() .tenantId("redaction") @@ -360,18 +355,6 @@ public abstract class AbstractPersistenceServerServiceTest { } - @SneakyThrows - public void createSchema(String jdbcUrl, String username, String password) { - - try (Connection connection = DriverManager.getConnection(jdbcUrl, username, password)) { - DataSource tenantDataSource = new SingleConnectionDataSource(connection, false); - JdbcTemplate insert = new JdbcTemplate(tenantDataSource); - insert.execute((StatementCallback) stmt -> stmt.execute("CREATE SCHEMA myschema")); - insert.execute((StatementCallback) stmt -> stmt.execute("GRANT USAGE ON SCHEMA myschema TO " + username)); - } - } - - @AfterEach public void cleanupStorage() { @@ -448,7 +431,9 @@ public abstract class AbstractPersistenceServerServiceTest { TestPropertyValues.of("spring.redis.port=" + redisContainer.getFirstMappedPort(), "multitenancy.master.datasource.url=" + postgreSQLContainerMaster.getJdbcUrl() + connectionStringDetails, "multitenancy.master.datasource.username=" + postgreSQLContainerMaster.getUsername(), - "multitenancy.master.datasource.password=" + postgreSQLContainerMaster.getPassword(), "keycloak.auth-server-url=" + kcInstance.getAuthServerUrl(), "commons.keycloak.serverUrl=" + kcInstance.getAuthServerUrl()).applyTo(configurableApplicationContext.getEnvironment()); + "multitenancy.master.datasource.password=" + postgreSQLContainerMaster.getPassword(), + "keycloak.auth-server-url=" + kcInstance.getAuthServerUrl(), + "commons.keycloak.serverUrl=" + kcInstance.getAuthServerUrl()).applyTo(configurableApplicationContext.getEnvironment()); }