internal List <AceInfo> GetExplicitEntriesSafe(int entityId, IEnumerable <int> relatedIdentities = null, EntryType?entryType = null) { return(GetExplicitEntriesSafe(entityId, SecurityEntity.GetFirstAclSafe(_securityContext, entityId, true), relatedIdentities, entryType)); }
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); }