/******************************************************************************************************* Related Identities */ public static IEnumerable <int> GetRelatedIdentities(SecurityContext context, int entityId, PermissionLevel level) { var identities = new List <int>(); SecurityEntity.EnterReadLock(); try { var root = SecurityEntity.GetEntitySafe(context, entityId, true); foreach (var entity in new EntityTreeWalker(root)) { // step forward if there is no any setting if (!entity.HasExplicitAcl) { continue; } // if breaked, adding existing parent-s effective identities because all identities are related. if (!entity.IsInherited && entity.Parent != null) { CollectIdentitiesFromAces(context.Evaluator.GetEffectiveEntriesSafe(entity.Parent.Id), level, identities); } // adding explicite identities CollectIdentitiesFromAces(context.Evaluator.GetExplicitEntriesSafe(entity.Id), level, identities); } } finally { SecurityEntity.ExitReadLock(); } return(identities); }
internal List <AceInfo> GetEffectiveEntries(int entityId, IEnumerable <int> relatedIdentities = null, EntryType?entryType = null) { SecurityEntity.EnterReadLock(); try { return(GetEffectiveEntriesSafe(entityId, relatedIdentities, entryType)); } finally { SecurityEntity.ExitReadLock(); } }
/****************************************************************************************************** Related Permissions */ public static Dictionary <PermissionTypeBase, int> GetRelatedPermissions(SecurityContext context, int entityId, PermissionLevel level, bool explicitOnly, int identityId, Func <int, bool> isEnabled) { if (!explicitOnly) { throw new NotSupportedException("Not supported in this version. Use explicitOnly = true"); } SecurityEntity.EnterReadLock(); try { var counters = new int[PermissionTypeBase.PermissionCount]; var identities = new[] { identityId }; var root = SecurityEntity.GetEntitySafe(context, entityId, true); foreach (var entity in new EntityTreeWalker(root)) { // step forward if there is no any setting if (!entity.HasExplicitAcl) { continue; } if (!isEnabled(entity.Id)) { continue; } // if breaked, adding existing parent-s effective identities because all identities are related. var localBits = new PermissionBitMask(); if (!entity.IsInherited && entity.Parent != null) { CollectPermissionsFromLocalAces(context.Evaluator.GetEffectiveEntriesSafe(entity.Parent.Id, identities), localBits); } // adding explicite identities CollectPermissionsFromAces(context.Evaluator.GetExplicitEntriesSafe(entity.Id, identities), level, counters, localBits); } var result = new Dictionary <PermissionTypeBase, int>(); for (var i = 0; i < PermissionTypeBase.PermissionCount; i++) { result.Add(PermissionTypeBase.GetPermissionTypeByIndex(i), counters[i]); } return(result); } finally { SecurityEntity.ExitReadLock(); } }
/********************************************************************************************************* Related Entities */ public static IEnumerable <int> GetRelatedEntities(SecurityContext context, int entityId, PermissionLevel level, bool explicitOnly, int identityId, IEnumerable <PermissionTypeBase> permissionTypes) { if (!explicitOnly) { throw new NotSupportedException("Not supported in this version. Use explicitOnly = true"); } SecurityEntity.EnterReadLock(); try { var entityIds = new List <int>(); var mask = PermissionTypeBase.GetPermissionMask(permissionTypes); var identities = new[] { identityId }; var root = SecurityEntity.GetEntitySafe(context, entityId, true); foreach (var entity in new EntityTreeWalker(root)) { // step forward if there is no any setting if (!entity.HasExplicitAcl) { continue; } var added = false; if (!entity.IsInherited && entity.Parent != null) { if (HasBitsByEffectiveAces(context.Evaluator.GetEffectiveEntriesSafe(entity.Parent.Id, identities), level, mask)) { entityIds.Add(entity.Id); added = true; } } // adding explicite identities if (!added) { if (HasBitsByExpliciteAces(context.Evaluator.GetExplicitEntriesSafe(entity.Id, identities), level, mask)) { entityIds.Add(entity.Id); } } } return(entityIds); } finally { SecurityEntity.ExitReadLock(); } }
internal PermissionValue GetPermission(int userId, int entityId, int ownerId, EntryType?entryType, params PermissionTypeBase[] permissions) { if (userId == Configuration.Identities.SystemUserId) { return(PermissionValue.Allowed); } SecurityEntity.EnterReadLock(); try { return(GetPermissionSafe(userId, entityId, ownerId, entryType, permissions)); } finally { SecurityEntity.ExitReadLock(); } }
public static Dictionary <PermissionTypeBase, int> GetExplicitPermissionsInSubtree(SecurityContext context, int entityId, int[] identities, bool includeRoot) { SecurityEntity.EnterReadLock(); try { var counters = new int[PermissionTypeBase.PermissionCount]; var root = SecurityEntity.GetEntitySafe(context, entityId, true); foreach (var entity in new EntityTreeWalker(root)) { // step forward if there is no any setting if (!entity.HasExplicitAcl || (entity.Id == entityId && !includeRoot)) { continue; } // if breaked, adding existing parent-s effective identities because all identities are related. var localBits = new PermissionBitMask(); if (!entity.IsInherited && entity.Parent != null && (includeRoot || entity.Parent.Id != entityId)) { CollectPermissionsFromLocalAces(context.Evaluator.GetEffectiveEntriesSafe(entity.Parent.Id, identities), localBits); } // adding explicite identities CollectPermissionsFromAces(context.Evaluator.GetExplicitEntriesSafe(entity.Id, identities), PermissionLevel.AllowedOrDenied, counters, localBits); } var result = new Dictionary <PermissionTypeBase, int>(); for (var i = 0; i < PermissionTypeBase.PermissionCount; i++) { result.Add(PermissionTypeBase.GetPermissionTypeByIndex(i), counters[i]); } return(result); } finally { SecurityEntity.ExitReadLock(); } }
/// <summary> /// Returns all entities in the predefined axis (All, ParentChain, Subtree) of the specified entity. /// The collection is empty if the entity was not found. /// This operation is thread safe. The thread safety uses system resources, so to minimize these, /// it's strongly recommended processing as fast as possible. /// </summary> /// <param name="entityId">The Id of the focused entity.</param> /// <param name="handleBreaks">Controls the permission inheritance handling.</param> /// <returns>The IEnumerable<SecurityEntity> to further filtering.</returns> public IEnumerable <SecurityEntity> GetEntities(int entityId, BreakOptions handleBreaks = BreakOptions.Default) { SecurityEntity.EnterReadLock(); try { var root = SecurityEntity.GetEntitySafe(_context, entityId, false); IEnumerable <SecurityEntity> collection; switch (_axis) { case Axis.All: collection = GetEntitiesFromParentChain(root, handleBreaks) .Union(GetEntitiesFromSubtree(root, handleBreaks)); break; case Axis.ParentChain: collection = GetEntitiesFromParentChain(root, handleBreaks); break; case Axis.Subtree: collection = GetEntitiesFromSubtree(root, handleBreaks); break; default: throw new ArgumentOutOfRangeException("Unknown axis: " + _axis); } foreach (var entity in collection) { yield return(entity); } } finally { SecurityEntity.ExitReadLock(); } }
/********************************************************************************************* Related Entities one level#2 */ public static IEnumerable <int> GetRelatedEntitiesOneLevel(SecurityContext context, int entityId, PermissionLevel level, int identityId, IEnumerable <PermissionTypeBase> permissionTypes) { SecurityEntity.EnterReadLock(); try { var result = new List <int>(); var identities = new[] { identityId }; var mask = PermissionTypeBase.GetPermissionMask(permissionTypes); var root = SecurityEntity.GetEntitySafe(context, entityId, true); foreach (var childEntity in root.Children) { var aces = context.Evaluator.GetEffectiveEntriesSafe(childEntity.Id, identities); if (aces.Any(a => HasBits(a.AllowBits, a.DenyBits, level, mask))) { result.Add(childEntity.Id); } } return(result); } finally { SecurityEntity.ExitReadLock(); } }
internal PermissionValue GetSubtreePermission(int userId, int entityId, int ownerId, params PermissionTypeBase[] permissions) { if (userId == Configuration.Identities.SystemUserId) { return(PermissionValue.Allowed); } var identities = GetIdentities(userId, ownerId, entityId); SecurityEntity.EnterReadLock(); try { var entity = SecurityEntity.GetEntitySafe(_securityContext, entityId, true); var firstAcl = SecurityEntity.GetFirstAclSafe(_securityContext, entityId, true); //======== #1: startbits: getpermbits //==> var allow = 0ul; var deny = 0ul; if (entityId == firstAcl.EntityId) { firstAcl.AggregateLocalOnlyValues(identities, ref allow, ref deny); } for (var permInfo = firstAcl; permInfo != null; permInfo = permInfo.Inherits ? permInfo.Parent : null) { permInfo.AggregateEffectiveValues(identities, ref allow, ref deny); } //==< var mask = PermissionTypeBase.GetPermissionMask(permissions); if ((deny & mask) != 0) { return(PermissionValue.Denied); } if ((allow & mask) != mask) { return(PermissionValue.Undefined); } // doesn't depend from the value of the entity's Inherits (need to evaluate through the breaks) // doesn't depend from the value of the LocalOnly (need to evaluate any entry) foreach (var descendantEntity in new EntityTreeWalker(entity)) { // if nearest holder is different, this entity is irrelevant (there is no entry to evaluate) if (!descendantEntity.HasExplicitAcl) { continue; } // only this level is sufficient to evaluate because any difference from "allow" causes exit instantly // filtered by relevant identities AceInfo[] relevantAces; try { relevantAces = GetExplicitEntriesSafe(descendantEntity.Id, identities).ToArray(); } catch (EntityNotFoundException) // catch only: well known exception { // do nothing because entity was deleted continue; } // different evaluation that depends on the inheritance continuity if (descendantEntity.IsInherited) { // if inherited, only denied bits play foreach (var ace in relevantAces) { deny |= ace.DenyBits; } if ((deny & mask) != 0uL) { return(PermissionValue.Denied); } } else { // if breaked, need to recalculate allow and deny bits too. allow = 0ul; deny = 0ul; var hasLocalOnly = false; // on this level need to explicit "allow" foreach (var ace in relevantAces) { allow |= ace.AllowBits; deny |= ace.DenyBits; hasLocalOnly |= ace.LocalOnly; } // return if inadequate if ((deny & mask) != 0) { return(PermissionValue.Denied); } if ((allow & mask) != mask) { return(PermissionValue.Undefined); } // if there is any local only entry, the children decide to exit or move forward. if (hasLocalOnly) { // move forward if the entity is a leaf (children is null) if (descendantEntity.Children != null) { foreach (var childEntity in descendantEntity.Children) { var value = GetPermissionSafe(userId, childEntity.Id, childEntity.OwnerId, permissions); // return if not allowed if (value != PermissionValue.Allowed) { return(value); } // move forward } } } } // walk forward on the tree } } finally { SecurityEntity.ExitReadLock(); } return(PermissionValue.Allowed); }