diff --git a/persistence-service-v1/keycloak-commons/src/main/java/com/iqser/red/keycloak/commons/DefaultKeyCloakCommonsConfiguration.java b/persistence-service-v1/keycloak-commons/src/main/java/com/iqser/red/keycloak/commons/DefaultKeyCloakCommonsConfiguration.java index a5bb84b47..bbfe5102e 100644 --- a/persistence-service-v1/keycloak-commons/src/main/java/com/iqser/red/keycloak/commons/DefaultKeyCloakCommonsConfiguration.java +++ b/persistence-service-v1/keycloak-commons/src/main/java/com/iqser/red/keycloak/commons/DefaultKeyCloakCommonsConfiguration.java @@ -1,6 +1,5 @@ package com.iqser.red.keycloak.commons; -import static com.iqser.red.keycloak.commons.UserCacheBuilder.USERS_CACHE; import java.time.Duration; @@ -14,6 +13,7 @@ import org.springframework.data.redis.cache.RedisCacheConfiguration; @ComponentScan public class DefaultKeyCloakCommonsConfiguration { + public static final String USERS_CACHE = "users"; @Bean public RedisCacheManagerBuilderCustomizer redisUserCacheManagerBuilderCustomizer() { diff --git a/persistence-service-v1/keycloak-commons/src/main/java/com/iqser/red/keycloak/commons/RealmService.java b/persistence-service-v1/keycloak-commons/src/main/java/com/iqser/red/keycloak/commons/RealmService.java index af2cbd525..b00d46c63 100644 --- a/persistence-service-v1/keycloak-commons/src/main/java/com/iqser/red/keycloak/commons/RealmService.java +++ b/persistence-service-v1/keycloak-commons/src/main/java/com/iqser/red/keycloak/commons/RealmService.java @@ -13,12 +13,9 @@ public class RealmService { private final KeyCloakAdminClientService keycloak; - private final KeyCloakSettings settings; + public RealmResource realm(String tenantId) { - - public RealmResource realm() { - - return keycloak.getAdminClient().realm(settings.getRealm()); + return keycloak.getAdminClient().realm(tenantId); } } 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 1a2fc87d0..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 @@ -1,6 +1,6 @@ package com.iqser.red.keycloak.commons; -import static com.iqser.red.keycloak.commons.UserCacheBuilder.USERS_CACHE; +import static com.iqser.red.keycloak.commons.DefaultKeyCloakCommonsConfiguration.USERS_CACHE; 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; @@ -33,18 +33,20 @@ public class UserListingService { private final RetryTemplate retryTemplate = RetryTemplate.builder().maxAttempts(3).exponentialBackoff(1000, 2, 5000).build(); - @Cacheable(value = USERS_CACHE) - public List getAllUsers() { + @Cacheable(value = USERS_CACHE, key = "'tenantId'") + public List getAllUsers(String tenantId) { return retryTemplate.execute(context -> { - List allUsers = realmService.realm().users().search(null, 0, 500); + + var realm = realmService.realm(tenantId); + List allUsers = realm.users().search(null, 0, 500); Map> usersByRole = new HashMap<>(); if(!allUsers.isEmpty()) { - var realmRoles = realmService.realm().roles().list().stream().map(r -> r.getName().toUpperCase()).collect(Collectors.toSet()); + var realmRoles = realm.roles().list().stream().map(r -> r.getName().toUpperCase()).collect(Collectors.toSet()); for (var role : ApplicationRoles.ROLE_DATA.keySet()) { if(realmRoles.contains(role)) { - Set users = realmService.realm().roles().get(role).getRoleUserMembers(0, 500); + Set users = realm.roles().get(role).getRoleUserMembers(0, 500); usersByRole.put(role, users.stream().map(UserRepresentation::getId).collect(Collectors.toSet())); } } diff --git a/persistence-service-v1/keycloak-commons/src/main/java/com/iqser/red/keycloak/commons/security/SecuredKeyCloakConfiguration.java b/persistence-service-v1/keycloak-commons/src/main/java/com/iqser/red/keycloak/commons/security/SecuredKeyCloakConfiguration.java index 077b32df9..45b91d7b6 100644 --- a/persistence-service-v1/keycloak-commons/src/main/java/com/iqser/red/keycloak/commons/security/SecuredKeyCloakConfiguration.java +++ b/persistence-service-v1/keycloak-commons/src/main/java/com/iqser/red/keycloak/commons/security/SecuredKeyCloakConfiguration.java @@ -1,9 +1,5 @@ package com.iqser.red.keycloak.commons.security; -import static com.iqser.red.keycloak.commons.UserCacheBuilder.USERS_CACHE; - -import java.time.Duration; - import javax.servlet.http.HttpServletRequest; import org.keycloak.adapters.AdapterTokenStore; @@ -21,14 +17,11 @@ import org.keycloak.adapters.springsecurity.authentication.SpringSecurityRequest import org.keycloak.adapters.springsecurity.config.KeycloakWebSecurityConfigurerAdapter; import org.keycloak.adapters.springsecurity.filter.KeycloakAuthenticationProcessingFilter; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.cache.RedisCacheManagerBuilderCustomizer; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Import; import org.springframework.context.annotation.Primary; -import org.springframework.data.redis.cache.RedisCacheConfiguration; import org.springframework.http.HttpMethod; import org.springframework.http.HttpStatus; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; diff --git a/persistence-service-v1/persistence-service-external-api-impl-v1/src/main/java/com/iqser/red/persistence/service/v1/external/api/impl/controller/GeneralSettingsController.java b/persistence-service-v1/persistence-service-external-api-impl-v1/src/main/java/com/iqser/red/persistence/service/v1/external/api/impl/controller/GeneralSettingsController.java index 35d1d79db..3005f1920 100644 --- a/persistence-service-v1/persistence-service-external-api-impl-v1/src/main/java/com/iqser/red/persistence/service/v1/external/api/impl/controller/GeneralSettingsController.java +++ b/persistence-service-v1/persistence-service-external-api-impl-v1/src/main/java/com/iqser/red/persistence/service/v1/external/api/impl/controller/GeneralSettingsController.java @@ -7,10 +7,10 @@ import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; +import com.iqser.red.service.persistence.management.v1.processor.service.GeneralConfigurationService; import com.iqser.red.service.persistence.service.v1.api.external.resource.GeneralSettingsResource; import com.iqser.red.service.persistence.service.v1.api.shared.model.GeneralConfigurationModel; -import com.iqser.red.persistence.service.v1.external.api.impl.service.GeneralConfigurationService; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; diff --git a/persistence-service-v1/persistence-service-external-api-impl-v1/src/main/java/com/iqser/red/persistence/service/v1/external/api/impl/controller/SMTPConfigurationController.java b/persistence-service-v1/persistence-service-external-api-impl-v1/src/main/java/com/iqser/red/persistence/service/v1/external/api/impl/controller/SMTPConfigurationController.java index f2633bcf0..a86de7098 100644 --- a/persistence-service-v1/persistence-service-external-api-impl-v1/src/main/java/com/iqser/red/persistence/service/v1/external/api/impl/controller/SMTPConfigurationController.java +++ b/persistence-service-v1/persistence-service-external-api-impl-v1/src/main/java/com/iqser/red/persistence/service/v1/external/api/impl/controller/SMTPConfigurationController.java @@ -14,6 +14,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.iqser.red.keycloak.commons.KeycloakSecurity; import com.iqser.red.keycloak.commons.RealmService; import com.iqser.red.service.persistence.management.v1.processor.service.persistence.SMTPConfigurationService; +import com.iqser.red.service.persistence.management.v1.processor.utils.multitenancy.TenantContext; import com.iqser.red.service.persistence.service.v1.api.external.resource.SMTPConfigurationResource; import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.configuration.SMTPConfiguration; @@ -49,10 +50,10 @@ public class SMTPConfigurationController implements SMTPConfigurationResource { smtpConfigurationService.updateSMTPConfiguration(smtpConfigurationModel); // also update in KC - var realmRepresentation = realmService.realm().toRepresentation(); + var realmRepresentation = realmService.realm(TenantContext.getTenantId()).toRepresentation(); var propertiesMap = convertSMTPConfigurationModelToMap(smtpConfigurationModel); realmRepresentation.setSmtpServer(propertiesMap); - realmService.realm().update(realmRepresentation); + realmService.realm(TenantContext.getTenantId()).update(realmRepresentation); } @@ -77,7 +78,7 @@ public class SMTPConfigurationController implements SMTPConfigurationResource { @PreAuthorize("hasAuthority('" + WRITE_SMTP_CONFIGURATION + "')") public void testSMTPConfiguration(@RequestBody SMTPConfiguration smtpConfigurationModel) { - var currentUserEmail = realmService.realm().users().get(KeycloakSecurity.getUserId()).toRepresentation().getEmail(); + var currentUserEmail = realmService.realm(TenantContext.getTenantId()).users().get(KeycloakSecurity.getUserId()).toRepresentation().getEmail(); smtpConfigurationService.testSMTPConfiguration(currentUserEmail, smtpConfigurationModel); } @@ -90,9 +91,9 @@ public class SMTPConfigurationController implements SMTPConfigurationResource { smtpConfigurationService.deleteConfiguration(); // also update in KC - var realmRepresentation = realmService.realm().toRepresentation(); + var realmRepresentation = realmService.realm(TenantContext.getTenantId()).toRepresentation(); realmRepresentation.setSmtpServer(new HashMap<>()); - realmService.realm().update(realmRepresentation); + realmService.realm(TenantContext.getTenantId()).update(realmRepresentation); } diff --git a/persistence-service-v1/persistence-service-external-api-impl-v1/src/main/java/com/iqser/red/persistence/service/v1/external/api/impl/initializer/RealmInitializer.java b/persistence-service-v1/persistence-service-external-api-impl-v1/src/main/java/com/iqser/red/persistence/service/v1/external/api/impl/initializer/RealmInitializer.java deleted file mode 100644 index 4c574dc44..000000000 --- a/persistence-service-v1/persistence-service-external-api-impl-v1/src/main/java/com/iqser/red/persistence/service/v1/external/api/impl/initializer/RealmInitializer.java +++ /dev/null @@ -1,30 +0,0 @@ -package com.iqser.red.persistence.service.v1.external.api.impl.initializer; - -import org.springframework.boot.ApplicationArguments; -import org.springframework.boot.ApplicationRunner; -import org.springframework.stereotype.Service; - -import com.iqser.red.persistence.service.v1.external.api.impl.service.GeneralConfigurationService; -import com.iqser.red.service.persistence.management.v1.processor.settings.FileManagementServiceSettings; - -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; - -@Slf4j -@Service -@RequiredArgsConstructor -public class RealmInitializer implements ApplicationRunner { - - private final GeneralConfigurationService generalConfigurationService; - private final FileManagementServiceSettings fileManagementServiceSettings; - - - @Override - public void run(ApplicationArguments args) throws Exception { - - var generalConfiguration = generalConfigurationService.getGeneralConfigurations(); - log.info("Currently Configured Application Name: {}, default name: {}", generalConfiguration.getDisplayName(), fileManagementServiceSettings.getApplicationName()); - generalConfigurationService.updateGeneralConfigurations(generalConfigurationService.getGeneralConfigurations()); - } - -} diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/acl/custom/api/ICustomPermissionService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/acl/custom/api/ICustomPermissionService.java index 1ccd4e00b..1a7c31e9a 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/acl/custom/api/ICustomPermissionService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/acl/custom/api/ICustomPermissionService.java @@ -18,6 +18,7 @@ import com.iqser.red.keycloak.commons.UserListingService; import com.iqser.red.keycloak.commons.model.User; import com.iqser.red.service.persistence.management.v1.processor.acl.AbstractACLService; import com.iqser.red.service.persistence.management.v1.processor.acl.RedPermission; +import com.iqser.red.service.persistence.management.v1.processor.utils.multitenancy.TenantContext; import com.iqser.red.service.persistence.service.v1.api.shared.model.permission.CustomPermissionMappingModel; import com.iqser.red.service.persistence.service.v1.api.shared.model.permission.CustomPermissionModel; @@ -108,7 +109,7 @@ public abstract class ICustomPermissionService exten private Set getUserIds() { - return userListingService.getAllUsers().stream().map(User::getUserId).collect(Collectors.toSet()); + return userListingService.getAllUsers(TenantContext.getTenantId()).stream().map(User::getUserId).collect(Collectors.toSet()); } diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/job/KeyCloakUserSyncService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/job/KeyCloakUserSyncService.java index 01407a638..c47a6ecbd 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/job/KeyCloakUserSyncService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/job/KeyCloakUserSyncService.java @@ -30,12 +30,12 @@ public class KeyCloakUserSyncService { public void syncUsersWithKC() { - var allUsers = userListingService.getAllUsers(); - // all userIds from KC - var allUserIds = allUsers.stream().map(User::getUserId).collect(Collectors.toSet()); - tenantManagementService.getTenants().forEach(tenant -> { + var allUsers = userListingService.getAllUsers(tenant.getTenantId()); + // all userIds from KC + var allUserIds = allUsers.stream().map(User::getUserId).collect(Collectors.toSet()); + TenantContext.setTenantId(tenant.getTenantId()); var redactionObjectsUserIds = new HashSet(); diff --git a/persistence-service-v1/persistence-service-external-api-impl-v1/src/main/java/com/iqser/red/persistence/service/v1/external/api/impl/service/GeneralConfigurationService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/GeneralConfigurationService.java similarity index 78% rename from persistence-service-v1/persistence-service-external-api-impl-v1/src/main/java/com/iqser/red/persistence/service/v1/external/api/impl/service/GeneralConfigurationService.java rename to persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/GeneralConfigurationService.java index c3d90ac60..da2b9c4d5 100644 --- a/persistence-service-v1/persistence-service-external-api-impl-v1/src/main/java/com/iqser/red/persistence/service/v1/external/api/impl/service/GeneralConfigurationService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/GeneralConfigurationService.java @@ -1,4 +1,4 @@ -package com.iqser.red.persistence.service.v1.external.api.impl.service; +package com.iqser.red.service.persistence.management.v1.processor.service; import org.apache.commons.lang3.StringUtils; import org.keycloak.representations.idm.RealmRepresentation; @@ -7,10 +7,13 @@ import org.springframework.stereotype.Service; import com.iqser.red.keycloak.commons.KeyCloakSettings; import com.iqser.red.keycloak.commons.RealmService; import com.iqser.red.service.persistence.management.v1.processor.settings.FileManagementServiceSettings; +import com.iqser.red.service.persistence.management.v1.processor.utils.multitenancy.TenantContext; import com.iqser.red.service.persistence.service.v1.api.shared.model.GeneralConfigurationModel; import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +@Slf4j @Service @RequiredArgsConstructor public class GeneralConfigurationService { @@ -19,10 +22,17 @@ public class GeneralConfigurationService { private final FileManagementServiceSettings fileManagementServiceSettings; private final KeyCloakSettings keyCloakSettings; + public void initGeneralConfiguration(String tenantId){ + TenantContext.setTenantId(tenantId); + var generalConfiguration = getGeneralConfigurations(); + log.info("Currently Configured Application Name: {}, default name: {}", generalConfiguration.getDisplayName(), fileManagementServiceSettings.getApplicationName()); + updateGeneralConfigurations(getGeneralConfigurations()); + TenantContext.clear(); + } public GeneralConfigurationModel getGeneralConfigurations() { - var realm = realmService.realm().toRepresentation(); + var realm = realmService.realm(TenantContext.getTenantId()).toRepresentation(); var auxiliaryName = realm.getDisplayNameHtml(); if (!fileManagementServiceSettings.getApplicationName().equals(auxiliaryName)) { @@ -45,7 +55,7 @@ public class GeneralConfigurationService { public void updateGeneralConfigurations(GeneralConfigurationModel generalConfigurationModel) { - var realm = realmService.realm(); + var realm = realmService.realm(TenantContext.getTenantId()); var clientRepresentations = realm.clients().findByClientId(keyCloakSettings.getClientId()); for (var client : clientRepresentations) { diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/KeyCloakRoleManagerApplicationRunner.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/KeyCloakRoleManagerApplicationRunner.java new file mode 100644 index 000000000..3643ffbdf --- /dev/null +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/KeyCloakRoleManagerApplicationRunner.java @@ -0,0 +1,29 @@ +package com.iqser.red.service.persistence.management.v1.processor.service; + +import org.springframework.boot.ApplicationArguments; +import org.springframework.boot.ApplicationRunner; +import org.springframework.stereotype.Component; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@Component +@RequiredArgsConstructor +public class KeyCloakRoleManagerApplicationRunner implements ApplicationRunner { + + private final TenantManagementService tenantManagementService; + private final KeyCloakRoleManagerService keyCloakRoleManagerService; + + + @Override + public void run(ApplicationArguments args) { + + tenantManagementService.getTenants().forEach(tenant -> { + + keyCloakRoleManagerService.updateRoles(tenant.getTenantId()); + + }); + } + +} diff --git a/persistence-service-v1/keycloak-commons/src/main/java/com/iqser/red/keycloak/commons/KeyCloakRoleManager.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/KeyCloakRoleManagerService.java similarity index 70% rename from persistence-service-v1/keycloak-commons/src/main/java/com/iqser/red/keycloak/commons/KeyCloakRoleManager.java rename to persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/KeyCloakRoleManagerService.java index cce6591b6..079efa20b 100644 --- a/persistence-service-v1/keycloak-commons/src/main/java/com/iqser/red/keycloak/commons/KeyCloakRoleManager.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/KeyCloakRoleManagerService.java @@ -1,4 +1,4 @@ -package com.iqser.red.keycloak.commons; +package com.iqser.red.service.persistence.management.v1.processor.service; import static com.iqser.red.keycloak.commons.roles.ActionRoles.GET_RSS; import static com.iqser.red.keycloak.commons.roles.ApplicationRoles.RED_ADMIN_ROLE; @@ -13,12 +13,12 @@ import java.util.stream.Collectors; import org.keycloak.representations.idm.ClientRepresentation; import org.keycloak.representations.idm.RoleRepresentation; -import org.springframework.boot.ApplicationArguments; -import org.springframework.boot.ApplicationRunner; import org.springframework.stereotype.Component; import com.google.common.collect.Lists; import com.google.common.collect.Sets; +import com.iqser.red.keycloak.commons.KeyCloakSettings; +import com.iqser.red.keycloak.commons.RealmService; import com.iqser.red.keycloak.commons.roles.ApplicationRoles; import lombok.RequiredArgsConstructor; @@ -27,23 +27,23 @@ import lombok.extern.slf4j.Slf4j; @Slf4j @Component @RequiredArgsConstructor -public class KeyCloakRoleManager implements ApplicationRunner { +public class KeyCloakRoleManagerService { private final RealmService realmService; - private final KeyCloakSettings settings; - @Override - public void run(ApplicationArguments args) { + public void updateRoles(String tenantId) { + + var realm = realmService.realm(tenantId); log.info("Running KeyCloak Role Manager, managing client: {} with system client {}", settings.getApplicationClientId(), settings.getClientId()); - var existingRoles = realmService.realm().roles().list().stream().map(RoleRepresentation::getName).collect(Collectors.toList()); + var existingRoles = realm.roles().list().stream().map(RoleRepresentation::getName).collect(Collectors.toList()); log.info("Existing KC roles: {}", existingRoles); - var redactionClientRepresentation = getRedactionClientRepresentation(); - var redactionClient = realmService.realm().clients().get(redactionClientRepresentation.getId()); + var redactionClientRepresentation = getRedactionClientRepresentation(tenantId); + var redactionClient = realm.clients().get(redactionClientRepresentation.getId()); var clientRoles = redactionClient.roles().list().stream().map(RoleRepresentation::getName).collect(Collectors.toList()); var allRoles = ApplicationRoles.ROLE_DATA.values().stream().flatMap(Set::stream).collect(Collectors.toSet()); @@ -58,8 +58,8 @@ public class KeyCloakRoleManager implements ApplicationRunner { clientRoles.forEach(clientRole -> { try { redactionClient.roles().deleteRole(clientRole); - }catch (Exception e){ - log.warn("Failed to delete client role: {}",clientRole); + } catch (Exception e) { + log.warn("Failed to delete client role: {}", clientRole); } }); @@ -86,43 +86,41 @@ public class KeyCloakRoleManager implements ApplicationRunner { log.info("Application Role: {} doesn't exist, creating it now", applicationRole); var role = new RoleRepresentation(applicationRole, applicationRole, false); role.setComposite(true); - realmService.realm().roles().create(role); + realm.roles().create(role); } - var applicationRoleResource = realmService.realm().roles().get(applicationRole); - Set composites = realmService.realm() - .rolesById() + var applicationRoleResource = realm.roles().get(applicationRole); + Set composites = realm.rolesById() .getClientRoleComposites(applicationRoleResource.toRepresentation().getId(), redactionClient.toRepresentation().getId()); log.info("Deleting previous composites for application role {}", applicationRole); - realmService.realm().rolesById().deleteComposites(applicationRoleResource.toRepresentation().getId(), new ArrayList<>(composites)); + realm.rolesById().deleteComposites(applicationRoleResource.toRepresentation().getId(), new ArrayList<>(composites)); var relevantClientRoles = allClientRoles.stream().filter(role -> ApplicationRoles.ROLE_DATA.get(applicationRole).contains(role.getName())).collect(Collectors.toList()); log.info("Writing new composites for application role {}", applicationRole); - realmService.realm().rolesById().addComposites(applicationRoleResource.toRepresentation().getId(), relevantClientRoles); + realm.rolesById().addComposites(applicationRoleResource.toRepresentation().getId(), relevantClientRoles); log.info("Finished application role {}", applicationRole); } // add RED_USER Realm Role to RED_MANAGER - var redUserRole = realmService.realm().roles().get(RED_USER_ROLE); - var redManagerRole = realmService.realm().roles().get(RED_MANAGER_ROLE); + var redUserRole = realm.roles().get(RED_USER_ROLE); + var redManagerRole = realm.roles().get(RED_MANAGER_ROLE); - realmService.realm().rolesById().addComposites(redManagerRole.toRepresentation().getId(), Lists.newArrayList(redUserRole.toRepresentation())); + realm.rolesById().addComposites(redManagerRole.toRepresentation().getId(), Lists.newArrayList(redUserRole.toRepresentation())); // add RED_USER_ADMIN Realm Role to RED_ADMIN - var redAdminRole = realmService.realm().roles().get(RED_ADMIN_ROLE); - var redUserAdminRole = realmService.realm().roles().get(RED_USER_ADMIN_ROLE); + var redAdminRole = realm.roles().get(RED_ADMIN_ROLE); + var redUserAdminRole = realm.roles().get(RED_USER_ADMIN_ROLE); - realmService.realm().rolesById().addComposites(redAdminRole.toRepresentation().getId(), Lists.newArrayList(redUserAdminRole.toRepresentation())); + realm.rolesById().addComposites(redAdminRole.toRepresentation().getId(), Lists.newArrayList(redUserAdminRole.toRepresentation())); - log.info("Finished KC Role Manager"); + log.info("Finished KC Role Manager for tenant {}", tenantId); } - - private ClientRepresentation getRedactionClientRepresentation() { + private ClientRepresentation getRedactionClientRepresentation(String tenantId) { String applicationClientId = settings.getApplicationClientId(); - var clientRepresentationIterator = realmService.realm().clients().findByClientId(applicationClientId).iterator(); + var clientRepresentationIterator = realmService.realm(tenantId).clients().findByClientId(applicationClientId).iterator(); if (clientRepresentationIterator.hasNext()) { return clientRepresentationIterator.next(); 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 2f01ef3d4..454bc1bfc 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 @@ -63,19 +63,23 @@ public class TenantManagementService { private final ResourceLoader resourceLoader; private final TenantRepository tenantRepository; private final AsyncMigrationStarterService asyncMigrationStarterService; + private final GeneralConfigurationService generalConfigurationService; + private final KeyCloakRoleManagerService keyCloakRoleManagerService; public TenantManagementService(EncryptionDecryptionService encryptionService, @Qualifier("tenantLiquibaseProperties") LiquibaseProperties liquibaseProperties, ResourceLoader resourceLoader, TenantRepository tenantRepository, - AsyncMigrationStarterService asyncMigrationStarterService) { + AsyncMigrationStarterService asyncMigrationStarterService, GeneralConfigurationService generalConfigurationService, KeyCloakRoleManagerService keyCloakRoleManagerService) { this.encryptionService = encryptionService; this.liquibaseProperties = liquibaseProperties; this.resourceLoader = resourceLoader; this.tenantRepository = tenantRepository; this.asyncMigrationStarterService = asyncMigrationStarterService; + this.generalConfigurationService = generalConfigurationService; + this.keyCloakRoleManagerService = keyCloakRoleManagerService; } @@ -141,6 +145,8 @@ public class TenantManagementService { tenantRepository.save(tenantEntity); + generalConfigurationService.initGeneralConfiguration(tenantRequest.getTenantId()); + keyCloakRoleManagerService.updateRoles(tenantRequest.getTenantId()); asyncMigrationStarterService.runForTenant(tenantRequest.getTenantId()); } else { diff --git a/persistence-service-v1/keycloak-commons/src/main/java/com/iqser/red/keycloak/commons/UserCacheBuilder.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/UserCacheBuilder.java similarity index 53% rename from persistence-service-v1/keycloak-commons/src/main/java/com/iqser/red/keycloak/commons/UserCacheBuilder.java rename to persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/UserCacheBuilder.java index a949f589c..998d333ec 100644 --- a/persistence-service-v1/keycloak-commons/src/main/java/com/iqser/red/keycloak/commons/UserCacheBuilder.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/UserCacheBuilder.java @@ -1,9 +1,11 @@ -package com.iqser.red.keycloak.commons; +package com.iqser.red.service.persistence.management.v1.processor.service; import javax.annotation.PostConstruct; import org.springframework.stereotype.Service; +import com.iqser.red.keycloak.commons.UserListingService; + import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -12,15 +14,14 @@ import lombok.extern.slf4j.Slf4j; @RequiredArgsConstructor public class UserCacheBuilder { - public static final String USERS_CACHE = "users"; - private final UserListingService userService; + private final TenantManagementService tenantManagementService; @PostConstruct protected void postConstruct() { - userService.getAllUsers(); + tenantManagementService.getTenants().forEach(tenant -> userService.getAllUsers(tenant.getTenantId())); } } diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/UserService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/UserService.java index f1e777ac3..ef5fc22e0 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/UserService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/UserService.java @@ -1,6 +1,6 @@ package com.iqser.red.service.persistence.management.v1.processor.service; -import static com.iqser.red.keycloak.commons.UserCacheBuilder.USERS_CACHE; +import static com.iqser.red.keycloak.commons.DefaultKeyCloakCommonsConfiguration.USERS_CACHE; 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; @@ -52,6 +52,7 @@ import com.iqser.red.service.persistence.management.v1.processor.exception.Confl import com.iqser.red.service.persistence.management.v1.processor.exception.NotAllowedException; import com.iqser.red.service.persistence.management.v1.processor.service.persistence.AuditPersistenceService; import com.iqser.red.service.persistence.management.v1.processor.service.persistence.NotificationPersistenceService; +import com.iqser.red.service.persistence.management.v1.processor.utils.multitenancy.TenantContext; import com.iqser.red.service.persistence.service.v1.api.shared.model.AuditCategory; import com.iqser.red.service.persistence.service.v1.api.shared.model.CreateUserRequest; import com.iqser.red.service.persistence.service.v1.api.shared.model.ResetPasswordRequest; @@ -91,7 +92,7 @@ public class UserService { @CacheEvict(value = USERS_CACHE, allEntries = true, beforeInvocation = true) public User createUser(CreateUserRequest user) { - if (!realmService.realm().users().search(user.getEmail()).isEmpty()) { + if (!realmService.realm(TenantContext.getTenantId()).users().search(user.getEmail()).isEmpty()) { throw new ConflictException("User with this username already exists"); } @@ -108,7 +109,7 @@ public class UserService { userRepresentation.setFirstName(user.getFirstName()); userRepresentation.setLastName(user.getLastName()); - try (var response = realmService.realm().users().create(userRepresentation)) { + try (var response = realmService.realm(TenantContext.getTenantId()).users().create(userRepresentation)) { if (response.getStatusInfo().getFamily() != Response.Status.Family.SUCCESSFUL) { if (response.getStatusInfo().getStatusCode() == 409) { @@ -148,7 +149,7 @@ public class UserService { private User getUserByUsername(String username) { - var userList = realmService.realm().users().search(username); + var userList = realmService.realm(TenantContext.getTenantId()).users().search(username); if (userList.isEmpty()) { throw new NotFoundException("User with this username already exists"); } @@ -160,7 +161,7 @@ public class UserService { private void sendResetPasswordEmail(String userId) { try { - realmService.realm().users().get(userId).executeActionsEmail(Collections.singletonList("UPDATE_PASSWORD"), 86400); + realmService.realm(TenantContext.getTenantId()).users().get(userId).executeActionsEmail(Collections.singletonList("UPDATE_PASSWORD"), 86400); } catch (Exception e) { throw new BadRequestException("Failed to send email", e); } @@ -251,7 +252,7 @@ public class UserService { throw new BadRequestException("No id provided."); } try { - return realmService.realm().users().get(userId); + return realmService.realm(TenantContext.getTenantId()).users().get(userId); } catch (NotFoundException e) { throw new NotFoundException("User with id: " + userId + " does not exist", e); } @@ -274,7 +275,7 @@ public class UserService { RoleRepresentation realmRole; try { - realmRole = realmService.realm().roles().get(role).toRepresentation(); + realmRole = realmService.realm(TenantContext.getTenantId()).roles().get(role).toRepresentation(); } catch (NotFoundException e) { log.warn("The realm role {} is not found.", role); throw new NotFoundException("The realm role " + role + " is not found.", e); @@ -285,7 +286,7 @@ public class UserService { private Set getRoles(String id) { - List realmMappings = realmService.realm().users().get(id).roles().getAll().getRealmMappings(); + List realmMappings = realmService.realm(TenantContext.getTenantId()).users().get(id).roles().getAll().getRealmMappings(); if (realmMappings == null) { log.warn("User with id=" + id + " contains null role mappings."); return new TreeSet<>(); @@ -338,20 +339,20 @@ public class UserService { public Optional getUserById(String userId) { - return userListingService.getAllUsers().stream().filter(u -> u.getUserId().equalsIgnoreCase(userId)).findAny(); + return userListingService.getAllUsers(TenantContext.getTenantId()).stream().filter(u -> u.getUserId().equalsIgnoreCase(userId)).findAny(); } public List getUsersByIds(Collection userIds) { - return userListingService.getAllUsers().stream().filter(u -> userIds.contains(u.getUserId())).collect(Collectors.toList()); + return userListingService.getAllUsers(TenantContext.getTenantId()).stream().filter(u -> userIds.contains(u.getUserId())).collect(Collectors.toList()); } @CacheEvict(value = USERS_CACHE, allEntries = true, beforeInvocation = true) public void updateMyProfile(UpdateMyProfileRequest updateProfileRequest) { - var user = realmService.realm().users().get(KeycloakSecurity.getUserId()); + var user = realmService.realm(TenantContext.getTenantId()).users().get(KeycloakSecurity.getUserId()); var userRepresentation = user.toRepresentation(); if (userRepresentation.getFederatedIdentities() != null && !userRepresentation.getFederatedIdentities().isEmpty() && !updateProfileRequest.getEmail() @@ -396,7 +397,7 @@ public class UserService { var changeEmailClient = KeycloakBuilder.builder() .serverUrl(keyCloakSettings.getServerUrl()) - .realm(keyCloakSettings.getRealm()) + .realm(TenantContext.getTenantId()) .username(username) .password(password) .clientId(keyCloakSettings.getClientId()) @@ -442,7 +443,7 @@ public class UserService { removeUserFromDossiers(userId, UserRemovalModel.PERMANENT); - realmService.realm().users().get(userId).remove(); + realmService.realm(TenantContext.getTenantId()).users().get(userId).remove(); customPermissionService.syncAllCustomPermissions(); auditPersistenceService.audit(AuditRequest.builder() @@ -460,7 +461,7 @@ public class UserService { */ public Set removeDeletedUsers(@NotNull Set userIds) { - var users = userListingService.getAllUsers(); + var users = userListingService.getAllUsers(TenantContext.getTenantId()); Set deletedUsers = new HashSet<>(); for (String userId : userIds) { @@ -468,7 +469,7 @@ public class UserService { log.info("Will delete {} user", userId); removeUserFromDossiers(userId, UserRemovalModel.PERMANENT); - realmService.realm().users().delete(userId); + realmService.realm(TenantContext.getTenantId()).users().delete(userId); auditPersistenceService.audit(AuditRequest.builder().objectId(userId).category(AuditCategory.USER.name()).message("User removed automatically").build()); deletedUsers.add(userId); @@ -483,7 +484,7 @@ public class UserService { @CacheEvict(value = USERS_CACHE, allEntries = true, beforeInvocation = true) public void updateProfile(String userId, UpdateProfileRequest updateProfileRequest) { - var user = realmService.realm().users().get(userId); + var user = realmService.realm(TenantContext.getTenantId()).users().get(userId); var userRepresentation = user.toRepresentation(); if (userRepresentation.getFederatedIdentities() != null && !userRepresentation.getFederatedIdentities().isEmpty() && !updateProfileRequest.getEmail() @@ -515,7 +516,7 @@ public class UserService { public User activateProfile(String userId, boolean isActive) { - var user = realmService.realm().users().get(userId); + var user = realmService.realm(TenantContext.getTenantId()).users().get(userId); var userRepresentation = user.toRepresentation(); userRepresentation.setEnabled(isActive); @@ -534,7 +535,7 @@ public class UserService { .details(Map.of("Profile activated", isActive)) .build()); - return convert(realmService.realm().users().get(userId).toRepresentation()); + return convert(realmService.realm(TenantContext.getTenantId()).users().get(userId).toRepresentation()); } @@ -545,7 +546,7 @@ public class UserService { request.setType("password"); request.setTemporary(resetPasswordRequest.isTemporary()); request.setValue(resetPasswordRequest.getPassword()); - realmService.realm().users().get(userId).resetPassword(request); + realmService.realm(TenantContext.getTenantId()).users().get(userId).resetPassword(request); } catch (Exception e) { throw new BadRequestException("Failed to send email", e); } @@ -554,7 +555,7 @@ public class UserService { public List getAllUsers() { - return userListingService.getAllUsers(); + return userListingService.getAllUsers(TenantContext.getTenantId()); } 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 d0e86dfeb..525d98b73 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 @@ -230,13 +230,15 @@ public abstract class AbstractPersistenceServerServiceTest { public void createUsers() { + TenantContext.setTenantId("redaction"); + when(keyCloakAdminClientService.getAdminClient()).thenReturn(KeyCloakTestContainer.getInstance().getKeycloakAdminClient()); userService.evictUserCache(); var allUsers = userService.getAllUsers(); if (allUsers.isEmpty()) { - TenantContext.setTenantId("redaction"); + 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 2c8681a76..cb873ee2d 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 @@ -5,6 +5,7 @@ import java.util.concurrent.TimeUnit; import javax.ws.rs.NotAuthorizedException; import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder; +import org.jboss.resteasy.client.jaxrs.internal.ResteasyClientBuilderImpl; import org.keycloak.OAuth2Constants; import org.keycloak.admin.client.KeycloakBuilder; import org.springframework.beans.factory.annotation.Autowired; @@ -12,8 +13,7 @@ import org.springframework.stereotype.Service; import com.iqser.red.keycloak.commons.KeyCloakSettings; import com.iqser.red.service.persistence.management.v1.processor.exception.AuthenticationFailedException; - -import org.jboss.resteasy.client.jaxrs.internal.ResteasyClientBuilderImpl; +import com.iqser.red.service.persistence.management.v1.processor.utils.multitenancy.TenantContext; @Service public class TokenService { @@ -33,7 +33,7 @@ public class TokenService { var tokenClient = KeycloakBuilder.builder() .serverUrl(keyCloakSettings.getServerUrl()) - .realm(keyCloakSettings.getRealm()) + .realm(TenantContext.getTenantId()) .username(username) .password(password) .clientId(keyCloakSettings.getClientId())