Tenant implementation changes

This commit is contained in:
Efstratios Giannopoulos 2024-05-24 18:32:51 +03:00
parent 480ebab1a9
commit 915d7592dc
17 changed files with 177 additions and 199 deletions

View File

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

View File

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

View File

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

View File

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

View File

@ -118,7 +118,7 @@ public class UserTouchedIntegrationEventHandlerImpl implements UserTouchedIntegr
message.setEvent(event);
}finally {
this.entityManager.enableTenantFilters();
this.entityManager.reloadTenantFilters();
}

View File

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

View File

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

View File

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

View File

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

View File

@ -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<DmpEntity> 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<DescriptionEntity> 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;
}

View File

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

View File

@ -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<ApplicationReadyEvent> {
private class CandidateInfo
{
@ -41,7 +40,7 @@ public class StorageFileCleanupTask implements Closeable, ApplicationListener<A
private Instant createdAt;
public UUID getId() {
return id;
return this.id;
}
public void setId(UUID id) {
@ -49,7 +48,7 @@ public class StorageFileCleanupTask implements Closeable, ApplicationListener<A
}
public Instant getCreatedAt() {
return createdAt;
return this.createdAt;
}
public void setCreatedAt(Instant createdAt) {
@ -77,16 +76,16 @@ public class StorageFileCleanupTask implements Closeable, ApplicationListener<A
if (this._config .getEnable() && intervalSeconds > 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<A
try {
if (item.getTenantId() != null) {
TenantEntity tenant = queryFactory.query(TenantQuery.class).ids(item.getTenantId()).first();
tenantScope.setTempTenant(entityManager, tenant.getId(), tenant.getCode());
tenantScope.setTempTenant(tenantEntityManager, tenant.getId(), tenant.getCode());
} else {
tenantScope.setTempTenant(entityManager, null, tenantScope.getDefaultTenantCode());
tenantScope.setTempTenant(tenantEntityManager, null, tenantScope.getDefaultTenantCode());
}
storageFileService.purgeSafe(fileId);
} finally {
tenantScope.removeTempTenant(entityManager);
tenantScope.removeTempTenant(tenantEntityManager);
}
}

View File

@ -163,15 +163,15 @@ public class TenantServiceImpl implements TenantService {
List<UserRoleEntity> existingItems;
List<UserCredentialEntity> 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();

View File

@ -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<UserRoleEntity> existingItems = this.queryFactory.query(UserRoleQuery.class).userIds(userId).tenantIsSet(false).roles(this.authorizationProperties.getAllowedGlobalRoles()).collect();
List<UUID> 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);
}
}

View File

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

View File

@ -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<String> 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<UserEntity> 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<String> 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<String> getRolesFromClaims() {
List<String> claimsRoles = this.claimExtractor.asStrings(currentPrincipalResolver.currentPrincipal(), ClaimNames.TenantRolesClaimName);
List<String> 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<String> 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

View File

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