diff --git a/backend/core/src/main/java/org/opencdmp/commons/scope/tenant/TenantScope.java b/backend/core/src/main/java/org/opencdmp/commons/scope/tenant/TenantScope.java index 20b9f0f10..30d0fc25e 100644 --- a/backend/core/src/main/java/org/opencdmp/commons/scope/tenant/TenantScope.java +++ b/backend/core/src/main/java/org/opencdmp/commons/scope/tenant/TenantScope.java @@ -1,8 +1,6 @@ package org.opencdmp.commons.scope.tenant; -import jakarta.persistence.EntityManager; -import org.hibernate.Session; -import org.opencdmp.data.tenant.TenantScopedBaseEntity; +import org.opencdmp.data.TenantEntityManager; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.web.context.annotation.RequestScope; @@ -62,55 +60,18 @@ public class TenantScope { return this.tenantCode.get(); } - public void setTempTenant(EntityManager entityManager, UUID tenant, String tenantCode) { + public void setTempTenant(TenantEntityManager entityManager, UUID tenant, String tenantCode) throws InvalidApplicationException { this.tenant.set(tenant); this.tenantCode.set(tenantCode); - entityManager - .unwrap(Session.class) - .disableFilter(TenantScopedBaseEntity.TENANT_FILTER); - - entityManager - .unwrap(Session.class) - .disableFilter(TenantScopedBaseEntity.DEFAULT_TENANT_FILTER); - if (this.tenant.get() != null || this.isDefaultTenant()) { - if(!this.isDefaultTenant()) { - entityManager - .unwrap(Session.class) - .enableFilter(TenantScopedBaseEntity.TENANT_FILTER) - .setParameter(TenantScopedBaseEntity.TENANT_FILTER_TENANT_PARAM, this.tenant.get().toString()); - } else { - entityManager - .unwrap(Session.class) - .enableFilter(TenantScopedBaseEntity.DEFAULT_TENANT_FILTER); - } - } + entityManager.reloadTenantFilters(); } - public void removeTempTenant(EntityManager entityManager) { + public void removeTempTenant(TenantEntityManager entityManager) throws InvalidApplicationException { this.tenant.set(this.initialTenant.get()); this.tenantCode.set(this.initialTenantCode.get()); - - entityManager - .unwrap(Session.class) - .disableFilter(TenantScopedBaseEntity.TENANT_FILTER); - - entityManager - .unwrap(Session.class) - .disableFilter(TenantScopedBaseEntity.DEFAULT_TENANT_FILTER); - if (this.initialTenant.get() != null || this.isDefaultTenant()) { - if(!this.isDefaultTenant()) { - entityManager - .unwrap(Session.class) - .enableFilter(TenantScopedBaseEntity.TENANT_FILTER) - .setParameter(TenantScopedBaseEntity.TENANT_FILTER_TENANT_PARAM, this.tenant.get().toString()); - } else { - entityManager - .unwrap(Session.class) - .enableFilter(TenantScopedBaseEntity.DEFAULT_TENANT_FILTER); - } - } + entityManager.reloadTenantFilters(); } public void setTenant(UUID tenant, String tenantCode) { diff --git a/backend/core/src/main/java/org/opencdmp/data/TenantEntityManager.java b/backend/core/src/main/java/org/opencdmp/data/TenantEntityManager.java index ed9e16ebb..1361edf14 100644 --- a/backend/core/src/main/java/org/opencdmp/data/TenantEntityManager.java +++ b/backend/core/src/main/java/org/opencdmp/data/TenantEntityManager.java @@ -91,8 +91,11 @@ public class TenantEntityManager { this.entityManager.clear(); } - public void enableTenantFilters() throws InvalidApplicationException { + public void reloadTenantFilters() throws InvalidApplicationException { + this.disableTenantFilters(); + if (!this.tenantScope.isSet()) return; + if(!this.tenantScope.isDefaultTenant()) { this.entityManager .unwrap(Session.class) @@ -105,6 +108,23 @@ public class TenantEntityManager { } } + public void loadExplictTenantFilters() throws InvalidApplicationException { + this.disableTenantFilters(); + + if (!this.tenantScope.isSet()) return; + + if(!this.tenantScope.isDefaultTenant()) { + this.entityManager + .unwrap(Session.class) + .enableFilter(TenantScopedBaseEntity.TENANT_FILTER_EXPLICT) + .setParameter(TenantScopedBaseEntity.TENANT_FILTER_TENANT_PARAM, this.tenantScope.getTenant().toString()); + } else { + this.entityManager + .unwrap(Session.class) + .enableFilter(TenantScopedBaseEntity.DEFAULT_TENANT_FILTER); + } + } + public void disableTenantFilters(){ this.entityManager .unwrap(Session.class) @@ -113,6 +133,10 @@ public class TenantEntityManager { this.entityManager .unwrap(Session.class) .disableFilter(TenantScopedBaseEntity.DEFAULT_TENANT_FILTER); + + this.entityManager + .unwrap(Session.class) + .disableFilter(TenantScopedBaseEntity.TENANT_FILTER_EXPLICT); } public EntityManager getEntityManager() { diff --git a/backend/core/src/main/java/org/opencdmp/data/tenant/TenantFilterAspect.java b/backend/core/src/main/java/org/opencdmp/data/tenant/TenantFilterAspect.java index 001440dcd..b3430ad22 100644 --- a/backend/core/src/main/java/org/opencdmp/data/tenant/TenantFilterAspect.java +++ b/backend/core/src/main/java/org/opencdmp/data/tenant/TenantFilterAspect.java @@ -1,46 +1,45 @@ -package org.opencdmp.data.tenant; - -import jakarta.persistence.EntityManager; -import org.aspectj.lang.JoinPoint; -import org.aspectj.lang.annotation.AfterReturning; -import org.aspectj.lang.annotation.Aspect; -import org.hibernate.Session; -import org.opencdmp.commons.scope.tenant.TenantScope; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - -import javax.management.InvalidApplicationException; - - -@Aspect -@Component -//@ConditionalOnMissingBean(TenantScope.class) -public class TenantFilterAspect { - - private final TenantScope tenantScope; - - @Autowired - public TenantFilterAspect( - TenantScope tenantScope - ) { - this.tenantScope = tenantScope; - } - - @AfterReturning( - pointcut = "bean(entityManagerFactory) && execution(* createEntityManager(..))", - returning = "retVal") - public void getSessionAfter(JoinPoint joinPoint, Object retVal) throws InvalidApplicationException { - if (retVal instanceof EntityManager && this.tenantScope.isSet()) { - Session session = ((EntityManager) retVal).unwrap(Session.class); - if(!this.tenantScope.isDefaultTenant()) { - session - .enableFilter(TenantScopedBaseEntity.TENANT_FILTER) - .setParameter(TenantScopedBaseEntity.TENANT_FILTER_TENANT_PARAM, this.tenantScope.getTenant().toString()); - } else { - session - .enableFilter(TenantScopedBaseEntity.DEFAULT_TENANT_FILTER); - } - } - } - -} +//package org.opencdmp.data.tenant; +// +//import jakarta.persistence.EntityManager; +//import org.aspectj.lang.JoinPoint; +//import org.aspectj.lang.annotation.AfterReturning; +//import org.aspectj.lang.annotation.Aspect; +//import org.hibernate.Session; +//import org.opencdmp.commons.scope.tenant.TenantScope; +//import org.springframework.beans.factory.annotation.Autowired; +//import org.springframework.stereotype.Component; +// +//import javax.management.InvalidApplicationException; +// +// +//@Aspect +//@Component +////@ConditionalOnMissingBean(TenantScope.class) +//public class TenantFilterAspect { +// +// private final TenantScope tenantScope; +// +// @Autowired +// public TenantFilterAspect( +// TenantScope tenantScope +// ) { +// this.tenantScope = tenantScope; +// } +// +// @AfterReturning( +// pointcut = "bean(entityManagerFactory) && execution(* createEntityManager(..))", +// returning = "retVal") +// public void getSessionAfter(JoinPoint joinPoint, Object retVal) throws InvalidApplicationException { +// if (retVal instanceof EntityManager && this.tenantScope.isSet()) { +// Session session = ((EntityManager) retVal).unwrap(Session.class); +// if(!this.tenantScope.isDefaultTenant()) { +// session +// .enableFilter(TenantScopedBaseEntity.TENANT_FILTER) +// .setParameter(TenantScopedBaseEntity.TENANT_FILTER_TENANT_PARAM, this.tenantScope.getTenant().toString()); +// } else { +// session +// .enableFilter(TenantScopedBaseEntity.DEFAULT_TENANT_FILTER); +// } +// } +// } +//} diff --git a/backend/core/src/main/java/org/opencdmp/data/tenant/TenantScopedBaseEntity.java b/backend/core/src/main/java/org/opencdmp/data/tenant/TenantScopedBaseEntity.java index 89b3b3750..2c166b17b 100644 --- a/backend/core/src/main/java/org/opencdmp/data/tenant/TenantScopedBaseEntity.java +++ b/backend/core/src/main/java/org/opencdmp/data/tenant/TenantScopedBaseEntity.java @@ -16,14 +16,17 @@ import java.util.UUID; //@Setter //@NoArgsConstructor @FilterDef(name = TenantScopedBaseEntity.TENANT_FILTER, parameters = @ParamDef(name = TenantScopedBaseEntity.TENANT_FILTER_TENANT_PARAM, type = String.class)) +@FilterDef(name = TenantScopedBaseEntity.TENANT_FILTER_EXPLICT, parameters = @ParamDef(name = TenantScopedBaseEntity.TENANT_FILTER_TENANT_PARAM, type = String.class)) @FilterDef(name = TenantScopedBaseEntity.DEFAULT_TENANT_FILTER) -@Filter(name = TenantScopedBaseEntity.DEFAULT_TENANT_FILTER, condition = "(tenant = tenant is null)") @Filter(name = TenantScopedBaseEntity.TENANT_FILTER, condition = "(tenant = (cast(:tenantId as uuid)) or tenant is null)") +@Filter(name = TenantScopedBaseEntity.TENANT_FILTER_EXPLICT, condition = "(tenant = (cast(:tenantId as uuid)))") +@Filter(name = TenantScopedBaseEntity.DEFAULT_TENANT_FILTER, condition = "(tenant = tenant is null)") @EntityListeners(TenantListener.class) public abstract class TenantScopedBaseEntity implements TenantScoped, Serializable { private static final long serialVersionUID = 1L; public static final String TENANT_FILTER = "tenantFilter"; public static final String DEFAULT_TENANT_FILTER = "defaultTenantFilter"; + public static final String TENANT_FILTER_EXPLICT = "tenantFilterExplict"; public static final String TENANT_FILTER_TENANT_PARAM = "tenantId"; @Column(name = "tenant", columnDefinition = "uuid", nullable = true) diff --git a/backend/core/src/main/java/org/opencdmp/integrationevent/outbox/usertouched/UserTouchedIntegrationEventHandlerImpl.java b/backend/core/src/main/java/org/opencdmp/integrationevent/outbox/usertouched/UserTouchedIntegrationEventHandlerImpl.java index 8396a9c16..285a38624 100644 --- a/backend/core/src/main/java/org/opencdmp/integrationevent/outbox/usertouched/UserTouchedIntegrationEventHandlerImpl.java +++ b/backend/core/src/main/java/org/opencdmp/integrationevent/outbox/usertouched/UserTouchedIntegrationEventHandlerImpl.java @@ -118,7 +118,7 @@ public class UserTouchedIntegrationEventHandlerImpl implements UserTouchedIntegr message.setEvent(event); }finally { - this.entityManager.enableTenantFilters(); + this.entityManager.reloadTenantFilters(); } diff --git a/backend/core/src/main/java/org/opencdmp/service/description/DescriptionServiceImpl.java b/backend/core/src/main/java/org/opencdmp/service/description/DescriptionServiceImpl.java index 737356898..ce3dc76a1 100644 --- a/backend/core/src/main/java/org/opencdmp/service/description/DescriptionServiceImpl.java +++ b/backend/core/src/main/java/org/opencdmp/service/description/DescriptionServiceImpl.java @@ -706,11 +706,11 @@ public class DescriptionServiceImpl implements DescriptionService { if (referenceType == null) throw new MyNotFoundException(this.messageSource.getMessage("General_ItemNotFound", new Object[]{fieldEntity.getReferenceTypeId(), ReferenceType.class.getSimpleName()}, LocaleContextHolder.getLocale())); if (referenceEntity.getSourceType().equals(ReferenceSourceType.External) && !this.tenantScope.isDefaultTenant() && referenceType.getTenantId() == null){ - this.tenantScope.setTempTenant(this.entityManager.getEntityManager(), null, this.tenantScope.getDefaultTenantCode()); + this.tenantScope.setTempTenant(this.entityManager, null, this.tenantScope.getDefaultTenantCode()); } this.entityManager.persist(referenceEntity); } finally { - this.tenantScope.removeTempTenant(this.entityManager.getEntityManager()); + this.tenantScope.removeTempTenant(this.entityManager); } } } diff --git a/backend/core/src/main/java/org/opencdmp/service/descriptiontemplate/DescriptionTemplateServiceImpl.java b/backend/core/src/main/java/org/opencdmp/service/descriptiontemplate/DescriptionTemplateServiceImpl.java index db4a5d64f..0ab3bcdbb 100644 --- a/backend/core/src/main/java/org/opencdmp/service/descriptiontemplate/DescriptionTemplateServiceImpl.java +++ b/backend/core/src/main/java/org/opencdmp/service/descriptiontemplate/DescriptionTemplateServiceImpl.java @@ -471,11 +471,11 @@ public class DescriptionTemplateServiceImpl implements DescriptionTemplateServic if (referenceType == null) throw new MyNotFoundException(this.messageSource.getMessage("General_ItemNotFound", new Object[]{referenceTypeDataEntity.getReferenceTypeId(), ReferenceType.class.getSimpleName()}, LocaleContextHolder.getLocale())); if (data.getSourceType().equals(ReferenceSourceType.External) && !this.tenantScope.isDefaultTenant() && referenceType.getTenantId() == null){ - this.tenantScope.setTempTenant(this.entityManager.getEntityManager(), null, this.tenantScope.getDefaultTenantCode()); + this.tenantScope.setTempTenant(this.entityManager, null, this.tenantScope.getDefaultTenantCode()); } this.entityManager.persist(data); } finally { - this.tenantScope.removeTempTenant(this.entityManager.getEntityManager()); + this.tenantScope.removeTempTenant(this.entityManager); } } } diff --git a/backend/core/src/main/java/org/opencdmp/service/dmp/DmpServiceImpl.java b/backend/core/src/main/java/org/opencdmp/service/dmp/DmpServiceImpl.java index 243fad2bb..ee098e721 100644 --- a/backend/core/src/main/java/org/opencdmp/service/dmp/DmpServiceImpl.java +++ b/backend/core/src/main/java/org/opencdmp/service/dmp/DmpServiceImpl.java @@ -961,11 +961,11 @@ public class DmpServiceImpl implements DmpService { if (referenceType == null) throw new MyNotFoundException(this.messageSource.getMessage("General_ItemNotFound", new Object[]{fieldEntity.getReferenceTypeId(), ReferenceType.class.getSimpleName()}, LocaleContextHolder.getLocale())); if (referenceEntity.getSourceType().equals(ReferenceSourceType.External) && !this.tenantScope.isDefaultTenant() && referenceType.getTenantId() == null){ - this.tenantScope.setTempTenant(this.entityManager.getEntityManager(), null, this.tenantScope.getDefaultTenantCode()); + this.tenantScope.setTempTenant(this.entityManager, null, this.tenantScope.getDefaultTenantCode()); } this.entityManager.persist(referenceEntity); } finally { - this.tenantScope.removeTempTenant(this.entityManager.getEntityManager()); + this.tenantScope.removeTempTenant(this.entityManager); } } } diff --git a/backend/core/src/main/java/org/opencdmp/service/elastic/ElasticServiceImpl.java b/backend/core/src/main/java/org/opencdmp/service/elastic/ElasticServiceImpl.java index 5813a3c48..f270c9a7b 100644 --- a/backend/core/src/main/java/org/opencdmp/service/elastic/ElasticServiceImpl.java +++ b/backend/core/src/main/java/org/opencdmp/service/elastic/ElasticServiceImpl.java @@ -386,7 +386,7 @@ public class ElasticServiceImpl implements ElasticService { } } while (items != null && !items.isEmpty()); }finally { - this.entityManager.enableTenantFilters(); + this.entityManager.reloadTenantFilters(); } } @@ -418,7 +418,7 @@ public class ElasticServiceImpl implements ElasticService { } } while (items != null && !items.isEmpty()); }finally { - this.entityManager.enableTenantFilters(); + this.entityManager.reloadTenantFilters(); } } diff --git a/backend/core/src/main/java/org/opencdmp/service/maintenance/MaintenanceServiceImpl.java b/backend/core/src/main/java/org/opencdmp/service/maintenance/MaintenanceServiceImpl.java index 0934f5593..5ddaf7cdb 100644 --- a/backend/core/src/main/java/org/opencdmp/service/maintenance/MaintenanceServiceImpl.java +++ b/backend/core/src/main/java/org/opencdmp/service/maintenance/MaintenanceServiceImpl.java @@ -80,10 +80,10 @@ public class MaintenanceServiceImpl implements MaintenanceService { activeUsers = userQuery.collectAs(new BaseFieldSet().ensure(User._id)); userQuery.isActive(IsActive.Inactive); inactiveUsers = userQuery.collectAs(new BaseFieldSet().ensure(User._id)); - this.entityManager.enableTenantFilters(); + this.entityManager.reloadTenantFilters(); } finally { - this.entityManager.enableTenantFilters(); + this.entityManager.reloadTenantFilters(); } for(UserEntity user : activeUsers) this.userTouchedIntegrationEventHandler.handle(user.getId()); @@ -108,7 +108,7 @@ public class MaintenanceServiceImpl implements MaintenanceService { inactiveTenants = tenantQuery.collectAs(new BaseFieldSet().ensure(Tenant._id).ensure(Tenant._code)); } finally { - this.entityManager.enableTenantFilters(); + this.entityManager.reloadTenantFilters(); } for (TenantEntity tenant : activeTenants) { TenantTouchedIntegrationEvent event = new TenantTouchedIntegrationEvent(); @@ -140,14 +140,14 @@ public class MaintenanceServiceImpl implements MaintenanceService { private void sendTenantDmpTouchEvents(UUID tenantId, String tenantCode) throws InvalidApplicationException { try { - this.tenantScope.setTempTenant(this.entityManager.getEntityManager(), tenantId, tenantCode); + this.tenantScope.setTempTenant(this.entityManager, tenantId, tenantCode); List items = this.queryFactory.query(DmpQuery.class).disableTracking().collectAs(new BaseFieldSet().ensure(Dmp._id).ensure(Dmp._isActive)); for (DmpEntity item : items) { if (item.getIsActive().equals(IsActive.Active)) this.annotationEntityTouchedIntegrationEventHandler.handleDmp(item.getId()); else this.annotationEntityRemovalIntegrationEventHandler.handleDmp(item.getId()); } } finally { - this.tenantScope.removeTempTenant(this.entityManager.getEntityManager()); + this.tenantScope.removeTempTenant(this.entityManager); } } @@ -170,14 +170,14 @@ public class MaintenanceServiceImpl implements MaintenanceService { private void sendTenantDescriptionTouchEvents(UUID tenantId, String tenantCode) throws InvalidApplicationException { try { - this.tenantScope.setTempTenant(this.entityManager.getEntityManager(), tenantId, tenantCode); + this.tenantScope.setTempTenant(this.entityManager, tenantId, tenantCode); List items = this.queryFactory.query(DescriptionQuery.class).disableTracking().collectAs(new BaseFieldSet().ensure(Description._id).ensure(Description._isActive)); for (DescriptionEntity item : items) { if (item.getIsActive().equals(IsActive.Active)) this.annotationEntityTouchedIntegrationEventHandler.handleDescription(item.getId()); else this.annotationEntityRemovalIntegrationEventHandler.handleDescription(item.getId()); } } finally { - this.tenantScope.removeTempTenant(this.entityManager.getEntityManager()); + this.tenantScope.removeTempTenant(this.entityManager); } } @@ -187,7 +187,7 @@ public class MaintenanceServiceImpl implements MaintenanceService { this.entityManager.disableTenantFilters(); tenants = this.queryFactory.query(TenantQuery.class).disableTracking().isActive(IsActive.Active).collectAs(new BaseFieldSet().ensure(Tenant._id).ensure(Tenant._code)); } finally { - this.entityManager.enableTenantFilters(); + this.entityManager.reloadTenantFilters(); } return tenants; } diff --git a/backend/core/src/main/java/org/opencdmp/service/metrics/MetricsServiceImpl.java b/backend/core/src/main/java/org/opencdmp/service/metrics/MetricsServiceImpl.java index 0dcc91475..c658c5a2c 100644 --- a/backend/core/src/main/java/org/opencdmp/service/metrics/MetricsServiceImpl.java +++ b/backend/core/src/main/java/org/opencdmp/service/metrics/MetricsServiceImpl.java @@ -1,6 +1,5 @@ package org.opencdmp.service.metrics; -import gr.cite.commons.web.keycloak.api.configuration.KeycloakClientProperties; import gr.cite.tools.data.query.QueryFactory; import gr.cite.tools.fieldset.BaseFieldSet; import gr.cite.tools.logging.LoggerService; @@ -34,7 +33,6 @@ public class MetricsServiceImpl implements MetricsService { private final UpdateMetricsTaskProperties _config; - private final KeycloakClientProperties _keycloakConfig; private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(MetricsServiceImpl.class)); @@ -43,14 +41,12 @@ public class MetricsServiceImpl implements MetricsService { QueryFactory queryFactory, TenantEntityManager entityManager, MyKeycloakAdminRestApi keycloakAdminRestApi, - UpdateMetricsTaskProperties config, - KeycloakClientProperties keycloakConfig) { + UpdateMetricsTaskProperties config) { this.registry = registry; this.queryFactory = queryFactory; this.entityManager = entityManager; this.keycloakAdminRestApi = keycloakAdminRestApi; this._config = config; - this._keycloakConfig = keycloakConfig; } @Override @@ -288,7 +284,7 @@ public class MetricsServiceImpl implements MetricsService { } catch (Exception e) { logger.error(e.getMessage(), e); } finally { - this.entityManager.enableTenantFilters(); + this.entityManager.reloadTenantFilters(); } } diff --git a/backend/core/src/main/java/org/opencdmp/service/storage/StorageFileCleanupTask.java b/backend/core/src/main/java/org/opencdmp/service/storage/StorageFileCleanupTask.java index 07169a76d..5dc76cde6 100644 --- a/backend/core/src/main/java/org/opencdmp/service/storage/StorageFileCleanupTask.java +++ b/backend/core/src/main/java/org/opencdmp/service/storage/StorageFileCleanupTask.java @@ -1,5 +1,12 @@ package org.opencdmp.service.storage; +import gr.cite.tools.data.query.Ordering; +import gr.cite.tools.data.query.QueryFactory; +import gr.cite.tools.logging.LoggerService; +import jakarta.persistence.EntityManager; +import jakarta.persistence.EntityManagerFactory; +import jakarta.persistence.EntityTransaction; +import jakarta.persistence.OptimisticLockException; import org.opencdmp.commons.fake.FakeRequestScope; import org.opencdmp.commons.scope.tenant.TenantScope; import org.opencdmp.data.StorageFileEntity; @@ -8,13 +15,6 @@ import org.opencdmp.data.TenantEntityManager; import org.opencdmp.model.StorageFile; import org.opencdmp.query.StorageFileQuery; import org.opencdmp.query.TenantQuery; -import gr.cite.tools.data.query.Ordering; -import gr.cite.tools.data.query.QueryFactory; -import gr.cite.tools.logging.LoggerService; -import jakarta.persistence.EntityManager; -import jakarta.persistence.EntityManagerFactory; -import jakarta.persistence.EntityTransaction; -import jakarta.persistence.OptimisticLockException; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.boot.context.event.ApplicationReadyEvent; @@ -22,7 +22,6 @@ import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationListener; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; import java.io.Closeable; import java.io.IOException; @@ -33,7 +32,7 @@ import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; @Service -@Scope(value = ConfigurableBeanFactory.SCOPE_SINGLETON) +@Scope(ConfigurableBeanFactory.SCOPE_SINGLETON) public class StorageFileCleanupTask implements Closeable, ApplicationListener { private class CandidateInfo { @@ -41,7 +40,7 @@ public class StorageFileCleanupTask implements Closeable, ApplicationListener 0) { logger.info("File clean up run in {} seconds", intervalSeconds); - scheduler = Executors.newScheduledThreadPool(1); - scheduler.scheduleAtFixedRate(this::process, 10, intervalSeconds, TimeUnit.SECONDS); + this.scheduler = Executors.newScheduledThreadPool(1); + this.scheduler.scheduleAtFixedRate(this::process, 10, intervalSeconds, TimeUnit.SECONDS); } else { - scheduler = null; + this.scheduler = null; } } @Override public void close() throws IOException { - if (scheduler != null) this.scheduler.close(); + if (this.scheduler != null) this.scheduler.close(); } protected void process() { @@ -137,13 +136,13 @@ public class StorageFileCleanupTask implements Closeable, ApplicationListener existingItems; List userCredentialEntities; try { - this.tenantScope.setTempTenant(this.entityManager.getEntityManager(), null, this.tenantScope.getDefaultTenantCode()); + this.tenantScope.setTempTenant(this.entityManager, null, this.tenantScope.getDefaultTenantCode()); existingItems = this.queryFactory.query(UserRoleQuery.class).disableTracking().tenantIsSet(false).roles(this.authorizationProperties.getGlobalAdminRole()).collect(); userCredentialEntities = this.queryFactory.query(UserCredentialQuery.class).disableTracking().userIds(existingItems.stream().map(UserRoleEntity::getUserId).distinct().toList()).collect(); } finally { - this.tenantScope.removeTempTenant(this.entityManager.getEntityManager()); + this.tenantScope.removeTempTenant(this.entityManager); } try { - this.tenantScope.setTempTenant(this.entityManager.getEntityManager(), tenant.getId(), tenant.getCode()); + this.tenantScope.setTempTenant(this.entityManager, tenant.getId(), tenant.getCode()); for (UUID userId : existingItems.stream().map(UserRoleEntity::getUserId).distinct().toList()) { UserCredentialEntity userCredential = userCredentialEntities.stream().filter(x-> !this.conventionService.isNullOrEmpty(x.getExternalId()) && x.getUserId().equals(userId)).findFirst().orElse(null); if (userCredential == null) continue; @@ -184,7 +184,7 @@ public class TenantServiceImpl implements TenantService { this.keycloakService.addUserToTenantRoleGroup(userCredential.getExternalId(), this.tenantScope.getTenantCode(), this.authorizationProperties.getTenantAdminRole()); } } finally { - this.tenantScope.removeTempTenant(this.entityManager.getEntityManager()); + this.tenantScope.removeTempTenant(this.entityManager); } this.entityManager.flush(); diff --git a/backend/core/src/main/java/org/opencdmp/service/user/UserServiceImpl.java b/backend/core/src/main/java/org/opencdmp/service/user/UserServiceImpl.java index 92a860e7a..1426ac273 100644 --- a/backend/core/src/main/java/org/opencdmp/service/user/UserServiceImpl.java +++ b/backend/core/src/main/java/org/opencdmp/service/user/UserServiceImpl.java @@ -231,11 +231,11 @@ public class UserServiceImpl implements UserService { throw new MyNotFoundException(this.messageSource.getMessage("General_ItemNotFound", new Object[]{model.getTypeId(), ReferenceType.class.getSimpleName()}, LocaleContextHolder.getLocale())); if (referenceEntity.getSourceType().equals(ReferenceSourceType.External) && !this.tenantScope.isDefaultTenant() && referenceType.getTenantId() == null) { - this.tenantScope.setTempTenant(this.entityManager.getEntityManager(), null, this.tenantScope.getDefaultTenantCode()); + this.tenantScope.setTempTenant(this.entityManager, null, this.tenantScope.getDefaultTenantCode()); } this.entityManager.persist(referenceEntity); } finally { - this.tenantScope.removeTempTenant(this.entityManager.getEntityManager()); + this.tenantScope.removeTempTenant(this.entityManager); } } } @@ -340,7 +340,7 @@ public class UserServiceImpl implements UserService { private void applyGlobalRoles(UUID userId, String subjectId, UserRolePatchPersist model) throws InvalidApplicationException { try { - this.tenantScope.setTempTenant(this.entityManager.getEntityManager(), null, this.tenantScope.getDefaultTenantCode()); + this.tenantScope.setTempTenant(this.entityManager, null, this.tenantScope.getDefaultTenantCode()); List existingItems = this.queryFactory.query(UserRoleQuery.class).userIds(userId).tenantIsSet(false).roles(this.authorizationProperties.getAllowedGlobalRoles()).collect(); List foundIds = new ArrayList<>(); @@ -364,7 +364,7 @@ public class UserServiceImpl implements UserService { this.entityManager.flush(); } finally { - this.tenantScope.removeTempTenant(this.entityManager.getEntityManager()); + this.tenantScope.removeTempTenant(this.entityManager); } } diff --git a/backend/web/src/main/java/org/opencdmp/configurations/WebMVCConfiguration.java b/backend/web/src/main/java/org/opencdmp/configurations/WebMVCConfiguration.java index e5a38d6a7..a301b259f 100644 --- a/backend/web/src/main/java/org/opencdmp/configurations/WebMVCConfiguration.java +++ b/backend/web/src/main/java/org/opencdmp/configurations/WebMVCConfiguration.java @@ -39,9 +39,13 @@ public class WebMVCConfiguration implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { int order = 1; - registry.addWebRequestInterceptor(scopeHeaderInterceptor).order(order++); - registry.addWebRequestInterceptor(scopeClaimInterceptor).order(order++); - registry.addWebRequestInterceptor(userInterceptor).order(order++); - registry.addWebRequestInterceptor(tenantInterceptor).order(order++); + registry.addWebRequestInterceptor(this.scopeHeaderInterceptor).order(order); + order++; + registry.addWebRequestInterceptor(this.scopeClaimInterceptor).order(order); + order++; + registry.addWebRequestInterceptor(this.userInterceptor).order(order); + order++; + registry.addWebRequestInterceptor(this.tenantInterceptor).order(order); + order++; } } diff --git a/backend/web/src/main/java/org/opencdmp/interceptors/tenant/TenantInterceptor.java b/backend/web/src/main/java/org/opencdmp/interceptors/tenant/TenantInterceptor.java index 9933c72db..c6a45ba0f 100644 --- a/backend/web/src/main/java/org/opencdmp/interceptors/tenant/TenantInterceptor.java +++ b/backend/web/src/main/java/org/opencdmp/interceptors/tenant/TenantInterceptor.java @@ -1,22 +1,6 @@ package org.opencdmp.interceptors.tenant; -import org.opencdmp.authorization.AuthorizationProperties; -import org.opencdmp.authorization.ClaimNames; -import org.opencdmp.authorization.Permission; -import org.opencdmp.commons.enums.IsActive; -import org.opencdmp.commons.lock.LockByKeyManager; -import org.opencdmp.commons.scope.tenant.TenantScope; -import org.opencdmp.commons.scope.user.UserScope; -import org.opencdmp.convention.ConventionService; -import org.opencdmp.data.TenantUserEntity; -import org.opencdmp.data.UserEntity; -import org.opencdmp.data.UserRoleEntity; -import org.opencdmp.data.tenant.TenantScopedBaseEntity; -import org.opencdmp.errorcode.ErrorThesaurusProperties; -import org.opencdmp.integrationevent.outbox.usertouched.UserTouchedIntegrationEventHandler; -import org.opencdmp.query.utils.BuildSubQueryInput; -import org.opencdmp.query.utils.QueryUtilsService; 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; @@ -27,8 +11,23 @@ import jakarta.persistence.PersistenceContext; import jakarta.persistence.criteria.CriteriaBuilder; import jakarta.persistence.criteria.CriteriaQuery; import jakarta.persistence.criteria.Root; -import org.hibernate.Session; import org.jetbrains.annotations.NotNull; +import org.opencdmp.authorization.AuthorizationProperties; +import org.opencdmp.authorization.ClaimNames; +import org.opencdmp.authorization.Permission; +import org.opencdmp.commons.enums.IsActive; +import org.opencdmp.commons.lock.LockByKeyManager; +import org.opencdmp.commons.scope.tenant.TenantScope; +import org.opencdmp.commons.scope.user.UserScope; +import org.opencdmp.convention.ConventionService; +import org.opencdmp.data.TenantEntityManager; +import org.opencdmp.data.TenantUserEntity; +import org.opencdmp.data.UserEntity; +import org.opencdmp.data.UserRoleEntity; +import org.opencdmp.errorcode.ErrorThesaurusProperties; +import org.opencdmp.integrationevent.outbox.usertouched.UserTouchedIntegrationEventHandler; +import org.opencdmp.query.utils.BuildSubQueryInput; +import org.opencdmp.query.utils.QueryUtilsService; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; @@ -70,6 +69,8 @@ public class TenantInterceptor implements WebRequestInterceptor { private final UserTouchedIntegrationEventHandler userTouchedIntegrationEventHandler; private final AuthorizationProperties authorizationProperties; private final UserTenantRolesCacheService userTenantRolesCacheService; + public final TenantEntityManager tenantEntityManager; + @PersistenceContext public EntityManager entityManager; @@ -83,7 +84,7 @@ public class TenantInterceptor implements WebRequestInterceptor { TenantScopeProperties tenantScopeProperties, UserAllowedTenantCacheService userAllowedTenantCacheService, PlatformTransactionManager transactionManager, - ErrorThesaurusProperties errors, QueryUtilsService queryUtilsService, LockByKeyManager lockByKeyManager, ConventionService conventionService, UserTouchedIntegrationEventHandler userTouchedIntegrationEventHandler, AuthorizationProperties authorizationProperties, UserTenantRolesCacheService userTenantRolesCacheService) { + ErrorThesaurusProperties errors, QueryUtilsService queryUtilsService, LockByKeyManager lockByKeyManager, ConventionService conventionService, UserTouchedIntegrationEventHandler userTouchedIntegrationEventHandler, AuthorizationProperties authorizationProperties, UserTenantRolesCacheService userTenantRolesCacheService, TenantEntityManager tenantEntityManager) { this.tenantScope = tenantScope; this.userScope = userScope; this.currentPrincipalResolver = currentPrincipalResolver; @@ -99,6 +100,7 @@ public class TenantInterceptor implements WebRequestInterceptor { this.userTouchedIntegrationEventHandler = userTouchedIntegrationEventHandler; this.authorizationProperties = authorizationProperties; this.userTenantRolesCacheService = userTenantRolesCacheService; + this.tenantEntityManager = tenantEntityManager; } @Override @@ -107,9 +109,9 @@ public class TenantInterceptor implements WebRequestInterceptor { if (!this.tenantScope.isMultitenant()) return; boolean isAllowedNoTenant = this.applicationContext.getBean(AuthorizationService.class).authorize(Permission.AllowNoTenant); - if (tenantScope.isSet() && this.entityManager != null) { + if (this.tenantScope.isSet() && this.entityManager != null) { List currentPrincipalTenantCodes = this.claimExtractor.asStrings(this.currentPrincipalResolver.currentPrincipal(), ClaimNames.TenantCodesClaimName); - if ((currentPrincipalTenantCodes == null || !currentPrincipalTenantCodes.contains(tenantScope.getTenantCode())) && !isAllowedNoTenant) { + if ((currentPrincipalTenantCodes == null || !currentPrincipalTenantCodes.contains(this.tenantScope.getTenantCode())) && !isAllowedNoTenant) { logger.warn("tenant not allowed {}", this.tenantScope.getTenant()); throw new MyForbiddenException(this.errors.getTenantNotAllowed().getCode(), this.errors.getTenantNotAllowed().getMessage()); } @@ -128,23 +130,14 @@ public class TenantInterceptor implements WebRequestInterceptor { } if (isUserAllowedTenant) { - 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); - } + this.tenantEntityManager.reloadTenantFilters(); 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); + this.tenantScope.setTenant(null, null); } else { logger.warn("tenant not allowed {}", this.tenantScope.getTenant()); throw new MyForbiddenException(this.errors.getTenantNotAllowed().getCode(), this.errors.getTenantNotAllowed().getMessage()); @@ -173,9 +166,9 @@ public class TenantInterceptor implements WebRequestInterceptor { } private boolean isUserAllowedTenant() throws InvalidApplicationException, InterruptedException { - if (userScope.isSet()) { + if (this.userScope.isSet()) { boolean usedResource = false; - String lockId = userScope.getUserId().toString().toLowerCase(Locale.ROOT); + String lockId = this.userScope.getUserId().toString().toLowerCase(Locale.ROOT); try { if (this.tenantScopeProperties.getAutoCreateTenantUser()) usedResource = this.lockByKeyManager.tryLock(lockId, 5000, TimeUnit.MILLISECONDS); @@ -184,7 +177,7 @@ public class TenantInterceptor implements WebRequestInterceptor { Root root = query.from(UserEntity.class); query.where(criteriaBuilder.and( criteriaBuilder.equal(root.get(UserEntity._isActive), IsActive.Active), - criteriaBuilder.in(root.get(UserEntity._id)).value(queryUtilsService.buildSubQuery(new BuildSubQueryInput<>(new BuildSubQueryInput.Builder<>(TenantUserEntity.class, UUID.class) + criteriaBuilder.in(root.get(UserEntity._id)).value(this.queryUtilsService.buildSubQuery(new BuildSubQueryInput<>(new BuildSubQueryInput.Builder<>(TenantUserEntity.class, UUID.class) .query(query) .criteriaBuilder(criteriaBuilder) .keyPathFunc((subQueryRoot) -> subQueryRoot.get(TenantUserEntity._userId)) @@ -226,7 +219,7 @@ public class TenantInterceptor implements WebRequestInterceptor { user.setUpdatedAt(Instant.now()); user.setIsActive(IsActive.Active); user.setTenantId(this.tenantScope.getTenant()); - user.setUserId(userScope.getUserId()); + user.setUserId(this.userScope.getUserId()); DefaultTransactionDefinition definition = new DefaultTransactionDefinition(); @@ -235,12 +228,12 @@ public class TenantInterceptor implements WebRequestInterceptor { definition.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED); TransactionStatus status = null; try { - status = transactionManager.getTransaction(definition); + status = this.transactionManager.getTransaction(definition); this.entityManager.persist(user); this.entityManager.flush(); - transactionManager.commit(status); + this.transactionManager.commit(status); } catch (Exception ex) { - if (status != null) transactionManager.rollback(status); + if (status != null) this.transactionManager.rollback(status); throw ex; } this.userTouchedIntegrationEventHandler.handle(this.userScope.getUserId()); @@ -251,7 +244,7 @@ public class TenantInterceptor implements WebRequestInterceptor { boolean usedResource = false; - String lockId = userScope.getUserId().toString().toLowerCase(Locale.ROOT); + String lockId = this.userScope.getUserId().toString().toLowerCase(Locale.ROOT); boolean hasChanges = false; try { usedResource = this.lockByKeyManager.tryLock(lockId, 5000, TimeUnit.MILLISECONDS); @@ -262,7 +255,7 @@ public class TenantInterceptor implements WebRequestInterceptor { definition.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED); TransactionStatus status = null; try { - status = transactionManager.getTransaction(definition); + status = this.transactionManager.getTransaction(definition); 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; @@ -278,9 +271,9 @@ public class TenantInterceptor implements WebRequestInterceptor { } this.entityManager.flush(); - transactionManager.commit(status); + this.transactionManager.commit(status); } catch (Exception ex) { - if (status != null) transactionManager.rollback(status); + if (status != null) this.transactionManager.rollback(status); throw ex; } } finally { @@ -292,7 +285,7 @@ public class TenantInterceptor implements WebRequestInterceptor { } private List getRolesFromClaims() { - List claimsRoles = this.claimExtractor.asStrings(currentPrincipalResolver.currentPrincipal(), ClaimNames.TenantRolesClaimName); + List claimsRoles = this.claimExtractor.asStrings(this.currentPrincipalResolver.currentPrincipal(), ClaimNames.TenantRolesClaimName); if (claimsRoles == null) claimsRoles = new ArrayList<>(); claimsRoles = claimsRoles.stream().filter(x -> x != null && !x.isBlank() && (this.conventionService.isListNullOrEmpty(this.authorizationProperties.getAllowedTenantRoles()) || this.authorizationProperties.getAllowedTenantRoles().contains(x))).distinct().toList(); return claimsRoles; @@ -307,7 +300,7 @@ public class TenantInterceptor implements WebRequestInterceptor { for (String item : this.authorizationProperties.getAllowedTenantRoles()) inRolesClause.value(item); query.where(criteriaBuilder.and( - criteriaBuilder.equal(root.get(UserRoleEntity._userId), userScope.getUserId()), + criteriaBuilder.equal(root.get(UserRoleEntity._userId), this.userScope.getUserId()), this.conventionService.isListNullOrEmpty(this.authorizationProperties.getAllowedTenantRoles()) ? criteriaBuilder.isNotNull(root.get(UserRoleEntity._role)) : inRolesClause, this.tenantScope.isDefaultTenant() ? criteriaBuilder.isNull(root.get(UserRoleEntity._tenantId)) : criteriaBuilder.equal(root.get(UserRoleEntity._tenantId), this.tenantScope.getTenant()) )).multiselect(root.get(UserRoleEntity._role).alias(UserRoleEntity._role)); @@ -336,7 +329,7 @@ public class TenantInterceptor implements WebRequestInterceptor { CriteriaBuilder.In inRolesClause = criteriaBuilder.in(root.get(UserRoleEntity._role)); for (String item : this.authorizationProperties.getAllowedTenantRoles()) inRolesClause.value(item); query.where(criteriaBuilder.and( - criteriaBuilder.equal(root.get(UserRoleEntity._userId), userScope.getUserId()), + criteriaBuilder.equal(root.get(UserRoleEntity._userId), this.userScope.getUserId()), this.conventionService.isListNullOrEmpty(this.authorizationProperties.getAllowedTenantRoles()) ? criteriaBuilder.isNotNull(root.get(UserRoleEntity._role)) : inRolesClause, this.tenantScope.isDefaultTenant() ? criteriaBuilder.isNull(root.get(UserRoleEntity._tenantId)) : criteriaBuilder.equal(root.get(UserRoleEntity._tenantId), this.tenantScope.getTenant()) )); @@ -361,7 +354,7 @@ public class TenantInterceptor implements WebRequestInterceptor { private UserRoleEntity buildRole(String role) throws InvalidApplicationException { UserRoleEntity data = new UserRoleEntity(); data.setId(UUID.randomUUID()); - data.setUserId( userScope.getUserId()); + data.setUserId(this.userScope.getUserId()); data.setRole(role); if (this.tenantScope.isDefaultTenant()) data.setTenantId(this.tenantScope.getTenant()); data.setCreatedAt(Instant.now()); @@ -371,6 +364,7 @@ public class TenantInterceptor implements WebRequestInterceptor { @Override public void postHandle(@NonNull WebRequest request, ModelMap model) { this.tenantScope.setTenant(null, null); + this.tenantEntityManager.disableTenantFilters(); } @Override diff --git a/backend/web/src/main/java/org/opencdmp/interceptors/tenant/TenantScopeClaimInterceptor.java b/backend/web/src/main/java/org/opencdmp/interceptors/tenant/TenantScopeClaimInterceptor.java index 3729e4dd1..5c36f73c3 100644 --- a/backend/web/src/main/java/org/opencdmp/interceptors/tenant/TenantScopeClaimInterceptor.java +++ b/backend/web/src/main/java/org/opencdmp/interceptors/tenant/TenantScopeClaimInterceptor.java @@ -1,13 +1,6 @@ package org.opencdmp.interceptors.tenant; -import org.opencdmp.authorization.ClaimNames; -import org.opencdmp.commons.enums.IsActive; -import org.opencdmp.commons.scope.tenant.TenantScope; -import org.opencdmp.convention.ConventionService; -import org.opencdmp.data.TenantEntity; -import org.opencdmp.data.UserEntity; -import org.opencdmp.errorcode.ErrorThesaurusProperties; import gr.cite.commons.web.oidc.principal.CurrentPrincipalResolver; import gr.cite.commons.web.oidc.principal.MyPrincipal; import gr.cite.commons.web.oidc.principal.extractor.ClaimExtractor; @@ -16,11 +9,16 @@ import gr.cite.tools.exception.MyForbiddenException; import gr.cite.tools.logging.LoggerService; import jakarta.persistence.EntityManager; import jakarta.persistence.PersistenceContext; -import jakarta.persistence.Tuple; import jakarta.persistence.criteria.CriteriaBuilder; import jakarta.persistence.criteria.CriteriaQuery; import jakarta.persistence.criteria.Root; import org.jetbrains.annotations.NotNull; +import org.opencdmp.authorization.ClaimNames; +import org.opencdmp.commons.enums.IsActive; +import org.opencdmp.commons.scope.tenant.TenantScope; +import org.opencdmp.convention.ConventionService; +import org.opencdmp.data.TenantEntity; +import org.opencdmp.errorcode.ErrorThesaurusProperties; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.lang.NonNull;