Pull request #630: RED-6224: Enabled multitenancy for user cache

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

* commit 'd392c1dae77a8ac46f243f586154b104867cf736':
  RED-6224: Enabled multitenancy for user cache
This commit is contained in:
Dominique Eiflaender 2023-03-21 12:58:28 +01:00
commit ae86178cc0
17 changed files with 131 additions and 120 deletions

View File

@ -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() {

View File

@ -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);
}
}

View File

@ -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<User> getAllUsers() {
@Cacheable(value = USERS_CACHE, key = "'tenantId'")
public List<User> getAllUsers(String tenantId) {
return retryTemplate.execute(context -> {
List<UserRepresentation> allUsers = realmService.realm().users().search(null, 0, 500);
var realm = realmService.realm(tenantId);
List<UserRepresentation> allUsers = realm.users().search(null, 0, 500);
Map<String, Set<String>> 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<UserRepresentation> users = realmService.realm().roles().get(role).getRoleUserMembers(0, 500);
Set<UserRepresentation> users = realm.roles().get(role).getRoleUserMembers(0, 500);
usersByRole.put(role, users.stream().map(UserRepresentation::getId).collect(Collectors.toSet()));
}
}

View File

@ -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;

View File

@ -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;

View File

@ -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);
}

View File

@ -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());
}
}

View File

@ -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<T, ID extends Serializable> exten
private Set<String> getUserIds() {
return userListingService.getAllUsers().stream().map(User::getUserId).collect(Collectors.toSet());
return userListingService.getAllUsers(TenantContext.getTenantId()).stream().map(User::getUserId).collect(Collectors.toSet());
}

View File

@ -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<String>();

View File

@ -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) {

View File

@ -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());
});
}
}

View File

@ -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<RoleRepresentation> composites = realmService.realm()
.rolesById()
var applicationRoleResource = realm.roles().get(applicationRole);
Set<RoleRepresentation> 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();

View File

@ -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 {

View File

@ -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()));
}
}

View File

@ -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<String> getRoles(String id) {
List<RoleRepresentation> realmMappings = realmService.realm().users().get(id).roles().getAll().getRealmMappings();
List<RoleRepresentation> 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<User> 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<User> getUsersByIds(Collection<String> 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<String> removeDeletedUsers(@NotNull Set<String> userIds) {
var users = userListingService.getAllUsers();
var users = userListingService.getAllUsers(TenantContext.getTenantId());
Set<String> 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<User> getAllUsers() {
return userListingService.getAllUsers();
return userListingService.getAllUsers(TenantContext.getTenantId());
}

View File

@ -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");

View File

@ -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())