Multi-Tenancy for Laravel and Laravel-Doctrine.

This library provides the necessary infra-structure for a complex multi-tenant application. Multi-tenancy allows an application to be silo'd into protected areas by some form of tenant identifier. This could be by sub-domain, URL parameter or some other scheme.

Article image for: Multi-Tenancy for Laravel and Laravel-Doctrine

Security Models.

Terminology
Types of Tenancy
Getting Started
Security Models
Routing
Middleware & Views
Issues / Links

Github Print

Security Models

The security model defines how data within a tenant owner should be shared. The default is no sharing at all. In fact the security model only applies when the User implements the BelongsToTenantParticipants and there can be multiple tenants on one user.

Shared

In this situation, the tenant owner may decide that any data can be shared by all child tenants of the owner. This model is called "shared" and means that all data in the tenant owner is available to all tenant creators at any time.

To set the security model, simply save the TenantParticipant instance with the security model set to: TenantSecurityModel::SHARED()

Behind the scenes, when the TenantAwareRepository is queried, the current Tenant information is extracted and the query builder instance modified to set the tenant owner and/or creator. For shared data, only the owner is set.

The other pre-built models are:

  • user
  • closed
  • inherit

User

The User model restricts the queries to the current tenant owner and any mapped tenant. So if a User has 4 child tenants, they will be able to access the data created only by those 4 child tenants. All other data will be excluded.

Closed

If the security model is set to closed, then all queries are created with the tenant owner and current creator only. The user in this scheme, even with multiple tenant creators, will only ever see data that was created by the current creator.

Inherit

Inherit allows the security model to be adopted from a parent tenant. If the parent model is inherit, or there is no parent then the model will be set to closed automatically. This library attempts to favour least access whenever possible.

Applying / Adding Security Models

The security model rules are applied by methods within the TenantAwareRepository. The model name is capitalised, prefixed with "apply" and suffixed with SecurityModel so "shared" becomes "applySharedSecurityModel".

This is why an App level repository is strongly suggested as you can then implement your own security models simply by extending the TenantSecurityModel, defining some new constants and then adding the appropriate method in your App repository.

For example: say you want to have a "global" policy where all unowned data is shared all over but you also have your own data that is private to your tenant, you could add this as a new method:

class AppTenantAwareRepository extends TenantAwareRepository
{

    protected function applyGlobalSecurityModel(QueryBuilder $qb, $alias)
    {
        $qb
            ->where("({$alias}.tenantOwnerId IS NULL OR {$alias}.tenantOwnerId = :tenantOwnerId)")
            ->setParameters([
                ':tenantOwnerId' => $this->tenant->getTenantOwnerId(),
            ])
        ;
    }
}

Additional schemes can be added as needed.

Note: while in theory you can mix security models within a tenant e.g.: some children are closed, others shared, some user; this may result in strange results or inconsistencies. It may lead to a large increase in duplicate records. It is up to you to manage this accordingly.