add supportExpansionTenant

This commit is contained in:
Efstratios Giannopoulos 2024-08-23 12:33:58 +03:00
parent cdaf9d43d5
commit cae4003af5
12 changed files with 97 additions and 45 deletions

View File

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

View File

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

View File

@ -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<UUID> tenant = new AtomicReference<>();
private final AtomicReference<String> tenantCode = new AtomicReference<>();
private final AtomicReference<UUID> initialTenant = new AtomicReference<>();
private final AtomicReference<String> 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 {

View File

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

View File

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

View File

@ -90,15 +90,20 @@ public class AnnotationEntityCreatedIntegrationEventHandlerImpl implements Annot
EventProcessingStatus status = EventProcessingStatus.Success;
try {
if (this.tenantScope.isMultitenant() && properties.getTenantId() != 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.isMultitenant()) {
} 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.currentPrincipalResolver.push(InboxPrincipal.build(properties, this.claimExtractorProperties));

View File

@ -90,15 +90,20 @@ public class AnnotationStatusEntityChangedIntegrationEventHandlerImpl implements
EventProcessingStatus status = EventProcessingStatus.Success;
try {
if (this.tenantScope.isMultitenant() && properties.getTenantId() != 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.isMultitenant()) {
} 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.currentPrincipalResolver.push(InboxPrincipal.build(properties, this.claimExtractorProperties));

View File

@ -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();
} finally {
this.entityManager.reloadTenantFilters();
}
List<String> 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();
@ -223,13 +228,14 @@ public class TenantServiceImpl implements TenantService {
}
this.entityManager.flush();
} finally {
this.tenantScope.removeTempTenant(this.entityManager);
}
for (String externalId : keycloakIdsToAddToTenantGroup) {
this.keycloakService.addUserToTenantRoleGroup(externalId, tenant.getCode(), this.authorizationConfiguration.getAuthorizationProperties().getTenantAdminRole());
}
} finally {
this.entityManager.reloadTenantFilters();
}
}
@Override

View File

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

View File

@ -90,7 +90,7 @@ 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);

View File

@ -64,7 +64,7 @@ public class TenantScopeHeaderInterceptor implements WebRequestInterceptor {
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) {
}
}

View File

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