multi tenant changes

This commit is contained in:
Efstratios Giannopoulos 2024-04-04 12:21:12 +03:00
parent ea6ea25116
commit bbe2d91830
30 changed files with 202 additions and 262 deletions

View File

@ -1,9 +1,9 @@
package gr.cite.annotation.web; package gr.cite.annotation.web;
import gr.cite.annotation.web.interceptors.UserInterceptor;
import gr.cite.annotation.web.scope.tenant.TenantInterceptor; import gr.cite.annotation.web.scope.tenant.TenantInterceptor;
import gr.cite.annotation.web.scope.tenant.TenantScopeClaimInterceptor; import gr.cite.annotation.web.scope.tenant.TenantScopeClaimInterceptor;
import gr.cite.annotation.web.scope.tenant.TenantScopeHeaderInterceptor; import gr.cite.annotation.web.scope.tenant.TenantScopeHeaderInterceptor;
import gr.cite.annotation.web.scope.user.UserInterceptor;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.InterceptorRegistry;

View File

@ -29,6 +29,7 @@ import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.preauth.AbstractPreAuthenticatedProcessingFilter; import org.springframework.security.web.authentication.preauth.AbstractPreAuthenticatedProcessingFilter;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
@ -104,7 +105,7 @@ public class SecurityConfiguration {
//In the example below, the default client handler will be ignored by the resolver //In the example below, the default client handler will be ignored by the resolver
@Override @Override
public List<Class<? extends AuthorizationHandler<? extends AuthorizationRequirement>>> disableHandlers() { public List<Class<? extends AuthorizationHandler<? extends AuthorizationRequirement>>> disableHandlers() {
return List.of(PermissionClientAuthorizationHandler.class); return new ArrayList<>();
} }
}; };
} }

View File

@ -1,17 +0,0 @@
//package gr.cite.intelcomp.stiviewer.web.controllers.error;
//
//import gr.cite.tools.exception.MyValidationException;
//import org.springframework.http.HttpStatus;
//import org.springframework.http.ResponseEntity;
//import org.springframework.web.bind.annotation.ControllerAdvice;
//import org.springframework.web.bind.annotation.ExceptionHandler;
//import org.springframework.web.context.request.WebRequest;
//
//@ControllerAdvice
//public class GenericErrorHandler {
//
// @ExceptionHandler(MyValidationException.class)
// public ResponseEntity<MyValidationException> handleValidationException(MyValidationException e, WebRequest webRequest) {
// return ResponseEntity.status(HttpStatus.NOT_ACCEPTABLE).body(e);
// }
//}

View File

@ -1,92 +0,0 @@
package gr.cite.annotation.web.interceptors;
import gr.cite.commons.web.oidc.principal.CurrentPrincipalResolver;
import gr.cite.commons.web.oidc.principal.extractor.ClaimExtractor;
import gr.cite.annotation.common.JsonHandlingService;
import gr.cite.annotation.common.lock.LockByKeyManager;
import gr.cite.annotation.common.scope.user.UserScope;
import gr.cite.annotation.data.UserCredentialEntity;
import gr.cite.annotation.model.UserCredential;
import gr.cite.annotation.query.UserCredentialQuery;
import gr.cite.tools.data.query.QueryFactory;
import gr.cite.tools.exception.MyForbiddenException;
import gr.cite.tools.fieldset.BaseFieldSet;
import gr.cite.tools.logging.LoggerService;
import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.lang.NonNull;
import org.springframework.stereotype.Component;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.ui.ModelMap;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.context.request.WebRequestInterceptor;
import java.util.UUID;
@Component
public class UserInterceptor implements WebRequestInterceptor {
private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(UserInterceptor.class));
private final UserScope userScope;
private final ClaimExtractor claimExtractor;
private final CurrentPrincipalResolver currentPrincipalResolver;
private final UserInterceptorCacheService userInterceptorCacheService;
private final QueryFactory queryFactory;
@PersistenceContext
public EntityManager entityManager;
@Autowired
public UserInterceptor(
UserScope userScope,
ClaimExtractor claimExtractor,
CurrentPrincipalResolver currentPrincipalResolver,
UserInterceptorCacheService userInterceptorCacheService,
QueryFactory queryFactory) {
this.userScope = userScope;
this.currentPrincipalResolver = currentPrincipalResolver;
this.claimExtractor = claimExtractor;
this.userInterceptorCacheService = userInterceptorCacheService;
this.queryFactory = queryFactory;
}
@Override
public void preHandle(WebRequest request) {
UUID userId = null;
if (this.currentPrincipalResolver.currentPrincipal().isAuthenticated()) {
String subjectId = this.claimExtractor.subjectString(this.currentPrincipalResolver.currentPrincipal());
if (subjectId == null || subjectId.isBlank()) throw new MyForbiddenException("Empty subjects not allowed");
UserInterceptorCacheService.UserInterceptorCacheValue cacheValue = this.userInterceptorCacheService.lookup(this.userInterceptorCacheService.buildKey(subjectId));
if (cacheValue != null) {
userId = cacheValue.getUserId();
} else {
userId = this.findExistingUserFromDbForce(subjectId);
cacheValue = new UserInterceptorCacheService.UserInterceptorCacheValue(subjectId, userId);
this.userInterceptorCacheService.put(cacheValue);
}
}
this.userScope.setUserId(userId);
}
private UUID findExistingUserFromDbForce(String subjectId){
UserCredentialEntity userCredential = this.queryFactory.query(UserCredentialQuery.class).externalIds(subjectId).firstAs(new BaseFieldSet().ensure(UserCredential._user));
if (userCredential != null) {
return userCredential.getUserId();
} else {
throw new MyForbiddenException("User not created try again.");
}
}
@Override
public void postHandle(@NonNull WebRequest request, ModelMap model) {
this.userScope.setUserId(null);
}
@Override
public void afterCompletion(@NonNull WebRequest request, Exception ex) {
}
}

View File

@ -1,10 +0,0 @@
package gr.cite.annotation.web.interceptors;
import gr.cite.tools.cache.CacheOptions;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
@Configuration
@ConfigurationProperties(prefix = "cache.user-by-subject-id")
public class UserInterceptorCacheOptions extends CacheOptions {
}

View File

@ -1,66 +0,0 @@
package gr.cite.annotation.web.interceptors;
import gr.cite.tools.cache.CacheService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.UUID;
@Service
public class UserInterceptorCacheService extends CacheService<UserInterceptorCacheService.UserInterceptorCacheValue> {
public static class UserInterceptorCacheValue {
public UserInterceptorCacheValue() {
}
public UserInterceptorCacheValue(String subjectId, UUID userId) {
this.subjectId = subjectId;
this.userId = userId;
}
private String subjectId;
public String getSubjectId() {
return subjectId;
}
public void setSubjectId(String subjectId) {
this.subjectId = subjectId;
}
private UUID userId;
public UUID getUserId() {
return userId;
}
public void setUserId(UUID userId) {
this.userId = userId;
}
}
@Autowired
public UserInterceptorCacheService(UserInterceptorCacheOptions options) {
super(options);
}
@Override
protected Class<UserInterceptorCacheValue> valueClass() {
return UserInterceptorCacheValue.class;
}
@Override
public String keyOf(UserInterceptorCacheValue value) {
return this.buildKey(value.getSubjectId());
}
public String buildKey(String subject) {
HashMap<String, String> keyParts = new HashMap<>();
keyParts.put("$subject$", subject);
return this.generateKey(keyParts);
}
}

View File

@ -20,11 +20,25 @@ idpclient:
Roles: Roles:
- type: resource_access - type: resource_access
path: dmp_web.roles path: dmp_web.roles
- type: tenant_roles
filterBy: "(.*):::TenantCode::"
extractByExpression: "(.*):(.*)"
extractExpressionValue: "[[g1]]"
GlobalRoles:
- type: resource_access
path: dmp_web.roles
TenantRoles:
- type: tenant_roles
filterBy: "(.*):::TenantCode::"
extractByExpression: "(.*):(.*)"
extractExpressionValue: "[[g1]]"
Scope: Scope:
- type: scope - type: scope
AccessToken: AccessToken:
- type: x-access-token - type: x-access-token
visibility: SENSITIVE visibility: SENSITIVE
Tenant:
- type: x-tenant
IssuedAt: IssuedAt:
- type: iat - type: iat
Issuer: Issuer:
@ -37,5 +51,8 @@ idpclient:
- type: azp - type: azp
Authorities: Authorities:
- type: authorities - type: authorities
ExternalProviderName: TenantCodes:
- type: identity_provider - type: tenant_roles
filterBy: "(.*):(.*)"
extractByExpression: "(.*):(.*)"
extractExpressionValue: "[[g2]]"

View File

@ -2,10 +2,10 @@ permissions:
policies: policies:
DeferredAffiliation: DeferredAffiliation:
roles: roles:
- Admin - TenantAdmin
- User - TenantUser
- Manager - TenantManager
- DescriptionTemplateEditor - TenantDescriptionTemplateEditor
clients: [ ] clients: [ ]
allowAnonymous: false allowAnonymous: false
allowAuthenticated: false allowAuthenticated: false
@ -19,14 +19,14 @@ permissions:
EditTenant: EditTenant:
roles: roles:
- Admin - Admin
clients: [ ] clients: [ "opendmp-api-dev" ]
allowAnonymous: false allowAnonymous: false
allowAuthenticated: false allowAuthenticated: false
DeleteTenant: DeleteTenant:
roles: roles:
- Admin - Admin
claims: [ ] claims: [ ]
clients: [ ] clients: [ "opendmp-api-dev" ]
allowAnonymous: false allowAnonymous: false
allowAuthenticated: false allowAuthenticated: false
AllowNoTenant: AllowNoTenant:
@ -39,47 +39,47 @@ permissions:
# Users # Users
BrowseUser: BrowseUser:
roles: roles:
- Admin - TenantAdmin
clients: [ ] clients: [ ]
allowAnonymous: true allowAnonymous: true
allowAuthenticated: false allowAuthenticated: false
EditUser: EditUser:
roles: roles:
- Admin - TenantAdmin
clients: [ ] clients: [ "opendmp-api-dev" ]
allowAnonymous: false allowAnonymous: false
allowAuthenticated: false allowAuthenticated: false
DeleteUser: DeleteUser:
roles: roles:
- Admin - TenantAdmin
claims: [ ] claims: [ ]
clients: [ ] clients: [ "opendmp-api-dev" ]
allowAnonymous: false allowAnonymous: false
allowAuthenticated: false allowAuthenticated: false
#Annotation #Annotation
BrowseAnnotation: BrowseAnnotation:
roles: roles:
- Admin - TenantAdmin
entityAffiliated: true entityAffiliated: true
clients: [ ] clients: [ ]
allowAnonymous: true allowAnonymous: true
allowAuthenticated: false allowAuthenticated: false
NewAnnotation: NewAnnotation:
roles: roles:
- Admin - TenantAdmin
entityAffiliated: true entityAffiliated: true
clients: [ ] clients: [ ]
allowAnonymous: true allowAnonymous: true
allowAuthenticated: false allowAuthenticated: false
EditAnnotation: EditAnnotation:
roles: roles:
- Admin - TenantAdmin
clients: [ ] clients: [ ]
allowAnonymous: true allowAnonymous: true
allowAuthenticated: false allowAuthenticated: false
DeleteAnnotation: DeleteAnnotation:
roles: roles:
- Admin - TenantAdmin
entityAffiliated: false entityAffiliated: false
clients: [ ] clients: [ ]
allowAnonymous: false allowAnonymous: false
@ -87,13 +87,13 @@ permissions:
#Tenant Configuration #Tenant Configuration
BrowseTenantConfiguration: BrowseTenantConfiguration:
roles: roles:
- Admin - TenantAdmin
clients: [ ] clients: [ ]
allowAnonymous: false allowAnonymous: false
allowAuthenticated: false allowAuthenticated: false
EditTenantConfiguration: EditTenantConfiguration:
roles: roles:
- Admin - TenantAdmin
clients: [ ] clients: [ ]
allowAnonymous: false allowAnonymous: false
allowAuthenticated: false allowAuthenticated: false

View File

@ -82,6 +82,7 @@ public class TenantEntityManager {
} }
public void enableTenantFilters() throws InvalidApplicationException { public void enableTenantFilters() throws InvalidApplicationException {
if (!tenantScope.isSet()) return;
if(!tenantScope.isDefaultTenant()) { if(!tenantScope.isDefaultTenant()) {
this.entityManager this.entityManager
.unwrap(Session.class) .unwrap(Session.class)

View File

@ -1,5 +1,6 @@
package gr.cite.annotation.integrationevent; package gr.cite.annotation.integrationevent;
import gr.cite.annotation.data.QueueOutboxEntity;
import gr.cite.annotation.integrationevent.outbox.OutboxProperties; import gr.cite.annotation.integrationevent.outbox.OutboxProperties;
import gr.cite.annotation.integrationevent.outbox.OutboxRepositoryImpl; import gr.cite.annotation.integrationevent.outbox.OutboxRepositoryImpl;
import gr.cite.queueoutbox.IntegrationEventContextCreator; import gr.cite.queueoutbox.IntegrationEventContextCreator;
@ -56,7 +57,11 @@ public class OutboxIntegrationEventConfigurer extends OutboxConfigurer {
@Bean @Bean
public IntegrationEventContextCreator integrationEventContextCreator() { public IntegrationEventContextCreator integrationEventContextCreator() {
return (message) -> new IntegrationEventContextImpl(); return (message) -> {
IntegrationEventContextImpl integrationEventContext = new IntegrationEventContextImpl();
if (message instanceof QueueOutboxEntity) integrationEventContext.setTenant(((QueueOutboxEntity)message).getTenantId());
return integrationEventContext;
};
} }
@Bean @Bean

View File

@ -1,11 +1,13 @@
package gr.cite.annotation.integrationevent.inbox; package gr.cite.annotation.integrationevent.inbox;
import gr.cite.commons.web.oidc.principal.MyPrincipal; import gr.cite.commons.web.oidc.principal.MyPrincipal;
import gr.cite.commons.web.oidc.principal.extractor.ClaimExtractorProperties;
import org.springframework.security.oauth2.core.ClaimAccessor; import org.springframework.security.oauth2.core.ClaimAccessor;
import org.springframework.security.oauth2.jwt.JwtClaimNames; import org.springframework.security.oauth2.jwt.JwtClaimNames;
import java.time.Instant; import java.time.Instant;
import java.time.temporal.ChronoUnit; import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -22,12 +24,15 @@ public class InboxPrincipal implements MyPrincipal, ClaimAccessor {
this.isAuthenticated = isAuthenticated; this.isAuthenticated = isAuthenticated;
} }
public static InboxPrincipal build(IntegrationEventProperties properties) { public static InboxPrincipal build(IntegrationEventProperties properties, ClaimExtractorProperties claimExtractorProperties) {
InboxPrincipal inboxPrincipal = new InboxPrincipal(true, "IntegrationEventQueueAppId"); InboxPrincipal inboxPrincipal = new InboxPrincipal(true, "IntegrationEventQueueAppId");
inboxPrincipal.put("client_id", properties.getAppId()); List<ClaimExtractorProperties.KeyPath> clientKey = claimExtractorProperties.getMapping().getOrDefault("Client", null);
inboxPrincipal.put(clientKey != null && clientKey.getFirst() != null ? clientKey.getFirst().getType() : "client_id", properties.getAppId());
inboxPrincipal.put("active", "true"); inboxPrincipal.put("active", "true");
inboxPrincipal.put("nbf", Instant.now().minus(30, ChronoUnit.SECONDS).toString()); List<ClaimExtractorProperties.KeyPath> notBeforeKey = claimExtractorProperties.getMapping().getOrDefault("NotBefore", null);
inboxPrincipal.put("exp", Instant.now().plus(10, ChronoUnit.MINUTES).toString()); inboxPrincipal.put(notBeforeKey != null && notBeforeKey.getFirst() != null ? notBeforeKey.getFirst().getType() :"nbf", Instant.now().minus(30, ChronoUnit.SECONDS).toString());
List<ClaimExtractorProperties.KeyPath> expiresAt = claimExtractorProperties.getMapping().getOrDefault("ExpiresAt", null);
inboxPrincipal.put(expiresAt != null && expiresAt.getFirst() != null ? expiresAt.getFirst().getType() :"exp", Instant.now().plus(10, ChronoUnit.MINUTES).toString());
return inboxPrincipal; return inboxPrincipal;
} }
@ -45,7 +50,10 @@ public class InboxPrincipal implements MyPrincipal, ClaimAccessor {
public List<String> getClaimAsStringList(String claim) { public List<String> getClaimAsStringList(String claim) {
if (claims == null) if (claims == null)
return null; return null;
return this.getClaimAsStringList(claim); if (this.claims.containsKey(claim)){
return List.of(this.claims.get(claim).toString());
}
return null;
} }
@Override @Override

View File

@ -245,6 +245,12 @@ public class InboxRepositoryImpl implements InboxRepository {
queueMessage.setId(UUID.randomUUID()); queueMessage.setId(UUID.randomUUID());
Object tenantId = inboxCreatorParams.getHeaders() != null ? inboxCreatorParams.getHeaders().getOrDefault(IntegrationEventMessageConstants.TENANT, null) : null; Object tenantId = inboxCreatorParams.getHeaders() != null ? inboxCreatorParams.getHeaders().getOrDefault(IntegrationEventMessageConstants.TENANT, null) : null;
if (tenantId instanceof UUID) queueMessage.setTenantId((UUID) tenantId); if (tenantId instanceof UUID) queueMessage.setTenantId((UUID) tenantId);
else if (tenantId instanceof String) {
try {
queueMessage.setTenantId(UUID.fromString((String) tenantId));
} catch (Exception e) {
}
}
queueMessage.setExchange(this.inboxProperties.getExchange()); queueMessage.setExchange(this.inboxProperties.getExchange());
queueMessage.setRoute(inboxCreatorParams.getRoutingKey()); queueMessage.setRoute(inboxCreatorParams.getRoutingKey());
queueMessage.setQueue(inboxCreatorParams.getQueueName()); queueMessage.setQueue(inboxCreatorParams.getQueueName());

View File

@ -15,6 +15,7 @@ import gr.cite.annotation.model.Tenant;
import gr.cite.annotation.query.EntityUserQuery; import gr.cite.annotation.query.EntityUserQuery;
import gr.cite.annotation.query.TenantQuery; import gr.cite.annotation.query.TenantQuery;
import gr.cite.commons.web.oidc.principal.CurrentPrincipalResolver; import gr.cite.commons.web.oidc.principal.CurrentPrincipalResolver;
import gr.cite.commons.web.oidc.principal.extractor.ClaimExtractorProperties;
import gr.cite.tools.auditing.AuditService; import gr.cite.tools.auditing.AuditService;
import gr.cite.tools.data.deleter.DeleterFactory; import gr.cite.tools.data.deleter.DeleterFactory;
import gr.cite.tools.data.query.QueryFactory; import gr.cite.tools.data.query.QueryFactory;
@ -83,7 +84,9 @@ public class AnnotationEntitiesRemovalIntegrationEventHandlerImpl implements Ann
} }
CurrentPrincipalResolver currentPrincipalResolver = this.applicationContext.getBean(CurrentPrincipalResolver.class); CurrentPrincipalResolver currentPrincipalResolver = this.applicationContext.getBean(CurrentPrincipalResolver.class);
currentPrincipalResolver.push(InboxPrincipal.build(properties));
ClaimExtractorProperties claimExtractorProperties = this.applicationContext.getBean(ClaimExtractorProperties.class);
currentPrincipalResolver.push(InboxPrincipal.build(properties, claimExtractorProperties));
EntityManagerFactory entityManagerFactory = this.applicationContext.getBean(EntityManagerFactory.class); EntityManagerFactory entityManagerFactory = this.applicationContext.getBean(EntityManagerFactory.class);
entityManager = entityManagerFactory.createEntityManager(); entityManager = entityManagerFactory.createEntityManager();

View File

@ -15,6 +15,7 @@ import gr.cite.annotation.model.Tenant;
import gr.cite.annotation.query.EntityUserQuery; import gr.cite.annotation.query.EntityUserQuery;
import gr.cite.annotation.query.TenantQuery; import gr.cite.annotation.query.TenantQuery;
import gr.cite.commons.web.oidc.principal.CurrentPrincipalResolver; import gr.cite.commons.web.oidc.principal.CurrentPrincipalResolver;
import gr.cite.commons.web.oidc.principal.extractor.ClaimExtractorProperties;
import gr.cite.tools.auditing.AuditService; import gr.cite.tools.auditing.AuditService;
import gr.cite.tools.data.deleter.DeleterFactory; import gr.cite.tools.data.deleter.DeleterFactory;
import gr.cite.tools.data.query.QueryFactory; import gr.cite.tools.data.query.QueryFactory;
@ -85,7 +86,9 @@ public class AnnotationEntitiesTouchedIntegrationEventHandlerImpl implements Ann
} }
CurrentPrincipalResolver currentPrincipalResolver = this.applicationContext.getBean(CurrentPrincipalResolver.class); CurrentPrincipalResolver currentPrincipalResolver = this.applicationContext.getBean(CurrentPrincipalResolver.class);
currentPrincipalResolver.push(InboxPrincipal.build(properties));
ClaimExtractorProperties claimExtractorProperties = this.applicationContext.getBean(ClaimExtractorProperties.class);
currentPrincipalResolver.push(InboxPrincipal.build(properties, claimExtractorProperties));
EntityManagerFactory entityManagerFactory = this.applicationContext.getBean(EntityManagerFactory.class); EntityManagerFactory entityManagerFactory = this.applicationContext.getBean(EntityManagerFactory.class);
entityManager = entityManagerFactory.createEntityManager(); entityManager = entityManagerFactory.createEntityManager();
@ -114,6 +117,7 @@ public class AnnotationEntitiesTouchedIntegrationEventHandlerImpl implements Ann
data.setId(UUID.randomUUID()); data.setId(UUID.randomUUID());
data.setEntityId(entityEvent.getEntityId()); data.setEntityId(entityEvent.getEntityId());
data.setUserId(user); data.setUserId(user);
data.setTenantId(properties.getTenantId());
data.setCreatedAt(Instant.now()); data.setCreatedAt(Instant.now());
data.setUpdatedAt(Instant.now()); data.setUpdatedAt(Instant.now());
data.setIsActive(IsActive.Active); data.setIsActive(IsActive.Active);

View File

@ -10,6 +10,7 @@ import gr.cite.annotation.integrationevent.inbox.EventProcessingStatus;
import gr.cite.annotation.integrationevent.inbox.InboxPrincipal; import gr.cite.annotation.integrationevent.inbox.InboxPrincipal;
import gr.cite.annotation.integrationevent.inbox.IntegrationEventProperties; import gr.cite.annotation.integrationevent.inbox.IntegrationEventProperties;
import gr.cite.annotation.service.tenant.TenantService; import gr.cite.annotation.service.tenant.TenantService;
import gr.cite.commons.web.oidc.principal.extractor.ClaimExtractorProperties;
import gr.cite.tools.auditing.AuditService; import gr.cite.tools.auditing.AuditService;
import gr.cite.tools.logging.LoggerService; import gr.cite.tools.logging.LoggerService;
import jakarta.persistence.EntityManager; import jakarta.persistence.EntityManager;
@ -53,7 +54,9 @@ public class TenantRemovalIntegrationEventHandlerImpl implements TenantRemovalIn
try (FakeRequestScope ignored = new FakeRequestScope()) { try (FakeRequestScope ignored = new FakeRequestScope()) {
try { try {
CurrentPrincipalResolver currentPrincipalResolver = this.applicationContext.getBean(CurrentPrincipalResolver.class); CurrentPrincipalResolver currentPrincipalResolver = this.applicationContext.getBean(CurrentPrincipalResolver.class);
currentPrincipalResolver.push(InboxPrincipal.build(properties));
ClaimExtractorProperties claimExtractorProperties = this.applicationContext.getBean(ClaimExtractorProperties.class);
currentPrincipalResolver.push(InboxPrincipal.build(properties, claimExtractorProperties));
TenantRemovalConsistencyHandler tenantRemovalConsistencyHandler = this.applicationContext.getBean(TenantRemovalConsistencyHandler.class); TenantRemovalConsistencyHandler tenantRemovalConsistencyHandler = this.applicationContext.getBean(TenantRemovalConsistencyHandler.class);
if (!(tenantRemovalConsistencyHandler.isConsistent(new TenantRemovalConsistencyPredicates(event.getId())))) if (!(tenantRemovalConsistencyHandler.isConsistent(new TenantRemovalConsistencyPredicates(event.getId()))))

View File

@ -10,6 +10,8 @@ import gr.cite.annotation.integrationevent.inbox.InboxPrincipal;
import gr.cite.annotation.integrationevent.inbox.IntegrationEventProperties; import gr.cite.annotation.integrationevent.inbox.IntegrationEventProperties;
import gr.cite.annotation.model.persist.TenantTouchedIntegrationEventPersist; import gr.cite.annotation.model.persist.TenantTouchedIntegrationEventPersist;
import gr.cite.annotation.service.tenant.TenantService; import gr.cite.annotation.service.tenant.TenantService;
import gr.cite.commons.web.oidc.principal.extractor.ClaimExtractor;
import gr.cite.commons.web.oidc.principal.extractor.ClaimExtractorProperties;
import gr.cite.tools.auditing.AuditService; import gr.cite.tools.auditing.AuditService;
import gr.cite.tools.logging.LoggerService; import gr.cite.tools.logging.LoggerService;
import gr.cite.tools.validation.ValidatorFactory; import gr.cite.tools.validation.ValidatorFactory;
@ -59,7 +61,8 @@ public class TenantTouchedIntegrationEventHandlerImpl implements TenantTouchedIn
try (FakeRequestScope ignored = new FakeRequestScope()) { try (FakeRequestScope ignored = new FakeRequestScope()) {
try { try {
CurrentPrincipalResolver currentPrincipalResolver = this.applicationContext.getBean(CurrentPrincipalResolver.class); CurrentPrincipalResolver currentPrincipalResolver = this.applicationContext.getBean(CurrentPrincipalResolver.class);
currentPrincipalResolver.push(InboxPrincipal.build(properties)); ClaimExtractorProperties claimExtractorProperties = this.applicationContext.getBean(ClaimExtractorProperties.class);
currentPrincipalResolver.push(InboxPrincipal.build(properties, claimExtractorProperties));
EntityManagerFactory entityManagerFactory = this.applicationContext.getBean(EntityManagerFactory.class); EntityManagerFactory entityManagerFactory = this.applicationContext.getBean(EntityManagerFactory.class);
entityManager = entityManagerFactory.createEntityManager(); entityManager = entityManagerFactory.createEntityManager();

View File

@ -14,6 +14,7 @@ import gr.cite.annotation.integrationevent.inbox.IntegrationEventProperties;
import gr.cite.annotation.model.Tenant; import gr.cite.annotation.model.Tenant;
import gr.cite.annotation.query.TenantQuery; import gr.cite.annotation.query.TenantQuery;
import gr.cite.annotation.service.user.UserService; import gr.cite.annotation.service.user.UserService;
import gr.cite.commons.web.oidc.principal.extractor.ClaimExtractorProperties;
import gr.cite.tools.auditing.AuditService; import gr.cite.tools.auditing.AuditService;
import gr.cite.tools.data.query.QueryFactory; import gr.cite.tools.data.query.QueryFactory;
import gr.cite.tools.exception.MyValidationException; import gr.cite.tools.exception.MyValidationException;
@ -89,7 +90,9 @@ public class UserRemovalIntegrationEventHandlerImpl implements UserRemovalIntegr
} }
CurrentPrincipalResolver currentPrincipalResolver = this.applicationContext.getBean(CurrentPrincipalResolver.class); CurrentPrincipalResolver currentPrincipalResolver = this.applicationContext.getBean(CurrentPrincipalResolver.class);
currentPrincipalResolver.push(InboxPrincipal.build(properties));
ClaimExtractorProperties claimExtractorProperties = this.applicationContext.getBean(ClaimExtractorProperties.class);
currentPrincipalResolver.push(InboxPrincipal.build(properties, claimExtractorProperties));
UserRemovalConsistencyHandler userRemovalConsistencyHandler = this.applicationContext.getBean(UserRemovalConsistencyHandler.class); UserRemovalConsistencyHandler userRemovalConsistencyHandler = this.applicationContext.getBean(UserRemovalConsistencyHandler.class);
if (!(userRemovalConsistencyHandler.isConsistent(new UserRemovalConsistencyPredicates(event.getUserId())))) if (!(userRemovalConsistencyHandler.isConsistent(new UserRemovalConsistencyPredicates(event.getUserId()))))

View File

@ -13,6 +13,7 @@ import gr.cite.annotation.integrationevent.inbox.IntegrationEventProperties;
import gr.cite.annotation.model.Tenant; import gr.cite.annotation.model.Tenant;
import gr.cite.annotation.query.TenantQuery; import gr.cite.annotation.query.TenantQuery;
import gr.cite.annotation.service.user.UserService; import gr.cite.annotation.service.user.UserService;
import gr.cite.commons.web.oidc.principal.extractor.ClaimExtractorProperties;
import gr.cite.tools.auditing.AuditService; import gr.cite.tools.auditing.AuditService;
import gr.cite.tools.data.query.QueryFactory; import gr.cite.tools.data.query.QueryFactory;
import gr.cite.tools.fieldset.BaseFieldSet; import gr.cite.tools.fieldset.BaseFieldSet;
@ -82,7 +83,9 @@ public class UserTouchedIntegrationEventHandlerImpl implements UserTouchedIntegr
} }
CurrentPrincipalResolver currentPrincipalResolver = this.applicationContext.getBean(CurrentPrincipalResolver.class); CurrentPrincipalResolver currentPrincipalResolver = this.applicationContext.getBean(CurrentPrincipalResolver.class);
currentPrincipalResolver.push(InboxPrincipal.build(properties));
ClaimExtractorProperties claimExtractorProperties = this.applicationContext.getBean(ClaimExtractorProperties.class);
currentPrincipalResolver.push(InboxPrincipal.build(properties, claimExtractorProperties));
EntityManagerFactory entityManagerFactory = this.applicationContext.getBean(EntityManagerFactory.class); EntityManagerFactory entityManagerFactory = this.applicationContext.getBean(EntityManagerFactory.class);
entityManager = entityManagerFactory.createEntityManager(); entityManager = entityManagerFactory.createEntityManager();

View File

@ -75,6 +75,7 @@ public class TenantServiceImpl implements TenantService {
data.setCode(model.getCode()); data.setCode(model.getCode());
data.setIsActive(IsActive.Active); data.setIsActive(IsActive.Active);
data.setCreatedAt(Instant.now()); data.setCreatedAt(Instant.now());
data.setUpdatedAt(Instant.now());
this.entityManager.persist(data); this.entityManager.persist(data);
} else { } else {

View File

@ -5,15 +5,19 @@ import gr.cite.annotation.authorization.AuthorizationFlags;
import gr.cite.annotation.authorization.Permission; import gr.cite.annotation.authorization.Permission;
import gr.cite.annotation.common.JsonHandlingService; import gr.cite.annotation.common.JsonHandlingService;
import gr.cite.annotation.common.enums.IsActive; import gr.cite.annotation.common.enums.IsActive;
import gr.cite.annotation.common.scope.tenant.TenantScope;
import gr.cite.annotation.convention.ConventionService; import gr.cite.annotation.convention.ConventionService;
import gr.cite.annotation.data.*; import gr.cite.annotation.data.*;
import gr.cite.annotation.integrationevent.inbox.usertouch.UserTouchedIntegrationEvent; import gr.cite.annotation.integrationevent.inbox.usertouch.UserTouchedIntegrationEvent;
import gr.cite.annotation.model.Annotation;
import gr.cite.annotation.model.Tenant;
import gr.cite.annotation.model.User; import gr.cite.annotation.model.User;
import gr.cite.annotation.model.builder.UserBuilder; import gr.cite.annotation.model.builder.UserBuilder;
import gr.cite.annotation.model.deleter.TenantUserDeleter; import gr.cite.annotation.model.deleter.TenantUserDeleter;
import gr.cite.annotation.model.deleter.UserContactInfoDeleter; import gr.cite.annotation.model.deleter.UserContactInfoDeleter;
import gr.cite.annotation.model.deleter.UserCredentialDeleter; import gr.cite.annotation.model.deleter.UserCredentialDeleter;
import gr.cite.annotation.model.deleter.UserDeleter; import gr.cite.annotation.model.deleter.UserDeleter;
import gr.cite.annotation.query.TenantQuery;
import gr.cite.annotation.query.TenantUserQuery; import gr.cite.annotation.query.TenantUserQuery;
import gr.cite.annotation.query.UserContactInfoQuery; import gr.cite.annotation.query.UserContactInfoQuery;
import gr.cite.annotation.query.UserCredentialQuery; import gr.cite.annotation.query.UserCredentialQuery;
@ -31,6 +35,8 @@ import gr.cite.tools.logging.LoggerService;
import gr.cite.tools.logging.MapLogEntry; import gr.cite.tools.logging.MapLogEntry;
import jakarta.transaction.Transactional; import jakarta.transaction.Transactional;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.context.MessageSource;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import javax.management.InvalidApplicationException; import javax.management.InvalidApplicationException;
@ -57,6 +63,9 @@ public class UserServiceImpl implements UserService {
private final BuilderFactory builderFactory; private final BuilderFactory builderFactory;
private final QueryFactory queryFactory; private final QueryFactory queryFactory;
private final TenantScope tenantScope;
private final MessageSource messageSource;
private final JsonHandlingService jsonHandlingService; private final JsonHandlingService jsonHandlingService;
@ -65,7 +74,7 @@ public class UserServiceImpl implements UserService {
DeleterFactory deleterFactory, DeleterFactory deleterFactory,
ConventionService conventionService, ConventionService conventionService,
TenantEntityManager entityManager, TenantEntityManager entityManager,
BuilderFactory builderFactory, QueryFactory queryFactory, BuilderFactory builderFactory, QueryFactory queryFactory, TenantScope tenantScope, MessageSource messageSource,
JsonHandlingService jsonHandlingService) { JsonHandlingService jsonHandlingService) {
this.authorizationService = authorizationService; this.authorizationService = authorizationService;
this.deleterFactory = deleterFactory; this.deleterFactory = deleterFactory;
@ -73,6 +82,8 @@ public class UserServiceImpl implements UserService {
this.entityManager = entityManager; this.entityManager = entityManager;
this.builderFactory = builderFactory; this.builderFactory = builderFactory;
this.queryFactory = queryFactory; this.queryFactory = queryFactory;
this.tenantScope = tenantScope;
this.messageSource = messageSource;
this.jsonHandlingService = jsonHandlingService; this.jsonHandlingService = jsonHandlingService;
} }
@ -197,19 +208,31 @@ public class UserServiceImpl implements UserService {
.userIds(userId) .userIds(userId)
.isActive(IsActive.Active) .isActive(IsActive.Active)
.collect(); .collect();
List<UUID> updatedCreatedIds = new ArrayList<>(); List<UUID> updatedCreatedIds = new ArrayList<>();
if (models != null) { if (models != null) {
List<TenantEntity> tenantEntities = this.queryFactory.query(TenantQuery.class)
.ids(models.stream().map(UserTouchedIntegrationEvent.TenantUser::getTenant).toList())
.isActive(IsActive.Active)
.collectAs(new BaseFieldSet().ensure(Tenant._id).ensure(Tenant._code));
for (UserTouchedIntegrationEvent.TenantUser model : models) { for (UserTouchedIntegrationEvent.TenantUser model : models) {
TenantUserEntity data = items.stream().filter(x -> x.getTenantId().equals(model.getTenant())).findFirst().orElse(null); TenantUserEntity data = items.stream().filter(x -> x.getTenantId().equals(model.getTenant())).findFirst().orElse(null);
if (data == null) { if (data == null) {
data = new TenantUserEntity(); try {
data.setId(UUID.randomUUID()); TenantEntity tenant = tenantEntities.stream().filter(x -> x.getId().equals(model.getTenant())).findFirst().orElse(null);
data.setUserId(userId); if (tenant == null) throw new MyNotFoundException(messageSource.getMessage("General_ItemNotFound", new Object[]{model.getTenant(), Tenant.class.getSimpleName()}, LocaleContextHolder.getLocale()));
data.setTenantId(model.getTenant()); this.tenantScope.setTempTenant(this.entityManager.getEntityManager(), tenant.getId(), tenant.getCode());
data.setCreatedAt(Instant.now()); data = new TenantUserEntity();
data.setUpdatedAt(Instant.now()); data.setId(UUID.randomUUID());
data.setIsActive(IsActive.Active); data.setUserId(userId);
entityManager.persist(data); data.setTenantId(model.getTenant());
data.setCreatedAt(Instant.now());
data.setUpdatedAt(Instant.now());
data.setIsActive(IsActive.Active);
entityManager.persist(data);
} finally {
this.tenantScope.removeTempTenant(this.entityManager.getEntityManager());
}
} }
updatedCreatedIds.add(data.getId()); updatedCreatedIds.add(data.getId());
} }

View File

@ -87,6 +87,7 @@ public class TenantEntityManager {
} }
public void enableTenantFilters() throws InvalidApplicationException { public void enableTenantFilters() throws InvalidApplicationException {
if (!tenantScope.isSet()) return;
if(!tenantScope.isDefaultTenant()) { if(!tenantScope.isDefaultTenant()) {
this.entityManager this.entityManager
.unwrap(Session.class) .unwrap(Session.class)

View File

@ -1,6 +1,7 @@
package eu.eudat.integrationevent; package eu.eudat.integrationevent;
import eu.eudat.data.QueueOutboxEntity;
import eu.eudat.integrationevent.outbox.OutboxProperties; import eu.eudat.integrationevent.outbox.OutboxProperties;
import eu.eudat.integrationevent.outbox.OutboxRepositoryImpl; import eu.eudat.integrationevent.outbox.OutboxRepositoryImpl;
import gr.cite.queueoutbox.IntegrationEventContextCreator; import gr.cite.queueoutbox.IntegrationEventContextCreator;
@ -57,7 +58,11 @@ public class OutboxIntegrationEventConfigurer extends OutboxConfigurer {
@Bean @Bean
public IntegrationEventContextCreator integrationEventContextCreator() { public IntegrationEventContextCreator integrationEventContextCreator() {
return (message) -> new IntegrationEventContextImpl(); return (message) -> {
IntegrationEventContextImpl integrationEventContext = new IntegrationEventContextImpl();
if (message instanceof QueueOutboxEntity) integrationEventContext.setTenant(((QueueOutboxEntity)message).getTenantId());
return integrationEventContext;
};
} }
@Bean @Bean

View File

@ -1,6 +1,7 @@
package eu.eudat.integrationevent.inbox; package eu.eudat.integrationevent.inbox;
import gr.cite.commons.web.oidc.principal.MyPrincipal; import gr.cite.commons.web.oidc.principal.MyPrincipal;
import gr.cite.commons.web.oidc.principal.extractor.ClaimExtractorProperties;
import org.springframework.security.oauth2.core.ClaimAccessor; import org.springframework.security.oauth2.core.ClaimAccessor;
import org.springframework.security.oauth2.jwt.JwtClaimNames; import org.springframework.security.oauth2.jwt.JwtClaimNames;
@ -11,8 +12,9 @@ import java.util.List;
import java.util.Map; import java.util.Map;
public class InboxPrincipal implements MyPrincipal, ClaimAccessor { public class InboxPrincipal implements MyPrincipal, ClaimAccessor {
private Map<String, Object> claims; private final Map<String, Object> claims;
private boolean isAuthenticated;
private final boolean isAuthenticated;
public InboxPrincipal(Boolean isAuthenticated, String name) { public InboxPrincipal(Boolean isAuthenticated, String name) {
this.claims = new HashMap<>(); this.claims = new HashMap<>();
@ -20,6 +22,18 @@ public class InboxPrincipal implements MyPrincipal, ClaimAccessor {
this.isAuthenticated = isAuthenticated; this.isAuthenticated = isAuthenticated;
} }
public static InboxPrincipal build(IntegrationEventProperties properties, ClaimExtractorProperties claimExtractorProperties) {
InboxPrincipal inboxPrincipal = new InboxPrincipal(true, "IntegrationEventQueueAppId");
List<ClaimExtractorProperties.KeyPath> clientKey = claimExtractorProperties.getMapping().getOrDefault("Client", null);
inboxPrincipal.put(clientKey != null && clientKey.getFirst() != null ? clientKey.getFirst().getType() : "client_id", properties.getAppId());
inboxPrincipal.put("active", "true");
List<ClaimExtractorProperties.KeyPath> notBeforeKey = claimExtractorProperties.getMapping().getOrDefault("NotBefore", null);
inboxPrincipal.put(notBeforeKey != null && notBeforeKey.getFirst() != null ? notBeforeKey.getFirst().getType() :"nbf", Instant.now().minus(30, ChronoUnit.SECONDS).toString());
List<ClaimExtractorProperties.KeyPath> expiresAt = claimExtractorProperties.getMapping().getOrDefault("ExpiresAt", null);
inboxPrincipal.put(expiresAt != null && expiresAt.getFirst() != null ? expiresAt.getFirst().getType() :"exp", Instant.now().plus(10, ChronoUnit.MINUTES).toString());
return inboxPrincipal;
}
@Override @Override
public Boolean isAuthenticated() { public Boolean isAuthenticated() {
return this.isAuthenticated; return this.isAuthenticated;
@ -32,8 +46,12 @@ public class InboxPrincipal implements MyPrincipal, ClaimAccessor {
@Override @Override
public List<String> getClaimAsStringList(String claim) { public List<String> getClaimAsStringList(String claim) {
if (claims == null) return null; if (claims == null)
return this.getClaimAsStringList(claim); return null;
if (this.claims.containsKey(claim)){
return List.of(this.claims.get(claim).toString());
}
return null;
} }
@Override @Override
@ -44,13 +62,4 @@ public class InboxPrincipal implements MyPrincipal, ClaimAccessor {
public void put(String key, Object value) { public void put(String key, Object value) {
this.claims.put(key, value); this.claims.put(key, value);
} }
public static InboxPrincipal build(IntegrationEventProperties properties) {
InboxPrincipal inboxPrincipal = new InboxPrincipal(true, "IntegrationEventQueueAppId");
inboxPrincipal.put("client_id", properties.getAppId());
inboxPrincipal.put("active", "true");
inboxPrincipal.put("nbf", Instant.now().minus(30, ChronoUnit.SECONDS).toString());
inboxPrincipal.put("exp", Instant.now().plus(10, ChronoUnit.MINUTES).toString());
return inboxPrincipal;
}
} }

View File

@ -1,7 +1,5 @@
package eu.eudat.integrationevent.outbox.tenanttouched; package eu.eudat.integrationevent.outbox.tenanttouched;
import javax.management.InvalidApplicationException;
public interface TenantTouchedIntegrationEventHandler { public interface TenantTouchedIntegrationEventHandler {
void handle(TenantTouchedIntegrationEvent event); void handle(TenantTouchedIntegrationEvent event);

View File

@ -1,10 +1,15 @@
package eu.eudat.integrationevent.outbox.tenanttouched; package eu.eudat.integrationevent.outbox.tenanttouched;
import eu.eudat.commons.scope.tenant.TenantScope;
import eu.eudat.integrationevent.outbox.OutboxIntegrationEvent; import eu.eudat.integrationevent.outbox.OutboxIntegrationEvent;
import eu.eudat.integrationevent.outbox.OutboxService; import eu.eudat.integrationevent.outbox.OutboxService;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import java.util.UUID; import java.util.UUID;
@Component
@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class TenantTouchedIntegrationEventHandlerImpl implements TenantTouchedIntegrationEventHandler { public class TenantTouchedIntegrationEventHandlerImpl implements TenantTouchedIntegrationEventHandler {
private final OutboxService outboxService; private final OutboxService outboxService;

View File

@ -194,7 +194,7 @@ public class TenantUserQuery extends QueryBase<TenantUserEntity> {
@Override @Override
protected String fieldNameOf(FieldResolver item) { protected String fieldNameOf(FieldResolver item) {
if (item.match(TenantUser._id)) return TenantUserEntity._id; if (item.match(TenantUser._id)) return TenantUserEntity._id;
else if (item.match(TenantUser._tenant, Tenant._id)) return TenantUserEntity._tenantId; else if (item.match(TenantUser._tenant)) return TenantUserEntity._tenantId;
else if (item.prefix(TenantUser._tenant)) return TenantUserEntity._tenantId; else if (item.prefix(TenantUser._tenant)) return TenantUserEntity._tenantId;
else if (item.match(TenantUser._isActive)) return TenantUserEntity._isActive; else if (item.match(TenantUser._isActive)) return TenantUserEntity._isActive;
else if (item.match(TenantUser._createdAt)) return TenantUserEntity._createdAt; else if (item.match(TenantUser._createdAt)) return TenantUserEntity._createdAt;

View File

@ -25,6 +25,6 @@ public interface TenantService {
Tenant persist(TenantPersist model, FieldSet fields) throws MyForbiddenException, MyValidationException, MyApplicationException, MyNotFoundException, InvalidApplicationException, Tenant persist(TenantPersist model, FieldSet fields) throws MyForbiddenException, MyValidationException, MyApplicationException, MyNotFoundException, InvalidApplicationException,
InvalidAlgorithmParameterException, NoSuchPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException, BadPaddingException, InvalidKeyException; InvalidAlgorithmParameterException, NoSuchPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException, BadPaddingException, InvalidKeyException;
Tenant decryptTenant(Tenant model) throws InvalidAlgorithmParameterException, NoSuchPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException, BadPaddingException, InvalidKeyException; Tenant decryptTenant(Tenant model) throws InvalidAlgorithmParameterException, NoSuchPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException, BadPaddingException, InvalidKeyException, InvalidApplicationException;
void deleteAndSave(UUID id) throws MyForbiddenException, InvalidApplicationException; void deleteAndSave(UUID id) throws MyForbiddenException, InvalidApplicationException;
} }

View File

@ -9,6 +9,10 @@ import eu.eudat.convention.ConventionService;
import eu.eudat.data.TenantEntity; import eu.eudat.data.TenantEntity;
import eu.eudat.data.TenantEntityManager; import eu.eudat.data.TenantEntityManager;
import eu.eudat.errorcode.ErrorThesaurusProperties; import eu.eudat.errorcode.ErrorThesaurusProperties;
import eu.eudat.integrationevent.outbox.tenantremoval.TenantRemovalIntegrationEvent;
import eu.eudat.integrationevent.outbox.tenantremoval.TenantRemovalIntegrationEventHandler;
import eu.eudat.integrationevent.outbox.tenanttouched.TenantTouchedIntegrationEvent;
import eu.eudat.integrationevent.outbox.tenanttouched.TenantTouchedIntegrationEventHandler;
import eu.eudat.model.Tenant; import eu.eudat.model.Tenant;
import eu.eudat.model.builder.TenantBuilder; import eu.eudat.model.builder.TenantBuilder;
import eu.eudat.model.deleter.TenantDeleter; import eu.eudat.model.deleter.TenantDeleter;
@ -67,18 +71,20 @@ public class TenantServiceImpl implements TenantService {
private final EncryptionService encryptionService; private final EncryptionService encryptionService;
private final TenantProperties properties; private final TenantProperties properties;
private final TenantTouchedIntegrationEventHandler tenantTouchedIntegrationEventHandler;
private final TenantRemovalIntegrationEventHandler tenantRemovalIntegrationEventHandler;
@Autowired @Autowired
public TenantServiceImpl( public TenantServiceImpl(
TenantEntityManager entityManager, TenantEntityManager entityManager,
AuthorizationService authorizationService, AuthorizationService authorizationService,
DeleterFactory deleterFactory, DeleterFactory deleterFactory,
BuilderFactory builderFactory, BuilderFactory builderFactory,
ConventionService conventionService, ConventionService conventionService,
MessageSource messageSource, MessageSource messageSource,
XmlHandlingService xmlHandlingService, XmlHandlingService xmlHandlingService,
ErrorThesaurusProperties errors, ErrorThesaurusProperties errors,
EncryptionService encryptionService, TenantProperties properties) { EncryptionService encryptionService, TenantProperties properties, TenantTouchedIntegrationEventHandler tenantTouchedIntegrationEventHandler, TenantRemovalIntegrationEventHandler tenantRemovalIntegrationEventHandler) {
this.entityManager = entityManager; this.entityManager = entityManager;
this.authorizationService = authorizationService; this.authorizationService = authorizationService;
this.deleterFactory = deleterFactory; this.deleterFactory = deleterFactory;
@ -89,6 +95,8 @@ public class TenantServiceImpl implements TenantService {
this.errors = errors; this.errors = errors;
this.encryptionService = encryptionService; this.encryptionService = encryptionService;
this.properties = properties; this.properties = properties;
this.tenantTouchedIntegrationEventHandler = tenantTouchedIntegrationEventHandler;
this.tenantRemovalIntegrationEventHandler = tenantRemovalIntegrationEventHandler;
} }
@Override @Override
@ -124,6 +132,11 @@ public class TenantServiceImpl implements TenantService {
this.entityManager.flush(); this.entityManager.flush();
TenantTouchedIntegrationEvent tenantTouchedIntegrationEvent = new TenantTouchedIntegrationEvent();
tenantTouchedIntegrationEvent.setId(data.getId());
tenantTouchedIntegrationEvent.setCode(data.getCode());
this.tenantTouchedIntegrationEventHandler.handle(tenantTouchedIntegrationEvent);
return this.builderFactory.builder(TenantBuilder.class).authorize(AuthorizationFlags.OwnerOrDmpAssociatedOrPermission).build(BaseFieldSet.build(fields, Tenant._id), data); return this.builderFactory.builder(TenantBuilder.class).authorize(AuthorizationFlags.OwnerOrDmpAssociatedOrPermission).build(BaseFieldSet.build(fields, Tenant._id), data);
} }
@ -185,17 +198,25 @@ public class TenantServiceImpl implements TenantService {
} }
@Override @Override
public Tenant decryptTenant(Tenant model) throws InvalidAlgorithmParameterException, NoSuchPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException, BadPaddingException, InvalidKeyException { public Tenant decryptTenant(Tenant model) throws InvalidAlgorithmParameterException, NoSuchPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException, BadPaddingException, InvalidKeyException, InvalidApplicationException {
if (model.getConfig() != null && model.getConfig().getDeposit() != null && model.getConfig().getDeposit().getSources() != null) { if (model.getConfig() != null && model.getConfig().getDeposit() != null && model.getConfig().getDeposit().getSources() != null) {
for (TenantSource source : model.getConfig().getDeposit().getSources().stream().collect(Collectors.toList())) { for (TenantSource source : model.getConfig().getDeposit().getSources().stream().toList()) {
source.setClientSecret(this.encryptionService.decryptAES(source.getClientSecret(), properties.getConfigEncryptionAesKey(), properties.getConfigEncryptionAesIv())); source.setClientSecret(this.encryptionService.decryptAES(source.getClientSecret(), properties.getConfigEncryptionAesKey(), properties.getConfigEncryptionAesIv()));
} }
} }
if (model.getConfig() != null && model.getConfig().getFileTransformers() != null && model.getConfig().getFileTransformers().getSources() != null) { if (model.getConfig() != null && model.getConfig().getFileTransformers() != null && model.getConfig().getFileTransformers().getSources() != null) {
for (TenantSource source : model.getConfig().getFileTransformers().getSources().stream().collect(Collectors.toList())) { for (TenantSource source : model.getConfig().getFileTransformers().getSources().stream().toList()) {
source.setClientSecret(this.encryptionService.decryptAES(source.getClientSecret(), properties.getConfigEncryptionAesKey(), properties.getConfigEncryptionAesIv())); source.setClientSecret(this.encryptionService.decryptAES(source.getClientSecret(), properties.getConfigEncryptionAesKey(), properties.getConfigEncryptionAesIv()));
} }
} }
TenantEntity data = this.entityManager.find(TenantEntity.class, model.getId());
if (data == null) throw new MyNotFoundException(messageSource.getMessage("General_ItemNotFound", new Object[]{model.getId(), Tenant.class.getSimpleName()}, LocaleContextHolder.getLocale()));
TenantTouchedIntegrationEvent tenantTouchedIntegrationEvent = new TenantTouchedIntegrationEvent();
tenantTouchedIntegrationEvent.setId(data.getId());
tenantTouchedIntegrationEvent.setCode(data.getCode());
this.tenantTouchedIntegrationEventHandler.handle(tenantTouchedIntegrationEvent);
return model; return model;
} }
@ -206,6 +227,10 @@ public class TenantServiceImpl implements TenantService {
this.authorizationService.authorizeForce(Permission.DeleteTenant); this.authorizationService.authorizeForce(Permission.DeleteTenant);
this.deleterFactory.deleter(TenantDeleter.class).deleteAndSaveByIds(List.of(id)); this.deleterFactory.deleter(TenantDeleter.class).deleteAndSaveByIds(List.of(id));
TenantRemovalIntegrationEvent tenantRemovalIntegrationEvent = new TenantRemovalIntegrationEvent();
tenantRemovalIntegrationEvent.setId(id);
this.tenantRemovalIntegrationEventHandler.handle(tenantRemovalIntegrationEvent);
} }
} }

View File

@ -26,6 +26,7 @@ import org.springframework.security.web.authentication.preauth.AbstractPreAuthen
import jakarta.servlet.Filter; import jakarta.servlet.Filter;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
@ -101,7 +102,7 @@ public class SecurityConfiguration {
//In the example below, the default client handler will be ignored by the resolver //In the example below, the default client handler will be ignored by the resolver
@Override @Override
public List<Class<? extends AuthorizationHandler<? extends AuthorizationRequirement>>> disableHandlers() { public List<Class<? extends AuthorizationHandler<? extends AuthorizationRequirement>>> disableHandlers() {
return List.of(PermissionClientAuthorizationHandler.class); return new ArrayList<>();
} }
}; };
} }

View File

@ -78,7 +78,7 @@ public class TenantController {
} }
@PostMapping("query") @PostMapping("query")
public QueryResult<Tenant> query(@RequestBody TenantLookup lookup) throws MyApplicationException, MyForbiddenException, InvalidAlgorithmParameterException, NoSuchPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException, BadPaddingException, InvalidKeyException { public QueryResult<Tenant> query(@RequestBody TenantLookup lookup) throws MyApplicationException, MyForbiddenException, InvalidAlgorithmParameterException, NoSuchPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException, BadPaddingException, InvalidKeyException, InvalidApplicationException {
logger.debug("querying {}", Tenant.class.getSimpleName()); logger.debug("querying {}", Tenant.class.getSimpleName());
this.censorFactory.censor(TenantCensor.class).censor(lookup.getProject(), null); this.censorFactory.censor(TenantCensor.class).censor(lookup.getProject(), null);
@ -97,7 +97,7 @@ public class TenantController {
} }
@GetMapping("{id}") @GetMapping("{id}")
public Tenant get(@PathVariable("id") UUID id, FieldSet fieldSet) throws MyApplicationException, MyForbiddenException, MyNotFoundException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException, InvalidKeyException { public Tenant get(@PathVariable("id") UUID id, FieldSet fieldSet) throws MyApplicationException, MyForbiddenException, MyNotFoundException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException, InvalidKeyException, InvalidApplicationException {
logger.debug(new MapLogEntry("retrieving" + Tenant.class.getSimpleName()).And("id", id).And("fields", fieldSet)); logger.debug(new MapLogEntry("retrieving" + Tenant.class.getSimpleName()).And("id", id).And("fields", fieldSet));
this.censorFactory.censor(TenantCensor.class).censor(fieldSet, null); this.censorFactory.censor(TenantCensor.class).censor(fieldSet, null);