From cae4003af542d7bbb1159fabac5bba6b29f9232f Mon Sep 17 00:00:00 2001 From: sgiannopoulos Date: Fri, 23 Aug 2024 12:33:58 +0300 Subject: [PATCH] add supportExpansionTenant --- .../tenant/MultitenancyConfiguration.java | 10 +++++++ .../scope/tenant/MultitenancyProperties.java | 14 +++++++++ .../commons/scope/tenant/TenantScope.java | 18 ++++++----- .../opencdmp/data/TenantEntityManager.java | 20 ++++++++----- .../opencdmp/data/tenant/TenantListener.java | 2 +- ...ityCreatedIntegrationEventHandlerImpl.java | 17 +++++++---- ...ityChangedIntegrationEventHandlerImpl.java | 17 +++++++---- .../service/tenant/TenantServiceImpl.java | 30 +++++++++++-------- .../tenant/TenantInterceptor.java | 2 +- .../tenant/TenantScopeClaimInterceptor.java | 4 +-- .../tenant/TenantScopeHeaderInterceptor.java | 7 +++-- .../main/resources/config/tenant-devel.yml | 1 + 12 files changed, 97 insertions(+), 45 deletions(-) diff --git a/backend/core/src/main/java/org/opencdmp/commons/scope/tenant/MultitenancyConfiguration.java b/backend/core/src/main/java/org/opencdmp/commons/scope/tenant/MultitenancyConfiguration.java index dd7c17666..190d0a8db 100644 --- a/backend/core/src/main/java/org/opencdmp/commons/scope/tenant/MultitenancyConfiguration.java +++ b/backend/core/src/main/java/org/opencdmp/commons/scope/tenant/MultitenancyConfiguration.java @@ -6,4 +6,14 @@ import org.springframework.context.annotation.Configuration; @Configuration @EnableConfigurationProperties(MultitenancyProperties.class) public class MultitenancyConfiguration { + private final MultitenancyProperties config; + + + public MultitenancyConfiguration(MultitenancyProperties config) { + this.config = config; + } + + public MultitenancyProperties getConfig() { + return this.config; + } } diff --git a/backend/core/src/main/java/org/opencdmp/commons/scope/tenant/MultitenancyProperties.java b/backend/core/src/main/java/org/opencdmp/commons/scope/tenant/MultitenancyProperties.java index fd5530df0..2a89fe816 100644 --- a/backend/core/src/main/java/org/opencdmp/commons/scope/tenant/MultitenancyProperties.java +++ b/backend/core/src/main/java/org/opencdmp/commons/scope/tenant/MultitenancyProperties.java @@ -5,6 +5,7 @@ import org.springframework.boot.context.properties.ConfigurationProperties; @ConfigurationProperties(prefix = "tenant.multitenancy") public class MultitenancyProperties { private boolean isMultitenant; + private boolean supportExpansionTenant; private String defaultTenantCode; public boolean isMultitenant() { @@ -15,6 +16,10 @@ public class MultitenancyProperties { this.isMultitenant = multitenant; } + public void setMultitenant(boolean multitenant) { + this.isMultitenant = multitenant; + } + public String getDefaultTenantCode() { return this.defaultTenantCode; } @@ -22,4 +27,13 @@ public class MultitenancyProperties { public void setDefaultTenantCode(String defaultTenantCode) { this.defaultTenantCode = defaultTenantCode; } + + public boolean getSupportExpansionTenant() { + return this.supportExpansionTenant; + } + + public void setSupportExpansionTenant(boolean supportExpansionTenant) { + this.supportExpansionTenant = supportExpansionTenant; + } } + 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 30d0fc25e..6cc559cfd 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 @@ -13,23 +13,27 @@ import java.util.concurrent.atomic.AtomicReference; @RequestScope public class TenantScope { public static final String TenantReplaceParameter = "::TenantCode::"; - private final MultitenancyProperties multitenancy; + private final MultitenancyConfiguration multitenancyConfiguration; private final AtomicReference tenant = new AtomicReference<>(); private final AtomicReference tenantCode = new AtomicReference<>(); private final AtomicReference initialTenant = new AtomicReference<>(); private final AtomicReference initialTenantCode = new AtomicReference<>(); @Autowired - public TenantScope(MultitenancyProperties multitenancy) { - this.multitenancy = multitenancy; + public TenantScope(MultitenancyConfiguration multitenancyConfiguration) { + this.multitenancyConfiguration = multitenancyConfiguration; } public Boolean isMultitenant() { - return this.multitenancy.isMultitenant(); + return this.multitenancyConfiguration.getConfig().isMultitenant(); + } + + public Boolean supportExpansionTenant() { + return this.multitenancyConfiguration.getConfig().getSupportExpansionTenant(); } public String getDefaultTenantCode() { - return this.multitenancy.getDefaultTenantCode(); + return this.multitenancyConfiguration.getConfig().getDefaultTenantCode(); } public Boolean isSet() { @@ -40,8 +44,8 @@ public class TenantScope { public Boolean isDefaultTenant() { if (!this.isMultitenant()) - return Boolean.TRUE; - return this.multitenancy.getDefaultTenantCode().equalsIgnoreCase(this.tenantCode.get()); + return Boolean.FALSE; + return this.supportExpansionTenant() && this.multitenancyConfiguration.getConfig().getDefaultTenantCode().equalsIgnoreCase(this.tenantCode.get()); } public UUID getTenant() throws InvalidApplicationException { 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 8498d2f45..12c2df61a 100644 --- a/backend/core/src/main/java/org/opencdmp/data/TenantEntityManager.java +++ b/backend/core/src/main/java/org/opencdmp/data/TenantEntityManager.java @@ -72,7 +72,7 @@ public class TenantEntityManager { if (!this.tenantFiltersDisabled && this.tenantScope.isMultitenant() && (entity instanceof TenantScoped tenantScopedEntity)) { if (tenantScopedEntity.getTenantId() != null && !tenantScopedEntity.getTenantId().equals(this.tenantScope.getTenant())) return null; } - if (disableTracking && entity != null) this.entityManager.detach(entity); + if (disableTracking) this.entityManager.detach(entity); return entity; } @@ -95,8 +95,10 @@ public class TenantEntityManager { } public void reloadTenantFilters() throws InvalidApplicationException { - if (!this.entityManager.isOpen()) return; - + if (!this.entityManager.isOpen()) { + this.tenantFiltersDisabled = false; + return; + } this.disableTenantFilters(); if (!this.tenantScope.isSet()) return; @@ -115,8 +117,10 @@ public class TenantEntityManager { } public void loadExplicitTenantFilters() throws InvalidApplicationException { - if (!this.entityManager.isOpen()) return; - + if (!this.entityManager.isOpen()) { + this.tenantFiltersDisabled = false; + return; + } this.disableTenantFilters(); if (!this.tenantScope.isSet()) return; @@ -135,8 +139,10 @@ public class TenantEntityManager { } public void disableTenantFilters() { - if (!this.entityManager.isOpen()) return; - + if (!this.entityManager.isOpen()) { + this.tenantFiltersDisabled = true; + return; + } this.entityManager .unwrap(Session.class) .disableFilter(TenantScopedBaseEntity.TENANT_FILTER); diff --git a/backend/core/src/main/java/org/opencdmp/data/tenant/TenantListener.java b/backend/core/src/main/java/org/opencdmp/data/tenant/TenantListener.java index 4bd8ffff5..24acedf00 100644 --- a/backend/core/src/main/java/org/opencdmp/data/tenant/TenantListener.java +++ b/backend/core/src/main/java/org/opencdmp/data/tenant/TenantListener.java @@ -74,7 +74,7 @@ public class TenantListener { } } } else { - if (entity.getTenantId() != null && (!this.tenantScope.isDefaultTenant() ||entity.getTenantId().compareTo(this.tenantScope.getTenant()) != 0)) { + if (entity.getTenantId() != null) { logger.error("somebody tried to change an entries tenant"); throw new MyForbiddenException(this.errors.getTenantTampering().getCode(), this.errors.getTenantTampering().getMessage()); } diff --git a/backend/core/src/main/java/org/opencdmp/integrationevent/inbox/annotationentitycreated/AnnotationEntityCreatedIntegrationEventHandlerImpl.java b/backend/core/src/main/java/org/opencdmp/integrationevent/inbox/annotationentitycreated/AnnotationEntityCreatedIntegrationEventHandlerImpl.java index fa6b67ea5..77aed5c04 100644 --- a/backend/core/src/main/java/org/opencdmp/integrationevent/inbox/annotationentitycreated/AnnotationEntityCreatedIntegrationEventHandlerImpl.java +++ b/backend/core/src/main/java/org/opencdmp/integrationevent/inbox/annotationentitycreated/AnnotationEntityCreatedIntegrationEventHandlerImpl.java @@ -90,15 +90,20 @@ public class AnnotationEntityCreatedIntegrationEventHandlerImpl implements Annot EventProcessingStatus status = EventProcessingStatus.Success; try { - if (this.tenantScope.isMultitenant() && properties.getTenantId() != null) { - TenantEntity tenant = this.queryFactory.query(TenantQuery.class).disableTracking().ids(properties.getTenantId()).firstAs(new BaseFieldSet().ensure(Tenant._id).ensure(Tenant._code)); - if (tenant == null) { + if (this.tenantScope.isMultitenant()) { + if (properties.getTenantId() != null) { + TenantEntity tenant = this.queryFactory.query(TenantQuery.class).disableTracking().ids(properties.getTenantId()).firstAs(new BaseFieldSet().ensure(Tenant._id).ensure(Tenant._code)); + if (tenant == null) { + logger.error("missing tenant from event message"); + return EventProcessingStatus.Error; + } + this.tenantScope.setTempTenant(this.tenantEntityManager, properties.getTenantId(), tenant.getCode()); + } else if (this.tenantScope.supportExpansionTenant()) { + this.tenantScope.setTempTenant(this.tenantEntityManager, null, this.tenantScope.getDefaultTenantCode()); + } else { logger.error("missing tenant from event message"); return EventProcessingStatus.Error; } - this.tenantScope.setTempTenant(this.tenantEntityManager, properties.getTenantId(), tenant.getCode()); - } else if (this.tenantScope.isMultitenant()) { - this.tenantScope.setTempTenant(this.tenantEntityManager, null, this.tenantScope.getDefaultTenantCode()); } this.currentPrincipalResolver.push(InboxPrincipal.build(properties, this.claimExtractorProperties)); diff --git a/backend/core/src/main/java/org/opencdmp/integrationevent/inbox/annotationstatusentitychanged/AnnotationStatusEntityChangedIntegrationEventHandlerImpl.java b/backend/core/src/main/java/org/opencdmp/integrationevent/inbox/annotationstatusentitychanged/AnnotationStatusEntityChangedIntegrationEventHandlerImpl.java index 4f449f598..f5a81bb90 100644 --- a/backend/core/src/main/java/org/opencdmp/integrationevent/inbox/annotationstatusentitychanged/AnnotationStatusEntityChangedIntegrationEventHandlerImpl.java +++ b/backend/core/src/main/java/org/opencdmp/integrationevent/inbox/annotationstatusentitychanged/AnnotationStatusEntityChangedIntegrationEventHandlerImpl.java @@ -90,15 +90,20 @@ public class AnnotationStatusEntityChangedIntegrationEventHandlerImpl implements EventProcessingStatus status = EventProcessingStatus.Success; try { - if (this.tenantScope.isMultitenant() && properties.getTenantId() != null) { - TenantEntity tenant = this.queryFactory.query(TenantQuery.class).disableTracking().ids(properties.getTenantId()).firstAs(new BaseFieldSet().ensure(Tenant._id).ensure(Tenant._code)); - if (tenant == null) { + if (this.tenantScope.isMultitenant()) { + if (properties.getTenantId() != null) { + TenantEntity tenant = this.queryFactory.query(TenantQuery.class).disableTracking().ids(properties.getTenantId()).firstAs(new BaseFieldSet().ensure(Tenant._id).ensure(Tenant._code)); + if (tenant == null) { + logger.error("missing tenant from event message"); + return EventProcessingStatus.Error; + } + this.tenantScope.setTempTenant(this.tenantEntityManager, properties.getTenantId(), tenant.getCode()); + } else if (this.tenantScope.supportExpansionTenant()) { + this.tenantScope.setTempTenant(this.tenantEntityManager, null, this.tenantScope.getDefaultTenantCode()); + } else { logger.error("missing tenant from event message"); return EventProcessingStatus.Error; } - this.tenantScope.setTempTenant(this.tenantEntityManager, properties.getTenantId(), tenant.getCode()); - } else if (this.tenantScope.isMultitenant()) { - this.tenantScope.setTempTenant(this.tenantEntityManager, null, this.tenantScope.getDefaultTenantCode()); } this.currentPrincipalResolver.push(InboxPrincipal.build(properties, this.claimExtractorProperties)); diff --git a/backend/core/src/main/java/org/opencdmp/service/tenant/TenantServiceImpl.java b/backend/core/src/main/java/org/opencdmp/service/tenant/TenantServiceImpl.java index acd148961..1301d9c0a 100644 --- a/backend/core/src/main/java/org/opencdmp/service/tenant/TenantServiceImpl.java +++ b/backend/core/src/main/java/org/opencdmp/service/tenant/TenantServiceImpl.java @@ -181,8 +181,13 @@ public class TenantServiceImpl implements TenantService { existingItems = this.queryFactory.query(UserRoleQuery.class).disableTracking().tenantIsSet(false).roles(this.authorizationConfiguration.getAuthorizationProperties().getGlobalAdminRoles()).collect(); userCredentialEntities = this.queryFactory.query(UserCredentialQuery.class).disableTracking().userIds(existingItems.stream().map(UserRoleEntity::getUserId).distinct().toList()).collect(); - - List keycloakIdsToAddToTenantGroup = new ArrayList<>(); + } finally { + this.entityManager.reloadTenantFilters(); + } + + List keycloakIdsToAddToTenantGroup = new ArrayList<>(); + try { + this.tenantScope.setTempTenant(this.entityManager, tenant.getId(), tenant.getCode()); for (UUID userId : existingItems.stream().map(UserRoleEntity::getUserId).distinct().toList()) { this.usageLimitService.checkIncrease(UsageLimitTargetMetric.USER_COUNT); TenantUserEntity tenantUserEntity = new TenantUserEntity(); @@ -196,13 +201,13 @@ public class TenantServiceImpl implements TenantService { this.eventBroker.emit(new UserAddedToTenantEvent(tenantUserEntity.getUserId(), tenantUserEntity.getTenantId())); this.accountingService.increase(UsageLimitTargetMetric.USER_COUNT.getValue()); - UserCredentialEntity userCredential = userCredentialEntities.stream().filter(x-> !this.conventionService.isNullOrEmpty(x.getExternalId()) && x.getUserId().equals(userId)).findFirst().orElse(null); + UserCredentialEntity userCredential = userCredentialEntities.stream().filter(x -> !this.conventionService.isNullOrEmpty(x.getExternalId()) && x.getUserId().equals(userId)).findFirst().orElse(null); if (userCredential == null) continue; UserRoleEntity item = new UserRoleEntity(); item.setId(UUID.randomUUID()); item.setUserId(userId); item.setTenantId(tenant.getId()); - if (existingItems.stream().filter(x -> x.getUserId().equals(userId) && x.getRole().equals(this.authorizationConfiguration.getAuthorizationProperties().getAdminRole())).findFirst().orElse(null) != null){ + if (existingItems.stream().filter(x -> x.getUserId().equals(userId) && x.getRole().equals(this.authorizationConfiguration.getAuthorizationProperties().getAdminRole())).findFirst().orElse(null) != null) { item.setRole(this.authorizationConfiguration.getAuthorizationProperties().getTenantAdminRole()); // admin } else { item.setRole(this.authorizationConfiguration.getAuthorizationProperties().getTenantUserRole()); // installation admin @@ -215,21 +220,22 @@ public class TenantServiceImpl implements TenantService { } this.entityManager.flush(); - + for (UUID userId : existingItems.stream().map(UserRoleEntity::getUserId).distinct().toList()) { this.userTouchedIntegrationEventHandler.handle(userId); this.eventBroker.emit(new UserTouchedEvent(userId)); - - } - - this.entityManager.flush(); - for (String externalId : keycloakIdsToAddToTenantGroup) { - this.keycloakService.addUserToTenantRoleGroup(externalId, tenant.getCode(), this.authorizationConfiguration.getAuthorizationProperties().getTenantAdminRole()); } + + this.entityManager.flush(); } finally { - this.entityManager.reloadTenantFilters(); + this.tenantScope.removeTempTenant(this.entityManager); } + + for (String externalId : keycloakIdsToAddToTenantGroup) { + this.keycloakService.addUserToTenantRoleGroup(externalId, tenant.getCode(), this.authorizationConfiguration.getAuthorizationProperties().getTenantAdminRole()); + } + } @Override 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 3c351d99a..9433760a9 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 @@ -117,7 +117,7 @@ public class TenantInterceptor implements WebRequestInterceptor { } boolean isUserAllowedTenant = false; - if (this.tenantScope.isDefaultTenant()){ + if (this.tenantScope.supportExpansionTenant() && this.tenantScope.isDefaultTenant()){ isUserAllowedTenant = true; } else { UserAllowedTenantCacheService.UserAllowedTenantCacheValue cacheValue = this.userAllowedTenantCacheService.lookup(this.userAllowedTenantCacheService.buildKey(this.userScope.getUserId(), this.tenantScope.getTenant())); 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 5c36f73c3..078ac55df 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 @@ -90,13 +90,13 @@ public class TenantScopeClaimInterceptor implements WebRequestInterceptor { if (this.conventionService.isNullOrEmpty(tenantCode)) tenantCode = this.claimExtractor.asString(principal, this.clientTenantClaimName); if (tenantCode == null || this.conventionService.isNullOrEmpty(tenantCode)) return false; - if (tenantCode.equalsIgnoreCase(this.tenantScope.getDefaultTenantCode())){ + if (this.tenantScope.supportExpansionTenant() && tenantCode.equalsIgnoreCase(this.tenantScope.getDefaultTenantCode())) { logger.debug("parsed tenant header and set tenant to default tenant"); this.tenantScope.setTenant(null, tenantCode); this.claimExtractorContext.putReplaceParameter(TenantScope.TenantReplaceParameter, tenantCode); return true; } - + UUID tenantId = this.conventionService.parseUUIDSafe(tenantCode); if (tenantId == null) { TenantByCodeCacheService.TenantByCodeCacheValue cacheValue = this.tenantByCodeCacheService.lookup(this.tenantByCodeCacheService.buildKey(tenantCode)); diff --git a/backend/web/src/main/java/org/opencdmp/interceptors/tenant/TenantScopeHeaderInterceptor.java b/backend/web/src/main/java/org/opencdmp/interceptors/tenant/TenantScopeHeaderInterceptor.java index d7c14f6c5..627712983 100644 --- a/backend/web/src/main/java/org/opencdmp/interceptors/tenant/TenantScopeHeaderInterceptor.java +++ b/backend/web/src/main/java/org/opencdmp/interceptors/tenant/TenantScopeHeaderInterceptor.java @@ -56,15 +56,15 @@ public class TenantScopeHeaderInterceptor implements WebRequestInterceptor { } @Override - public void preHandle(@NotNull WebRequest request) { + public void preHandle(@NotNull WebRequest request) { if (!this.currentPrincipalResolver.currentPrincipal().isAuthenticated()) return; if (!this.tenantScope.isMultitenant()) return; String tenantCode = request.getHeader(ClaimNames.TenantClaimName); logger.debug("retrieved request tenant header is: {}", tenantCode); if (tenantCode == null || this.conventionService.isNullOrEmpty(tenantCode)) return; - - if (tenantCode.equalsIgnoreCase(this.tenantScope.getDefaultTenantCode())){ + + if (this.tenantScope.supportExpansionTenant() && tenantCode.equalsIgnoreCase(this.tenantScope.getDefaultTenantCode())) { logger.debug("parsed tenant header and set tenant to default tenant"); this.tenantScope.setTenant(null, tenantCode); this.claimExtractorContext.putReplaceParameter(TenantScope.TenantReplaceParameter, tenantCode); @@ -144,3 +144,4 @@ public class TenantScopeHeaderInterceptor implements WebRequestInterceptor { public void afterCompletion(@NonNull WebRequest request, Exception ex) { } } + diff --git a/backend/web/src/main/resources/config/tenant-devel.yml b/backend/web/src/main/resources/config/tenant-devel.yml index 9f42782a8..96e4bf11e 100644 --- a/backend/web/src/main/resources/config/tenant-devel.yml +++ b/backend/web/src/main/resources/config/tenant-devel.yml @@ -4,6 +4,7 @@ tenant: multitenancy: is-multitenant: true default-tenant-code: default + support-expansion-tenant: true interceptor: client-claims-prefix: client_ enforce-trusted-tenant: false