From a5f31ab88099fcc4f8e0bf22803b897ea2ee40b3 Mon Sep 17 00:00:00 2001 From: sgiannopoulos Date: Wed, 3 Apr 2024 10:15:28 +0300 Subject: [PATCH 1/4] add cache to tenant interceptor --- .../tenant/TenantInterceptor.java | 20 +++- .../tenant/UserAllowedTenantCacheOptions.java | 2 + .../tenant/UserAllowedTenantCacheService.java | 1 + .../tenant/UserTenantRolesCacheOptions.java | 10 ++ .../tenant/UserTenantRolesCacheService.java | 91 +++++++++++++++++++ .../web/src/main/resources/config/cache.yml | 9 ++ 6 files changed, 130 insertions(+), 3 deletions(-) create mode 100644 dmp-backend/web/src/main/java/eu/eudat/interceptors/tenant/UserTenantRolesCacheOptions.java create mode 100644 dmp-backend/web/src/main/java/eu/eudat/interceptors/tenant/UserTenantRolesCacheService.java 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 From a5e69fe7773eabbec9556d7f3dd17c9d200ea48a Mon Sep 17 00:00:00 2001 From: sgiannopoulos Date: Wed, 3 Apr 2024 10:24:51 +0300 Subject: [PATCH 2/4] bug fix --- .../eu/eudat/interceptors/tenant/TenantInterceptor.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) 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 59b59d033..ebf5a7059 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 @@ -138,6 +138,10 @@ public class TenantInterceptor implements WebRequestInterceptor { .unwrap(Session.class) .enableFilter(TenantScopedBaseEntity.DEFAULT_TENANT_FILTER); } + 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 || this.isWhiteListedEndpoint(request)) { tenantScope.setTenant(null, null); @@ -146,11 +150,6 @@ public class TenantInterceptor implements WebRequestInterceptor { throw new MyForbiddenException(this.errors.getTenantNotAllowed().getCode(), this.errors.getTenantNotAllowed().getMessage()); } } - - 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)) { From b3db6f10850eb2faf741b3d4ef4dc7c50bc74595 Mon Sep 17 00:00:00 2001 From: sgiannopoulos Date: Wed, 3 Apr 2024 11:36:31 +0300 Subject: [PATCH 3/4] remove tenant from UserContactInfo UserCredential --- .../00.01.034_Add_ntf_User_Credential.sql | 6 ------ .../00.01.043_addTenant_Id_to_Tables.sql | 18 ------------------ .../00.01.052_Add_ant_User_Credential.sql | 6 ------ 3 files changed, 30 deletions(-) diff --git a/dmp-db-scema/updates/00.01.034_Add_ntf_User_Credential.sql b/dmp-db-scema/updates/00.01.034_Add_ntf_User_Credential.sql index 38e40c78a..9dc8332a2 100644 --- a/dmp-db-scema/updates/00.01.034_Add_ntf_User_Credential.sql +++ b/dmp-db-scema/updates/00.01.034_Add_ntf_User_Credential.sql @@ -12,14 +12,8 @@ CREATE TABLE IF NOT EXISTS public."ntf_UserCredential" "created_at" timestamp without time zone NOT NULL, "updated_at" timestamp without time zone NOT NULL, "is_active" smallint NOT NULL DEFAULT 1, - "tenant" uuid, "data" character varying COLLATE pg_catalog."default", CONSTRAINT "ntf_UserCredential_pkey" PRIMARY KEY (id), - CONSTRAINT "ntf_UserCredential_tenant_fkey" FOREIGN KEY ("tenant") - REFERENCES public."ntf_Tenant" (id) MATCH SIMPLE - ON UPDATE NO ACTION - ON DELETE NO ACTION - NOT VALID, CONSTRAINT "ntf_UserCredential_user_fkey" FOREIGN KEY ("user") REFERENCES public."ntf_User" (id) MATCH SIMPLE ON UPDATE NO ACTION diff --git a/dmp-db-scema/updates/00.01.043_addTenant_Id_to_Tables.sql b/dmp-db-scema/updates/00.01.043_addTenant_Id_to_Tables.sql index b02decacd..9dbf92285 100644 --- a/dmp-db-scema/updates/00.01.043_addTenant_Id_to_Tables.sql +++ b/dmp-db-scema/updates/00.01.043_addTenant_Id_to_Tables.sql @@ -157,24 +157,6 @@ BEGIN ON DELETE NO ACTION NOT VALID; - ALTER TABLE public."UserContactInfo" - ADD COLUMN tenant uuid; - ALTER TABLE public."UserContactInfo" - ADD CONSTRAINT "UserContactInfo_tenant_fkey" FOREIGN KEY (tenant) - REFERENCES public."Tenant" (id) - ON UPDATE NO ACTION - ON DELETE NO ACTION - NOT VALID; - - ALTER TABLE public."UserCredential" - ADD COLUMN tenant uuid; - ALTER TABLE public."UserCredential" - ADD CONSTRAINT "UserCredential_tenant_fkey" FOREIGN KEY (tenant) - REFERENCES public."Tenant" (id) - ON UPDATE NO ACTION - ON DELETE NO ACTION - NOT VALID; - ALTER TABLE public."UserDescriptionTemplate" ADD COLUMN tenant uuid; ALTER TABLE public."UserDescriptionTemplate" diff --git a/dmp-db-scema/updates/00.01.052_Add_ant_User_Credential.sql b/dmp-db-scema/updates/00.01.052_Add_ant_User_Credential.sql index 22e574867..f2c9dec8f 100644 --- a/dmp-db-scema/updates/00.01.052_Add_ant_User_Credential.sql +++ b/dmp-db-scema/updates/00.01.052_Add_ant_User_Credential.sql @@ -12,14 +12,8 @@ CREATE TABLE IF NOT EXISTS public."ant_UserCredential" "created_at" timestamp without time zone NOT NULL, "updated_at" timestamp without time zone NOT NULL, "is_active" smallint NOT NULL DEFAULT 1, - "tenant" uuid, "data" character varying COLLATE pg_catalog."default", CONSTRAINT "ant_UserCredential_pkey" PRIMARY KEY (id), - CONSTRAINT "ant_UserCredential_tenant_fkey" FOREIGN KEY ("tenant") - REFERENCES public."ant_Tenant" (id) MATCH SIMPLE - ON UPDATE NO ACTION - ON DELETE NO ACTION - NOT VALID, CONSTRAINT "ant_UserCredential_user_fkey" FOREIGN KEY ("user") REFERENCES public."ant_User" (id) MATCH SIMPLE ON UPDATE NO ACTION From f47c049b8c672e5ac97e2930842b82e219e9da79 Mon Sep 17 00:00:00 2001 From: sgiannopoulos Date: Wed, 3 Apr 2024 12:22:43 +0300 Subject: [PATCH 4/4] elastic apply tenant logic --- .../eu/eudat/data/TenantEntityManager.java | 25 ++++++ .../data/DescriptionElasticEntity.java | 13 ++- .../eudat/elastic/data/DmpElasticEntity.java | 12 +++ .../DescriptionElasticBuilder.java | 3 + .../elasticbuilder/DmpElasticBuilder.java | 3 + .../query/DescriptionElasticQuery.java | 37 +++++++-- .../eudat/elastic/query/DmpElasticQuery.java | 39 ++++++++- .../eudat/service/elastic/ElasticService.java | 4 +- .../service/elastic/ElasticServiceImpl.java | 79 +++++++++++-------- 9 files changed, 171 insertions(+), 44 deletions(-) diff --git a/dmp-backend/core/src/main/java/eu/eudat/data/TenantEntityManager.java b/dmp-backend/core/src/main/java/eu/eudat/data/TenantEntityManager.java index efbaccdb2..ba8a2b77b 100644 --- a/dmp-backend/core/src/main/java/eu/eudat/data/TenantEntityManager.java +++ b/dmp-backend/core/src/main/java/eu/eudat/data/TenantEntityManager.java @@ -3,12 +3,14 @@ package eu.eudat.data; import eu.eudat.authorization.Permission; import eu.eudat.commons.scope.tenant.TenantScope; import eu.eudat.commons.scope.tenant.TenantScoped; +import eu.eudat.data.tenant.TenantScopedBaseEntity; import gr.cite.commons.web.authz.service.AuthorizationService; import gr.cite.commons.web.oidc.principal.CurrentPrincipalResolver; import gr.cite.commons.web.oidc.principal.extractor.ClaimExtractor; import gr.cite.tools.exception.MyForbiddenException; import jakarta.persistence.*; +import org.hibernate.Session; import org.springframework.stereotype.Service; import org.springframework.web.context.annotation.RequestScope; @@ -80,5 +82,28 @@ public class TenantEntityManager { public void clear() { this.entityManager.clear(); } + + public void enableTenantFilters() throws InvalidApplicationException { + if(!tenantScope.isDefaultTenant()) { + this.entityManager + .unwrap(Session.class) + .enableFilter(TenantScopedBaseEntity.TENANT_FILTER) + .setParameter(TenantScopedBaseEntity.TENANT_FILTER_TENANT_PARAM, tenantScope.getTenant().toString()); + } else { + this.entityManager + .unwrap(Session.class) + .enableFilter(TenantScopedBaseEntity.DEFAULT_TENANT_FILTER); + } + } + + public void disableTenantFilters(){ + this.entityManager + .unwrap(Session.class) + .disableFilter(TenantScopedBaseEntity.TENANT_FILTER); + + this.entityManager + .unwrap(Session.class) + .disableFilter(TenantScopedBaseEntity.DEFAULT_TENANT_FILTER); + } } diff --git a/dmp-backend/core/src/main/java/eu/eudat/elastic/data/DescriptionElasticEntity.java b/dmp-backend/core/src/main/java/eu/eudat/elastic/data/DescriptionElasticEntity.java index df810740b..3a5078cb9 100644 --- a/dmp-backend/core/src/main/java/eu/eudat/elastic/data/DescriptionElasticEntity.java +++ b/dmp-backend/core/src/main/java/eu/eudat/elastic/data/DescriptionElasticEntity.java @@ -1,7 +1,6 @@ package eu.eudat.elastic.data; import eu.eudat.commons.enums.DescriptionStatus; -import eu.eudat.commons.enums.DescriptionTemplateVersionStatus; import eu.eudat.elastic.data.nested.*; import gr.cite.tools.elastic.ElasticConstants; import org.springframework.data.annotation.Id; @@ -19,6 +18,10 @@ public class DescriptionElasticEntity { private UUID id; public final static String _id = "id"; + @Field(value = DescriptionElasticEntity._tenantId, type = FieldType.Keyword) + private UUID tenantId; + public final static String _tenantId = "tenantId"; + @MultiField(mainField = @Field(value = DescriptionElasticEntity._label, type = FieldType.Text), otherFields = { @InnerField(suffix = ElasticConstants.SubFields.keyword, type = FieldType.Keyword) }) @@ -65,6 +68,14 @@ public class DescriptionElasticEntity { this.id = id; } + public UUID getTenantId() { + return tenantId; + } + + public void setTenantId(UUID tenantId) { + this.tenantId = tenantId; + } + public String getLabel() { return label; } diff --git a/dmp-backend/core/src/main/java/eu/eudat/elastic/data/DmpElasticEntity.java b/dmp-backend/core/src/main/java/eu/eudat/elastic/data/DmpElasticEntity.java index 1bc1eaa28..6adfc844e 100644 --- a/dmp-backend/core/src/main/java/eu/eudat/elastic/data/DmpElasticEntity.java +++ b/dmp-backend/core/src/main/java/eu/eudat/elastic/data/DmpElasticEntity.java @@ -19,6 +19,10 @@ public class DmpElasticEntity { private UUID id; public final static String _id = "id"; + @Field(value = DmpElasticEntity._tenantId, type = FieldType.Keyword) + private UUID tenantId; + public final static String _tenantId = "tenantId"; + @MultiField(mainField = @Field(value = DmpElasticEntity._label, type = FieldType.Text), otherFields = { @InnerField(suffix = ElasticConstants.SubFields.keyword, type = FieldType.Keyword) }) @@ -84,6 +88,14 @@ public class DmpElasticEntity { this.id = id; } + public UUID getTenantId() { + return tenantId; + } + + public void setTenantId(UUID tenantId) { + this.tenantId = tenantId; + } + public String getLabel() { return label; } diff --git a/dmp-backend/core/src/main/java/eu/eudat/elastic/elasticbuilder/DescriptionElasticBuilder.java b/dmp-backend/core/src/main/java/eu/eudat/elastic/elasticbuilder/DescriptionElasticBuilder.java index cf5c332e7..62921c448 100644 --- a/dmp-backend/core/src/main/java/eu/eudat/elastic/elasticbuilder/DescriptionElasticBuilder.java +++ b/dmp-backend/core/src/main/java/eu/eudat/elastic/elasticbuilder/DescriptionElasticBuilder.java @@ -67,6 +67,9 @@ public class DescriptionElasticBuilder extends BaseElasticBuilder predicates){ + if (this.tenantScope.isSet()){ + Query tenantQuery; + if (this.tenantScope.isDefaultTenant()){ + tenantQuery = this.fieldNotExists(this.elasticFieldOf(DescriptionElasticEntity._tenantId))._toQuery(); + } + else { + try { + tenantQuery = this.or(this.fieldNotExists(this.elasticFieldOf(DescriptionElasticEntity._tenantId))._toQuery(), + this.equals(this.elasticFieldOf(DescriptionElasticEntity._tenantId), this.tenantScope.getTenant()))._toQuery(); + } catch (InvalidApplicationException e) { + throw new RuntimeException(e); + } + } + if (predicates == null) return tenantQuery; + else return this.and(tenantQuery, this.or(predicates)._toQuery()); + } else { + if (predicates != null) return this.or(predicates)._toQuery(); + } + return null; + } + @Override protected Query applyAuthZ() { - if (this.authorize.contains(AuthorizationFlags.None)) return null; - //if (this.authorize.contains(AuthorizationFlags.Permission) && this.authService.authorize(Permission.BrowseDescription)) return null; + if (this.authorize.contains(AuthorizationFlags.None)) return this.applyTenant(null); + if (this.authorize.contains(AuthorizationFlags.Permission) && this.authService.authorize(Permission.BrowseDescription)) return this.applyTenant(null); UUID userId = null; boolean usePublic = this.authorize.contains(AuthorizationFlags.Public); if (this.authorize.contains(AuthorizationFlags.DmpAssociated)) userId = this.userScope.getUserIdSafe(); @@ -175,9 +202,9 @@ public class DescriptionElasticQuery extends ElasticQuery { private final AppElasticProperties appElasticProperties; private final ElasticService elasticService; private final UserScope userScope; + private final TenantScope tenantScope; private final AuthorizationService authService; @Autowired() - public DmpElasticQuery(ElasticsearchTemplate elasticsearchTemplate, ElasticProperties elasticProperties, QueryFactory queryFactory, AppElasticProperties appElasticProperties, ElasticService elasticService, UserScope userScope, AuthorizationService authService) { + public DmpElasticQuery(ElasticsearchTemplate elasticsearchTemplate, ElasticProperties elasticProperties, QueryFactory queryFactory, AppElasticProperties appElasticProperties, ElasticService elasticService, UserScope userScope, TenantScope tenantScope, AuthorizationService authService) { super(elasticsearchTemplate, elasticProperties); this.queryFactory = queryFactory; this.appElasticProperties = appElasticProperties; this.elasticService = elasticService; this.userScope = userScope; + this.tenantScope = tenantScope; this.authService = authService; } @@ -183,10 +188,32 @@ public class DmpElasticQuery extends ElasticQuery { return DmpElasticEntity.class; } + private Query applyTenant(List predicates){ + if (this.tenantScope.isSet()){ + Query tenantQuery; + if (this.tenantScope.isDefaultTenant()){ + tenantQuery = this.fieldNotExists(this.elasticFieldOf(DmpElasticEntity._tenantId))._toQuery(); + } + else { + try { + tenantQuery = this.or(this.fieldNotExists(this.elasticFieldOf(DmpElasticEntity._tenantId))._toQuery(), + this.equals(this.elasticFieldOf(DmpElasticEntity._tenantId), this.tenantScope.getTenant()))._toQuery(); + } catch (InvalidApplicationException e) { + throw new RuntimeException(e); + } + } + if (predicates == null) return tenantQuery; + else return this.and(tenantQuery, this.or(predicates)._toQuery()); + } else { + if (predicates != null) return this.or(predicates)._toQuery(); + } + return null; + } @Override protected Query applyAuthZ() { - if (this.authorize.contains(AuthorizationFlags.None)) return null; - if (this.authorize.contains(AuthorizationFlags.Permission) && this.authService.authorize(Permission.BrowseDmp)) return null; + + if (this.authorize.contains(AuthorizationFlags.None)) return this.applyTenant(null); + if (this.authorize.contains(AuthorizationFlags.Permission) && this.authService.authorize(Permission.BrowseDmp)) return this.applyTenant(null); UUID userId = null; boolean usePublic = this.authorize.contains(AuthorizationFlags.Public); if (this.authorize.contains(AuthorizationFlags.DmpAssociated)) userId = this.userScope.getUserIdSafe(); @@ -203,7 +230,11 @@ public class DmpElasticQuery extends ElasticQuery { query.ids(userId); predicates.add(this.nestedQuery(query).build()._toQuery()); } - return this.or(predicates)._toQuery(); + if (!predicates.isEmpty()) { + return this.applyTenant(predicates); + } else { + return this.equals(this.elasticFieldOf(DescriptionElasticEntity._id), UUID.randomUUID()); + } } @Override diff --git a/dmp-backend/core/src/main/java/eu/eudat/service/elastic/ElasticService.java b/dmp-backend/core/src/main/java/eu/eudat/service/elastic/ElasticService.java index f58965132..2d1c1648d 100644 --- a/dmp-backend/core/src/main/java/eu/eudat/service/elastic/ElasticService.java +++ b/dmp-backend/core/src/main/java/eu/eudat/service/elastic/ElasticService.java @@ -30,7 +30,7 @@ public interface ElasticService { void deleteDescriptionIndex() throws IOException; - void resetDmpIndex() throws IOException; + void resetDmpIndex() throws IOException, InvalidApplicationException; - void resetDescriptionIndex() throws IOException; + void resetDescriptionIndex() throws IOException, InvalidApplicationException; } diff --git a/dmp-backend/core/src/main/java/eu/eudat/service/elastic/ElasticServiceImpl.java b/dmp-backend/core/src/main/java/eu/eudat/service/elastic/ElasticServiceImpl.java index 667ccd73e..3936ee638 100644 --- a/dmp-backend/core/src/main/java/eu/eudat/service/elastic/ElasticServiceImpl.java +++ b/dmp-backend/core/src/main/java/eu/eudat/service/elastic/ElasticServiceImpl.java @@ -9,6 +9,7 @@ import eu.eudat.commons.enums.IsActive; import eu.eudat.data.DescriptionEntity; import eu.eudat.data.DmpEntity; import eu.eudat.data.TenantEntityManager; +import eu.eudat.data.tenant.TenantScopedBaseEntity; import eu.eudat.elastic.data.DescriptionElasticEntity; import eu.eudat.elastic.data.DmpElasticEntity; import eu.eudat.elastic.data.nested.*; @@ -29,6 +30,7 @@ import gr.cite.tools.exception.MyNotFoundException; import gr.cite.tools.fieldset.BaseFieldSet; import gr.cite.tools.logging.LoggerService; import gr.cite.tools.logging.MapLogEntry; +import org.hibernate.Session; import org.slf4j.LoggerFactory; import org.springframework.context.MessageSource; import org.springframework.context.i18n.LocaleContextHolder; @@ -133,6 +135,7 @@ public class ElasticServiceImpl implements ElasticService { private Map createDescriptionTemplatePropertyMap(){ Map propertyMap = new HashMap<>(); propertyMap.put(DescriptionElasticEntity._id, this.createElastic(FieldType.Keyword, false)); + propertyMap.put(DescriptionElasticEntity._tenantId, this.createElastic(FieldType.Keyword, false)); propertyMap.put(DescriptionElasticEntity._label, this.createElastic(FieldType.Keyword, false)); propertyMap.put(DescriptionElasticEntity._description, this.createElastic(FieldType.Text, true)); propertyMap.put(DescriptionElasticEntity._status, this.createElastic(FieldType.Short, false)); @@ -149,6 +152,7 @@ public class ElasticServiceImpl implements ElasticService { private Map createDmpTemplatePropertyMap(){ Map propertyMap = new HashMap<>(); propertyMap.put(DmpElasticEntity._id, this.createElastic(FieldType.Keyword, false)); + propertyMap.put(DmpElasticEntity._tenantId, this.createElastic(FieldType.Keyword, false)); propertyMap.put(DmpElasticEntity._label, this.createElastic(FieldType.Text, true)); propertyMap.put(DmpElasticEntity._description, this.createElastic(FieldType.Text, false)); propertyMap.put(DmpElasticEntity._status, this.createElastic(FieldType.Short, false)); @@ -356,7 +360,7 @@ public class ElasticServiceImpl implements ElasticService { } @Override - public void resetDmpIndex() throws IOException { + public void resetDmpIndex() throws IOException, InvalidApplicationException { logger.debug(new MapLogEntry("reset dmp index")); this.authorizationService.authorizeForce(Permission.ManageElastic); @@ -364,47 +368,58 @@ public class ElasticServiceImpl implements ElasticService { this.deleteDmpIndex(); this.ensureDmpIndex(); - int page = 0; - int pageSize = this.appElasticProperties.getResetBatchSize(); - List items; - do { - DmpQuery query = this.queryFactory.query(DmpQuery.class); - query.setOrder(new Ordering().addAscending(Dmp._createdAt)); - query.setPage(new Paging(page * pageSize, pageSize)); - - items = query.collect(); - if (items != null && !items.isEmpty()) { - List elasticEntities = this.builderFactory.builder(DmpElasticBuilder.class).build(items); - elasticsearchTemplate.save(elasticEntities, IndexCoordinates.of(this.appElasticProperties.getDmpIndexName())); - page++; - } - } while (items != null && !items.isEmpty()); + try { + this.entityManager.disableTenantFilters(); + int page = 0; + int pageSize = this.appElasticProperties.getResetBatchSize(); + List items; + do { + DmpQuery query = this.queryFactory.query(DmpQuery.class); + query.setOrder(new Ordering().addAscending(Dmp._createdAt)); + query.setPage(new Paging(page * pageSize, pageSize)); + + items = query.collect(); + if (items != null && !items.isEmpty()) { + List elasticEntities = this.builderFactory.builder(DmpElasticBuilder.class).build(items); + elasticsearchTemplate.save(elasticEntities, IndexCoordinates.of(this.appElasticProperties.getDmpIndexName())); + page++; + } + } while (items != null && !items.isEmpty()); + }finally { + this.entityManager.enableTenantFilters(); + } } @Override - public void resetDescriptionIndex() throws IOException { + public void resetDescriptionIndex() throws IOException, InvalidApplicationException { logger.debug(new MapLogEntry("reset description index")); this.authorizationService.authorizeForce(Permission.ManageElastic); - + if (!this.enabled()) return; this.deleteDescriptionIndex(); this.ensureDescriptionIndex(); - int page = 0; - int pageSize = this.appElasticProperties.getResetBatchSize(); - List items; - do { - DescriptionQuery query = this.queryFactory.query(DescriptionQuery.class); - query.setOrder(new Ordering().addAscending(Description._createdAt)); - query.setPage(new Paging(page * pageSize, pageSize)); + try { + this.entityManager.disableTenantFilters(); - items = query.collect(); - if (items != null && !items.isEmpty()) { - List elasticEntities = this.builderFactory.builder(DescriptionElasticBuilder.class).build(items); - elasticsearchTemplate.save(elasticEntities, IndexCoordinates.of(this.appElasticProperties.getDescriptionIndexName())); - page++; - } - } while (items != null && !items.isEmpty()); + int page = 0; + int pageSize = this.appElasticProperties.getResetBatchSize(); + List items; + do { + DescriptionQuery query = this.queryFactory.query(DescriptionQuery.class); + query.setOrder(new Ordering().addAscending(Description._createdAt)); + query.setPage(new Paging(page * pageSize, pageSize)); + + items = query.collect(); + if (items != null && !items.isEmpty()) { + List elasticEntities = this.builderFactory.builder(DescriptionElasticBuilder.class).build(items); + elasticsearchTemplate.save(elasticEntities, IndexCoordinates.of(this.appElasticProperties.getDescriptionIndexName())); + page++; + } + } while (items != null && !items.isEmpty()); + }finally { + this.entityManager.enableTenantFilters(); + } } //endregion