/// <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) { _entityManager.EnterReadLock(); try { var root = _entityManager.GetEntitySafe(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 { _entityManager.ExitReadLock(); } }
public Dictionary <PermissionTypeBase, int> GetExplicitPermissionsInSubtree(SecurityContext context, int entityId, int[] identities, bool includeRoot) { _entityManager.EnterReadLock(); try { var counters = new int[PermissionTypeBase.PermissionCount]; var root = _entityManager.GetEntitySafe(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 broken, 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, EntryType.Normal), localBits); } // adding explicit identities CollectPermissionsFromAces(context.Evaluator.GetExplicitEntriesSafe(entity.Id, identities, EntryType.Normal), 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 { _entityManager.ExitReadLock(); } }
internal PermissionValue GetSubtreePermission(int userId, int entityId, int ownerId, params PermissionTypeBase[] permissions) { if (userId == _systemUserId) { return(PermissionValue.Allowed); } var identities = GetIdentities(userId, ownerId, entityId); _entityManager.EnterReadLock(); try { var entity = _entityManager.GetEntitySafe(entityId, true); var firstAcl = _entityManager.GetFirstAclSafe(entityId, true); //======== #1: start bits: get permission bits //==> 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 // ReSharper disable once LoopCanBeConvertedToQuery foreach (var ace in relevantAces) { deny |= ace.DenyBits; } if ((deny & mask) != 0uL) { return(PermissionValue.Denied); } } else { // if broken, 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 { _entityManager.ExitReadLock(); } return(PermissionValue.Allowed); }