diff --git a/dmp-backend/web/src/main/java/eu/eudat/interceptors/tenant/TenantInterceptor.java b/dmp-backend/web/src/main/java/eu/eudat/interceptors/tenant/TenantInterceptor.java index 62e2d0d0a..59b59d033 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/interceptors/tenant/TenantInterceptor.java +++ b/dmp-backend/web/src/main/java/eu/eudat/interceptors/tenant/TenantInterceptor.java @@ -69,6 +69,7 @@ public class TenantInterceptor implements WebRequestInterceptor { private final ConventionService conventionService; private final UserTouchedIntegrationEventHandler userTouchedIntegrationEventHandler; private final AuthorizationProperties authorizationProperties; + private final UserTenantRolesCacheService userTenantRolesCacheService; @PersistenceContext public EntityManager entityManager; @@ -82,7 +83,7 @@ public class TenantInterceptor implements WebRequestInterceptor { TenantScopeProperties tenantScopeProperties, UserAllowedTenantCacheService userAllowedTenantCacheService, PlatformTransactionManager transactionManager, - ErrorThesaurusProperties errors, QueryUtilsService queryUtilsService, LockByKeyManager lockByKeyManager, ConventionService conventionService, UserTouchedIntegrationEventHandler userTouchedIntegrationEventHandler, AuthorizationProperties authorizationProperties) { + ErrorThesaurusProperties errors, QueryUtilsService queryUtilsService, LockByKeyManager lockByKeyManager, ConventionService conventionService, UserTouchedIntegrationEventHandler userTouchedIntegrationEventHandler, AuthorizationProperties authorizationProperties, UserTenantRolesCacheService userTenantRolesCacheService) { this.tenantScope = tenantScope; this.userScope = userScope; this.currentPrincipalResolver = currentPrincipalResolver; @@ -97,6 +98,7 @@ public class TenantInterceptor implements WebRequestInterceptor { this.conventionService = conventionService; this.userTouchedIntegrationEventHandler = userTouchedIntegrationEventHandler; this.authorizationProperties = authorizationProperties; + this.userTenantRolesCacheService = userTenantRolesCacheService; } @Override @@ -145,7 +147,10 @@ public class TenantInterceptor implements WebRequestInterceptor { } } - this.syncUserWithClaims(); + UserTenantRolesCacheService.UserTenantRolesCacheValue cacheValue = this.userTenantRolesCacheService.lookup(this.userTenantRolesCacheService.buildKey(this.userScope.getUserId(), this.tenantScope.isDefaultTenant() ? UUID.fromString("00000000-0000-0000-0000-000000000000") : this.tenantScope.getTenant())); + if (cacheValue == null || !this.userRolesSynced(cacheValue.getRoles())) { + this.syncUserWithClaims(); + } } else { if (!isAllowedNoTenant) { if (!this.isWhiteListedEndpoint(request)) { @@ -244,6 +249,8 @@ public class TenantInterceptor implements WebRequestInterceptor { } private void syncUserWithClaims() throws InvalidApplicationException, InterruptedException { + + boolean usedResource = false; String lockId = userScope.getUserId().toString().toLowerCase(Locale.ROOT); boolean hasChanges = false; @@ -258,7 +265,14 @@ public class TenantInterceptor implements WebRequestInterceptor { try { status = transactionManager.getTransaction(definition); - List existingUserRoles = this.collectUserRoles(); + UserTenantRolesCacheService.UserTenantRolesCacheValue cacheValue = this.userTenantRolesCacheService.lookup(this.userTenantRolesCacheService.buildKey(this.userScope.getUserId(), this.tenantScope.isDefaultTenant() ? UUID.fromString("00000000-0000-0000-0000-000000000000") : this.tenantScope.getTenant())); + List existingUserRoles; + if (cacheValue != null) { + existingUserRoles = cacheValue.getRoles(); + } else { + existingUserRoles = this.collectUserRoles(); + this.userTenantRolesCacheService.put(new UserTenantRolesCacheService.UserTenantRolesCacheValue(this.userScope.getUserId(), this.tenantScope.isDefaultTenant() ? UUID.fromString("00000000-0000-0000-0000-000000000000") : this.tenantScope.getTenant(), existingUserRoles)); + } if (!this.userRolesSynced(existingUserRoles)) { this.syncRoles(); hasChanges = true; diff --git a/dmp-backend/web/src/main/java/eu/eudat/interceptors/tenant/UserAllowedTenantCacheOptions.java b/dmp-backend/web/src/main/java/eu/eudat/interceptors/tenant/UserAllowedTenantCacheOptions.java index d5bd5d9ca..4443c70f2 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/interceptors/tenant/UserAllowedTenantCacheOptions.java +++ b/dmp-backend/web/src/main/java/eu/eudat/interceptors/tenant/UserAllowedTenantCacheOptions.java @@ -8,3 +8,5 @@ import org.springframework.context.annotation.Configuration; @ConfigurationProperties(prefix = "cache.user-allowed-tenant") public class UserAllowedTenantCacheOptions extends CacheOptions { } + + diff --git a/dmp-backend/web/src/main/java/eu/eudat/interceptors/tenant/UserAllowedTenantCacheService.java b/dmp-backend/web/src/main/java/eu/eudat/interceptors/tenant/UserAllowedTenantCacheService.java index 7bcc92a69..951ba891d 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/interceptors/tenant/UserAllowedTenantCacheService.java +++ b/dmp-backend/web/src/main/java/eu/eudat/interceptors/tenant/UserAllowedTenantCacheService.java @@ -88,3 +88,4 @@ public class UserAllowedTenantCacheService extends CacheService { + + public static class UserTenantRolesCacheValue { + + public UserTenantRolesCacheValue() { + } + + public UserTenantRolesCacheValue(UUID userId, UUID tenantId, List roles) { + this.userId = userId; + this.tenantId = tenantId; + this.roles = roles; + } + + private UUID userId; + + public UUID getUserId() { + return userId; + } + + public void setUserId(UUID userId) { + this.userId = userId; + } + + private UUID tenantId; + + public UUID getTenantId() { + return tenantId; + } + + public void setTenantId(UUID tenantId) { + this.tenantId = tenantId; + } + + private List roles; + + public List getRoles() { + return roles; + } + + public void setRoles(List roles) { + this.roles = roles; + } + } + + @Autowired + public UserTenantRolesCacheService(UserTenantRolesCacheOptions options) { + super(options); + } + + @EventListener + public void handleUserRemovedFromTenantEvent(UserRemovedFromTenantEvent event) { + this.evict(this.buildKey(event.getUserId(), event.getTenantId())); + } + + @EventListener + public void handleUserAddedToTenantEvent(UserAddedToTenantEvent event) { + this.evict(this.buildKey(event.getUserId(), event.getTenantId())); + } + + @Override + protected Class valueClass() { + return UserTenantRolesCacheValue.class; + } + + @Override + public String keyOf(UserTenantRolesCacheValue value) { + return this.buildKey(value.getUserId(), value.getTenantId()); + } + + public String buildKey(UUID userId, UUID tenantId) { + HashMap keyParts = new HashMap<>(); + keyParts.put("$user_id$", userId.toString().toLowerCase(Locale.ROOT)); + keyParts.put("$tenant_id$", tenantId.toString().toLowerCase(Locale.ROOT)); + return this.generateKey(keyParts); + } +} diff --git a/dmp-backend/web/src/main/resources/config/cache.yml b/dmp-backend/web/src/main/resources/config/cache.yml index 050ca19de..c79b7f88f 100644 --- a/dmp-backend/web/src/main/resources/config/cache.yml +++ b/dmp-backend/web/src/main/resources/config/cache.yml @@ -68,6 +68,12 @@ cache: maximumSize: 500 enableRecordStats: false expireAfterWriteSeconds: 60 + - names: [ userTenantRoles ] + allowNullValues: true + initialCapacity: 100 + maximumSize: 500 + enableRecordStats: false + expireAfterWriteSeconds: 60 mapCaches: userBySubjectId: name: userBySubjectId @@ -81,6 +87,9 @@ cache: userAllowedTenant: name: userAllowedTenant keyPattern: user_allowed_tenant$tenant_id$_$user_id$:v0 + userTenantRoles: + name: userTenantRoles + keyPattern: user_tenant_roles$tenant_id$_$user_id$:v0 supportiveMaterial: name: supportiveMaterial keyPattern: supportive_material_$type$_$lang$:v0