using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Threading.Tasks; using Abp; using Abp.Application.Features; using Abp.Authorization; using Abp.Collections.Extensions; using Abp.Domain.Services; using Abp.Domain.Uow; using Abp.Localization; using Abp.MultiTenancy; using Abp.Runtime.Caching; using IwbZero.Authorization.Base.Permissions; using IwbZero.Authorization.Base.Roles; using IwbZero.Authorization.Users; using IwbZero.IdentityFramework; using IwbZero.Runtime.Caching; using IwbZero.Runtime.Session; using IwbZero.Zero.Configuration; using Microsoft.AspNet.Identity; namespace IwbZero.Authorization.Roles { /// /// Extends of ASP.NET Identity Framework. /// Applications should derive this class with appropriate generic arguments. /// public abstract class IwbRoleManager : RoleManager, IDomainService where TRole : IwbSysRole, new() where TUser : IwbSysUser { public ILocalizationManager LocalizationManager { get; set; } protected string LocalizationSourceName { get; set; } public IIwbSession AbpSession { get; set; } public IRoleManagementConfig RoleManagementConfig { get; private set; } public FeatureDependencyContext FeatureDependencyContext { get; set; } private IRolePermissionStore RolePermissionStore { get { if (!(Store is IRolePermissionStore)) { throw new AbpException("Store is not IRolePermissionStore"); } return Store as IRolePermissionStore; } } protected IwbRoleStore IwbStore { get; private set; } protected IPermissionManager PermissionManager { get; } protected ICacheManager CacheManager { get; } protected IUnitOfWorkManager UnitOfWorkManager { get; } //private readonly IRepository _organizationUnitRepository; //private readonly IRepository _organizationUnitRoleRepository; /// /// Constructor. /// protected IwbRoleManager( IwbRoleStore store, IPermissionManager permissionManager, IRoleManagementConfig roleManagementConfig, ICacheManager cacheManager, IUnitOfWorkManager unitOfWorkManager) : base(store) { PermissionManager = permissionManager; CacheManager = cacheManager; UnitOfWorkManager = unitOfWorkManager; RoleManagementConfig = roleManagementConfig; IwbStore = store; AbpSession = NullIwbSession.Instance; LocalizationManager = NullLocalizationManager.Instance; LocalizationSourceName = IwbZeroConsts.LocalizationSourceName; } /// /// Checks if a role is granted for a permission. /// /// The role's name to check it's permission /// Name of the permission /// True, if the role has the permission public virtual async Task IsGrantedAsync(string roleName, string permissionName) { return await IsGrantedAsync((await GetRoleByNameAsync(roleName)).Id, PermissionManager.GetPermission(permissionName)); } /// /// Checks if a role has a permission. /// /// The role's id to check it's permission /// Name of the permission /// True, if the role has the permission public virtual async Task IsGrantedAsync(int roleId, string permissionName) { return await IsGrantedAsync(roleId, PermissionManager.GetPermission(permissionName)); } /// /// Checks if a role is granted for a permission. /// /// The role /// The permission /// True, if the role has the permission public Task IsGrantedAsync(TRole role, Permission permission) { return IsGrantedAsync(role.Id, permission); } /// /// Checks if a role is granted for a permission. /// /// role id /// The permission /// True, if the role has the permission public virtual async Task IsGrantedAsync(int roleId, Permission permission) { //Get cached role permissions var cacheItem = await GetRolePermissionCacheItemAsync(roleId); //Check the permission return cacheItem.GrantedPermissions.Contains(permission.Name); } /// /// Checks if a role is granted for a permission. /// /// role /// /// The permission /// /// True, if the role has the permission public virtual async Task IsGrantedAsync(TRole role, string dataKey, int operType, Permission permission) { return await IsGrantedAsync(role.Id, dataKey, operType, permission.Name); } /// /// Checks if a role is granted for a permission. /// /// role id /// /// The permission /// /// True, if the role has the permission public virtual async Task IsGrantedAsync(int roleId, string dataKey, int operType, Permission permission) { return await IsGrantedAsync(roleId, dataKey, operType, permission.Name); } /// /// Checks if a role is granted for a permission. /// /// role /// /// The permission /// /// True, if the role has the permission public virtual async Task IsGrantedAsync(TRole role, string dataKey, int operType, string permissionName) { return await IsGrantedAsync(role.Id, dataKey, operType, permissionName); } /// /// Checks if a role is granted for a data Permission. /// /// role id /// /// The permission /// /// True, if the role has the permission public virtual async Task IsGrantedAsync(int roleId, string dataKey, int operType, string permissionName) { //Get cached role permissions var cacheItem = await GetRoleDataPermissionCacheItemAsync(roleId); //Check the permission // ReSharper disable once PossibleUnintendedLinearSearchInSet return cacheItem.GrantedPermissions.Contains($"{permissionName}@{dataKey}@{operType}", DataPermissionNameComparer.Instance); } /// /// Gets granted permission names for a role. /// /// Role id /// List of granted permissions public virtual async Task> GetGrantedPermissionsAsync(int roleId) { return await GetGrantedPermissionsAsync(await GetRoleByIdAsync(roleId)); } /// /// Gets granted permission names for a role. /// /// Role name /// List of granted permissions public virtual async Task> GetGrantedPermissionsAsync(string roleName) { return await GetGrantedPermissionsAsync(await GetRoleByNameAsync(roleName)); } /// /// Gets granted permissions for a role. /// /// Role /// List of granted permissions public virtual async Task> GetGrantedPermissionsAsync(TRole role) { var permissionList = new List(); foreach (var permission in PermissionManager.GetAllPermissions()) { if (await IsGrantedAsync(role.Id, permission)) { permissionList.Add(permission); } } return permissionList; } /// /// Sets all granted permissions of a role at once. /// Prohibits all other permissions. /// /// Role id /// Permissions public virtual async Task SetGrantedPermissionsAsync(int roleId, IEnumerable permissions) { await SetGrantedPermissionsAsync(await GetRoleByIdAsync(roleId), permissions); } /// /// Sets all granted permissions of a role at once. /// Prohibits all other permissions. /// /// The role /// Permissions public virtual async Task SetGrantedPermissionsAsync(TRole role, IEnumerable permissions) { var oldPermissions = await GetGrantedPermissionsAsync(role); var newPermissions = permissions.ToArray(); foreach (var permission in oldPermissions.Where(p => !newPermissions.Contains(p, PermissionEqualityComparer.Instance))) { //await ProhibitPermissionAsync(role, permission); await RemovePermissionAsync(role, permission); } foreach (var permission in newPermissions.Where(p => !oldPermissions.Contains(p, PermissionEqualityComparer.Instance))) { await GrantPermissionAsync(role, permission); } } /// /// Grants a permission for a role. /// /// Role /// Permission public async Task GrantPermissionAsync(TRole role, Permission permission) { if (await IsGrantedAsync(role.Id, permission)) { return; } await RolePermissionStore.RemovePermissionAsync(role, new PermissionGrantInfo(permission.Name, false)); await RolePermissionStore.AddPermissionAsync(role, new PermissionGrantInfo(permission.Name, true)); await SetGrantedPermissionCacheItem(role.Id, permission.Name); } /// /// Prohibits a permission for a role. /// /// Role /// Permission public async Task ProhibitPermissionAsync(TRole role, Permission permission) { if (!await IsGrantedAsync(role.Id, permission)) { return; } await RolePermissionStore.RemovePermissionAsync(role, new PermissionGrantInfo(permission.Name, true)); await RolePermissionStore.AddPermissionAsync(role, new PermissionGrantInfo(permission.Name, false)); await SetGrantedPermissionCacheItem(role.Id, permission.Name, false); } /// /// Prohibits a permission for a role. /// /// Role /// Permission public async Task RemovePermissionAsync(TRole role, Permission permission) { if (!await IsGrantedAsync(role.Id, permission)) { return; } await RolePermissionStore.RemovePermissionAsync(role, new PermissionGrantInfo(permission.Name, true)); await SetGrantedPermissionCacheItem(role.Id, permission.Name, false); } /// /// Prohibits all permissions for a role. /// /// Role public async Task ProhibitAllPermissionsAsync(TRole role) { foreach (var permission in PermissionManager.GetAllPermissions()) { await ProhibitPermissionAsync(role, permission); } } private async Task SetGrantedPermissionCacheItem(int roleId, string permissionName, bool isAdded = true) { var permissionCacheItem = await GetRolePermissionCacheItemAsync(roleId); if (isAdded) permissionCacheItem.GrantedPermissions.AddIfNotContains(permissionName); else permissionCacheItem.GrantedPermissions.Remove(permissionName); } /// /// Resets all permission settings for a role. /// It removes all permission settings for the role. /// /// Role public async Task ResetAllPermissionsAsync(TRole role) { await RolePermissionStore.RemoveAllPermissionSettingsAsync(role); } /// /// Creates a role. /// /// Role public override async Task CreateAsync(TRole role) { role.SetNormalizedName(); var result = await CheckDuplicateRoleNameAsync(role.Id, role.Name, role.DisplayName); if (!result.Succeeded) { return result; } var tenantId = GetCurrentTenantId(); if (tenantId.HasValue && !role.TenantId.HasValue) { role.TenantId = tenantId.Value; } return await base.CreateAsync(role); } public override async Task UpdateAsync(TRole role) { role.SetNormalizedName(); var result = await CheckDuplicateRoleNameAsync(role.Id, role.Name, role.DisplayName); if (!result.Succeeded) { return result; } return await base.UpdateAsync(role); } /// /// Deletes a role. /// /// Role public override async Task DeleteAsync(TRole role) { if (role.IsStatic) { return AbpIdentityResult.Failed(string.Format(L("CanNotDeleteStaticRole"), role.Name)); } return await base.DeleteAsync(role); } /// /// Gets a role by given id. /// Throws exception if no role with given id. /// /// Role id /// Role /// Throws exception if no role with given id public virtual async Task GetRoleByIdAsync(int roleId) { var role = await FindByIdAsync(roleId); if (role == null) { throw new AbpException("There is no role with id: " + roleId); } return role; } /// /// Gets a role by given name. /// Throws exception if no role with given roleName. /// /// Role name /// Role /// Throws exception if no role with given roleName public virtual async Task GetRoleByNameAsync(string roleName) { var role = await FindByNameAsync(roleName); if (role == null) { throw new AbpException("There is no role with name: " + roleName); } return role; } public async Task GrantAllPermissionsAsync(TRole role) { FeatureDependencyContext.TenantId = role.TenantId; var permissions = PermissionManager.GetAllPermissions(role.GetMultiTenancySide()) .Where(permission => permission.FeatureDependency == null || permission.FeatureDependency.IsSatisfied(FeatureDependencyContext) ); await SetGrantedPermissionsAsync(role, permissions); } [UnitOfWork] public virtual async Task CreateStaticRoles(int tenantId) { var staticRoleDefinitions = RoleManagementConfig.StaticRoles.Where(sr => sr.Side == MultiTenancySides.Tenant); using (UnitOfWorkManager.Current.SetTenantId(tenantId)) { foreach (var staticRoleDefinition in staticRoleDefinitions) { var role = new TRole { TenantId = tenantId, Name = staticRoleDefinition.RoleName, DisplayName = staticRoleDefinition.RoleName, AccountType = 1, RoleType = 0, IsStatic = true }; role.SetNormalizedName(); var identityResult = await CreateAsync(role); if (!identityResult.Succeeded) { return identityResult; } } } return IdentityResult.Success; } [UnitOfWork] public virtual async Task CreateStaticRoles(int tenantId, TRole role) { var staticRoleDefinitions = RoleManagementConfig.StaticRoles.Where(sr => sr.Side == MultiTenancySides.Tenant); using (UnitOfWorkManager.Current.SetTenantId(tenantId)) { foreach (var staticRoleDefinition in staticRoleDefinitions) { role.TenantId = tenantId; role.Name = staticRoleDefinition.RoleName; role.DisplayName = staticRoleDefinition.RoleName; role.IsStatic = true; role.SetNormalizedName(); var identityResult = await CreateAsync(role); if (!identityResult.Succeeded) { return identityResult; } } } return IdentityResult.Success; } public virtual async Task CheckDuplicateRoleNameAsync(int? expectedRoleId, string name, string displayName) { var role = await FindByNameAsync(name); if (role != null && role.Id != expectedRoleId) { return AbpIdentityResult.Failed(string.Format(L("RoleNameIsAlreadyTaken"), name)); } role = await FindByDisplayNameAsync(displayName); if (role != null && role.Id != expectedRoleId) { return AbpIdentityResult.Failed(string.Format(L("RoleDisplayNameIsAlreadyTaken"), displayName)); } return IdentityResult.Success; } private Task FindByDisplayNameAsync(string displayName) { return IwbStore.FindByDisplayNameAsync(displayName); } private async Task GetRolePermissionCacheItemAsync(int roleId) { var cacheKey = roleId + "@" + (GetCurrentTenantId() ?? 0); return await CacheManager.GetRolePermissionCache().GetAsync(cacheKey, async () => { var newCacheItem = new RolePermissionCacheItem(roleId); var role = await Store.FindByIdAsync(roleId); if (role == null) { throw new AbpException("There is no role with given id: " + roleId); } var staticRoleDefinition = RoleManagementConfig.StaticRoles.FirstOrDefault(r => r.RoleName == role.Name && r.Side == role.GetMultiTenancySide()); if (staticRoleDefinition != null) { foreach (var permission in PermissionManager.GetAllPermissions()) { if (staticRoleDefinition.IsGrantedByDefault(permission)) { newCacheItem.GrantedPermissions.Add(permission.Name); } } } foreach (var permissionInfo in await RolePermissionStore.GetPermissionsAsync(roleId)) { if (permissionInfo.IsGranted) { newCacheItem.GrantedPermissions.AddIfNotContains(permissionInfo.Name); } else { newCacheItem.GrantedPermissions.Remove(permissionInfo.Name); } } return newCacheItem; }); } private async Task GetRoleDataPermissionCacheItemAsync(int roleId) { var cacheKey = $"Data-{roleId}@{GetCurrentTenantId() ?? 0}"; return await CacheManager.GetRolePermissionCache().GetAsync(cacheKey, async () => { var newCacheItem = new RolePermissionCacheItem(roleId); var role = await Store.FindByIdAsync(roleId); if (role == null) { throw new AbpException("There is no role with given id: " + roleId); } foreach (var permissionInfo in await RolePermissionStore.GetPermissionsAsync(roleId)) { if (permissionInfo.IsGranted) { if (permissionInfo.OperType == 1) { newCacheItem.GrantedPermissions.AddIfNotContains($"{permissionInfo.Name}@{permissionInfo.DataKey}@{(int)OperType.Create}"); newCacheItem.GrantedPermissions.AddIfNotContains($"{permissionInfo.Name}@{permissionInfo.DataKey}@{(int)OperType.Update}"); newCacheItem.GrantedPermissions.AddIfNotContains($"{permissionInfo.Name}@{permissionInfo.DataKey}@{(int)OperType.Delete}"); newCacheItem.GrantedPermissions.AddIfNotContains($"{permissionInfo.Name}@{permissionInfo.DataKey}@{(int)OperType.Query}"); } else { newCacheItem.GrantedPermissions.AddIfNotContains($"{permissionInfo.Name}@{permissionInfo.DataKey}@{permissionInfo.OperType}"); } } else { newCacheItem.GrantedPermissions.Remove($"{permissionInfo.Name}@{permissionInfo.DataKey}@{permissionInfo.OperType}"); } } return newCacheItem; }); } protected virtual string L(string name) { return LocalizationManager.GetString(LocalizationSourceName, name); } protected virtual string L(string name, CultureInfo cultureInfo) { return LocalizationManager.GetString(LocalizationSourceName, name, cultureInfo); } private int? GetCurrentTenantId() { if (UnitOfWorkManager.Current != null) { return UnitOfWorkManager.Current.GetTenantId(); } return AbpSession.TenantId; } } }