Other users data is returned from query
haiderali22 opened this issue · 8 comments
Hi hope you are fine findById is working fine but findAll and count return others users(tennat) data, do i have to also implement does methods in MultiTenancyRepository?
Hi @haiderali22, normally all methods are multi tenant compliant, even findall() and count().
This is because findAll() and count() are using CriteriaBuilder under the hood which applies the hibernate filter.
There is an integration test that should cover this in the InventoryRepositoryTest.
Do you have any data or integration test to reproduce this? Thanks :)
I will try to look into it as well in the evening.
Have a good one :)
I am using using your code in my own project, maybe configuration issue then. Though I resolved it in my own repo with custom query
@Query("select t from #{#entityName} t where t."+AuditTenantEntity.TENANT_FILTER_ARGUMENT_NAME +"= ?#{principal.username}") List<Order> findAll();
principal is my custom implementation of UserDetail
The only thing that i can think about right now, is that a entity which is not owned by the tenant being (left, outer, ...) joined with the entity which is owned by the tenant. This can occur when a .sql migration is executed without checking the tenant_id. Then i could read the joined data (from another tenant) from the owned tenant.
Basically this: https://github.com/M-Devloo/Spring-boot-auth0-discriminator-multitenancy/pull/6/files (Work in progress to mitigate this which i didn't find a proper solution for framework wise yet)
But it is not possible when the data is inserted through the application. Only from third party manipulation.
But according to your own code snippet, it seems like this is a standalone entity?
Your fix is basically exactly the same what the TenantServiceAspect
needs to do for a read operation.
Perhaps this @pointcut is not triggered correctly around the Repository?
Yes you are right pointcut was not triggering , i think due to change i made in it. I changed th eexpression to this @pointcut("execution(public * com.hali.spring.dbauth.repositories..*(..))") so that the repository defined in this package is only considered because i am adding users to application in another repository which are in package com.hali.spring.dbauth.security.repositories (in which i cannot add tennat id)
Glad i could help :)
A good solution for your problem could be to create a custom annotation that says @NotMultiTenant on your repository and extend the @aspect with something like this:
@Around("execution(public * *(..)) && isRepository() && @annotation(NotMultiTenant)") { // ignore multi tenancy }.
This way you reuse the "framework" code and allows you to safely implement your other features while keeping the multi tenancy by default on.
Perhaps i could add this for an enhancement into this project as well
Thankyou for your reply
I tried adding annotaion for disabling certain repository but had no successs. Below is the code
@Slf4j
@Aspect
@Component
public class TenantServiceAspect {
@PersistenceContext public EntityManager entityManager;
@Pointcut("execution(public * org.springframework.data.repository.Repository+.*(..))")
void isRepository() {
/* aspect */
}
@Around("execution(public * *(..)) && isRepository() && !@annotation(com.hali.spring.dbauth.multitenancy.DisableMultiTenant)")
public Object aroundExecution(final ProceedingJoinPoint pjp) throws Throwable {
// if (pjp.getTarget().getClass().isAnnotationPresent(DisableMultiTenant.class)) {
// return pjp.proceed();
// }
final Filter filter =
this.entityManager
.unwrap(Session.class) // requires transaction
.enableFilter(AuditTenantEntity.TENANT_FILTER_NAME)
.setParameter(
AuditTenantEntity.TENANT_FILTER_ARGUMENT_NAME, TenantAssistance.resolveCurrentTenantIdentifier());
filter.validate();
return pjp.proceed();
}
}
@Target({ ElementType.TYPE})
@Inherited
@Retention(RetentionPolicy.RUNTIME)
public @interface DisableMultiTenant {
}
@Around("execution(public * *(..)) && isRepository() ")
public Object aroundExecution(final ProceedingJoinPoint pjp) throws Throwable {
// if (pjp.getTarget().getClass().isAnnotationPresent(DisableMultiTenant.class)) {
// return pjp.proceed();
// }
MergedAnnotation<DisableMultiTenant> annotations = MergedAnnotations.from(pjp.getTarget().getClass(),
SearchStrategy.TYPE_HIERARCHY).get(DisableMultiTenant.class).withNonMergedAttributes();
if(annotations.isPresent())
{
return pjp.proceed();
}
final Filter filter =
this.entityManager
.unwrap(Session.class) // requires transaction
.enableFilter(AuditTenantEntity.TENANT_FILTER_NAME)
.setParameter(
AuditTenantEntity.TENANT_FILTER_ARGUMENT_NAME, TenantAssistance.resolveCurrentTenantIdentifier());
filter.validate();
return pjp.proceed();
}
Change to code above now working fine i think. let me test it further