Webiant Logo Webiant Logo
  1. No results found.

    Try your search with a different keyword or use * as a wildcard.

AclService.cs

using Nop.Core;
using Nop.Core.Caching;
using Nop.Core.Domain.Catalog;
using Nop.Core.Domain.Customers;
using Nop.Core.Domain.Security;
using Nop.Data;
using Nop.Services.Customers;

namespace Nop.Services.Security;

/// 
/// ACL service
/// 
public partial class AclService : IAclService
{
    #region Fields

    protected readonly CatalogSettings _catalogSettings;
    protected readonly ICustomerService _customerService;
    protected readonly IRepository _aclRecordRepository;
    protected readonly IStaticCacheManager _staticCacheManager;
    protected readonly IWorkContext _workContext;

    #endregion

    #region Ctor

    public AclService(CatalogSettings catalogSettings,
        ICustomerService customerService,
        IRepository aclRecordRepository,
        IStaticCacheManager staticCacheManager,
        IWorkContext workContext)
    {
        _catalogSettings = catalogSettings;
        _customerService = customerService;
        _aclRecordRepository = aclRecordRepository;
        _staticCacheManager = staticCacheManager;
        _workContext = workContext;
    }

    #endregion

    #region Utilities

    /// 
    /// Inserts an ACL record
    /// 
    /// ACL record
    /// A task that represents the asynchronous operation
    protected virtual async Task InsertAclRecordAsync(AclRecord aclRecord)
    {
        await _aclRecordRepository.InsertAsync(aclRecord);
    }

    /// 
    /// Get a value indicating whether any ACL records exist for entity type are related to customer roles
    /// 
    /// Type of entity that supports the ACL
    /// 
    /// A task that represents the asynchronous operation
    /// The task result contains true if exist; otherwise false
    /// 
    protected virtual async Task IsEntityAclMappingExistAsync() where TEntity : BaseEntity, IAclSupported
    {
        var entityName = typeof(TEntity).Name;
        var key = _staticCacheManager.PrepareKeyForDefaultCache(NopSecurityDefaults.EntityAclRecordExistsCacheKey, entityName);

        var query = from acl in _aclRecordRepository.Table
            where acl.EntityName == entityName
            select acl;

        return await _staticCacheManager.GetAsync(key, query.Any);
    }

    #endregion

    #region Methods

    /// 
    /// Apply ACL to the passed query
    /// 
    /// Type of entity that supports the ACL
    /// Query to filter
    /// Customer
    /// 
    /// A task that represents the asynchronous operation
    /// The task result contains the filtered query
    /// 
    public virtual async Task> ApplyAcl(IQueryable query, Customer customer)
        where TEntity : BaseEntity, IAclSupported
    {
        ArgumentNullException.ThrowIfNull(query);

        ArgumentNullException.ThrowIfNull(customer);

        var customerRoleIds = await _customerService.GetCustomerRoleIdsAsync(customer);
        return await ApplyAcl(query, customerRoleIds);
    }

    /// 
    /// Apply ACL to the passed query
    /// 
    /// Type of entity that supports the ACL
    /// Query to filter
    /// Identifiers of customer's roles
    /// 
    /// A task that represents the asynchronous operation
    /// The task result contains the filtered query
    /// 
    public virtual async Task> ApplyAcl(IQueryable query, int[] customerRoleIds)
        where TEntity : BaseEntity, IAclSupported
    {
        ArgumentNullException.ThrowIfNull(query);

        ArgumentNullException.ThrowIfNull(customerRoleIds);

        if (!customerRoleIds.Any() || _catalogSettings.IgnoreAcl || !await IsEntityAclMappingExistAsync())
            return query;

        return from entity in query
            where !entity.SubjectToAcl || _aclRecordRepository.Table.Any(acl =>
                acl.EntityName == typeof(TEntity).Name && acl.EntityId == entity.Id && customerRoleIds.Contains(acl.CustomerRoleId))
            select entity;
    }

    /// 
    /// Deletes an ACL record
    /// 
    /// ACL record
    /// A task that represents the asynchronous operation
    public virtual async Task DeleteAclRecordAsync(AclRecord aclRecord)
    {
        await _aclRecordRepository.DeleteAsync(aclRecord);
    }

    /// 
    /// Gets ACL records
    /// 
    /// Type of entity that supports the ACL
    /// Entity
    /// 
    /// A task that represents the asynchronous operation
    /// The task result contains the aCL records
    /// 
    public virtual async Task> GetAclRecordsAsync(TEntity entity) where TEntity : BaseEntity, IAclSupported
    {
        ArgumentNullException.ThrowIfNull(entity);

        var entityId = entity.Id;
        var entityName = entity.GetType().Name;

        var query = from ur in _aclRecordRepository.Table
            where ur.EntityId == entityId &&
                  ur.EntityName == entityName
            select ur;
        var aclRecords = await query.ToListAsync();

        return aclRecords;
    }

    /// 
    /// Inserts an ACL record
    /// 
    /// Type of entity that supports the ACL
    /// Entity
    /// Customer role id
    /// A task that represents the asynchronous operation
    public virtual async Task InsertAclRecordAsync(TEntity entity, int customerRoleId) where TEntity : BaseEntity, IAclSupported
    {
        ArgumentNullException.ThrowIfNull(entity);

        if (customerRoleId == 0)
            throw new ArgumentOutOfRangeException(nameof(customerRoleId));

        var entityId = entity.Id;
        var entityName = entity.GetType().Name;

        var aclRecord = new AclRecord
        {
            EntityId = entityId,
            EntityName = entityName,
            CustomerRoleId = customerRoleId
        };

        await InsertAclRecordAsync(aclRecord);
    }

    /// 
    /// Find customer role identifiers with granted access
    /// 
    /// Type of entity that supports the ACL
    /// Entity
    /// 
    /// A task that represents the asynchronous operation
    /// The task result contains the customer role identifiers
    /// 
    public virtual async Task GetCustomerRoleIdsWithAccessAsync(TEntity entity) where TEntity : BaseEntity, IAclSupported
    {
        ArgumentNullException.ThrowIfNull(entity);

        var entityId = entity.Id;
        var entityName = entity.GetType().Name;

        var key = _staticCacheManager.PrepareKeyForDefaultCache(NopSecurityDefaults.AclRecordCacheKey, entityId, entityName);

        var query = from ur in _aclRecordRepository.Table
            where ur.EntityId == entityId &&
                  ur.EntityName == entityName
            select ur.CustomerRoleId;

        return await _staticCacheManager.GetAsync(key, () => query.ToArray());
    }

    /// 
    /// Authorize ACL permission
    /// 
    /// Type of entity that supports the ACL
    /// Entity
    /// 
    /// A task that represents the asynchronous operation
    /// The task result contains true - authorized; otherwise, false
    /// 
    public virtual async Task AuthorizeAsync(TEntity entity) where TEntity : BaseEntity, IAclSupported
    {
        return await AuthorizeAsync(entity, await _workContext.GetCurrentCustomerAsync());
    }

    /// 
    /// Authorize ACL permission
    /// 
    /// Type of entity that supports the ACL
    /// Entity
    /// Customer
    /// 
    /// A task that represents the asynchronous operation
    /// The task result contains true - authorized; otherwise, false
    /// 
    public virtual async Task AuthorizeAsync(TEntity entity, Customer customer) where TEntity : BaseEntity, IAclSupported
    {
        if (entity == null)
            return false;

        if (customer == null)
            return false;

        if (_catalogSettings.IgnoreAcl)
            return true;

        if (!entity.SubjectToAcl)
            return true;

        foreach (var role1 in await _customerService.GetCustomerRolesAsync(customer))
        foreach (var role2Id in await GetCustomerRoleIdsWithAccessAsync(entity))
            if (role1.Id == role2Id)
                //yes, we have such permission
                return true;

        //no permission found
        return false;
    }

    #endregion
}