private void AggregateAffectedPermissions(PermissionTypeBase permission, AggregationType aggregationType, Dictionary <int, PermissionTypeBase> aggregation) { if (aggregation.ContainsKey(permission.Index)) { return; } aggregation[permission.Index] = permission; PermissionTypeBase[] morePermissions; switch (aggregationType) { case AggregationType.Allow: morePermissions = permission.Allows; break; case AggregationType.Deny: morePermissions = permission.Denies.ToArray(); break; default: throw new NotSupportedException("Unknown AggregationType: " + aggregationType); } if (morePermissions?.Length > 0) { foreach (var perm in morePermissions) { if (perm != null) { AggregateAffectedPermissions(perm, aggregationType, aggregation); } } } }
/**************************************************************************************************** Related Identities #2 */ public static IEnumerable <int> GetRelatedIdentities(SecurityContext context, int entityId, PermissionLevel level, IEnumerable <PermissionTypeBase> permissionTypes) { SecurityEntity.EnterReadLock(); try { var identities = new List <int>(); var mask = PermissionTypeBase.GetPermissionMask(permissionTypes); 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, mask, identities); } // adding explicite identities CollectIdentitiesFromAces(context.Evaluator.GetExplicitEntriesSafe(entity.Id), level, mask, identities); } return(identities); } finally { SecurityEntity.ExitReadLock(); } }
internal void ToString(StringBuilder sb) { // +U1:____++++ sb.Append(LocalOnly ? '-':'+'); sb.Append("(" + IdentityId + ")"); sb.Append(':'); var chars = new char[PermissionTypeBase.PermissionCount]; for (var i = 0; i < chars.Length; i++) { chars[i] = '_'; } foreach (var perm in Permissions) { var index = PermissionTypeBase.PermissionCount - PermissionTypeBase.GetPermissionTypeByName(perm.Name).Index - 1; if (perm.Deny) { chars[index] = '-'; } if (perm.Allow) { chars[index] = '+'; } } sb.Append(chars); }
internal PermissionValue GetPermissionSafe(int userId, int entityId, int ownerId, EntryType?entryType, params PermissionTypeBase[] permissions) { if (userId == Configuration.Identities.SystemUserId) { return(PermissionValue.Allowed); } //==> var identities = GetIdentities(userId, ownerId, entityId); var allow = 0ul; var deny = 0ul; var firstAcl = SecurityEntity.GetFirstAclSafe(_securityContext, entityId, true); if (firstAcl == null) { return(PermissionValue.Undefined); } if (entryType == null) { if (entityId == firstAcl.EntityId) { firstAcl.AggregateLocalOnlyValues(identities, ref allow, ref deny); } for (var aclInfo = firstAcl; aclInfo != null; aclInfo = aclInfo.Inherits ? aclInfo.Parent : null) { aclInfo.AggregateEffectiveValues(identities, ref allow, ref deny); } } else { if (entityId == firstAcl.EntityId) { firstAcl.AggregateLocalOnlyValues(identities, entryType.Value, ref allow, ref deny); } for (var aclInfo = firstAcl; aclInfo != null; aclInfo = aclInfo.Inherits ? aclInfo.Parent : null) { aclInfo.AggregateEffectiveValues(identities, entryType.Value, ref allow, ref deny); } } //==< var mask = PermissionTypeBase.GetPermissionMask(permissions); if ((deny & mask) != 0) { return(PermissionValue.Denied); } if ((allow & mask) != mask) { return(PermissionValue.Undefined); } return(PermissionValue.Allowed); }
/****************************************************************************************************** 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(); } }
private static void IncrementCounters(ulong bits, int[] counters) { var mask = 1uL; var b = bits; foreach (var pt in PermissionTypeBase.GetPermissionTypes()) { if ((b & mask) > 0) { counters[pt.Index]++; } mask = mask << 1; } }
private AccessControlEntry CreateEmptyAce(AceInfo aceInfo) { var perms = new Permission[PermissionTypeBase.PermissionCount]; for (var i = 0; i < perms.Length; i++) { perms[i] = new Permission { Name = PermissionTypeBase.GetPermissionTypeByIndex(i).Name } } ; return(new AccessControlEntry { IdentityId = aceInfo.IdentityId, LocalOnly = aceInfo.LocalOnly, Permissions = perms }); }
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(); } }
internal string _traceEffectivePermissionValues(int entityId, int userId, int ownerId) { var values = new char[PermissionTypeBase.PermissionCount]; foreach (var permType in PermissionTypeBase.GetPermissionTypes()) { var val = GetPermission(userId, entityId, ownerId, permType); char c; switch (val) { case PermissionValue.Undefined: c = '_'; break; case PermissionValue.Allowed: c = '+'; break; case PermissionValue.Denied: c = '-'; break; default: throw new NotSupportedException("Unknown PermissionValue: " + val); } values[values.Length - permType.Index - 1] = c; } return(new string(values)); }
/// <summary> /// Starts the security subsystem using the passed configuration. /// Call this method only once in your application's startup sequence. /// The method prepares and memorizes the main components for /// creating SecurityContext instances in a fastest possible way. /// The main components are global objects: /// ISecurityDataProvider instance, IMessageProvider instance and SecurityCache instance. /// </summary> protected static void StartTheSystem(SecurityConfiguration configuration) { _generalContext = null; // The messageprovider provider must receive ongoing activities at this time. StartedAt = DateTime.UtcNow; int lastActivityIdFromDb; var uncompleted = DataHandler.LoadCompletionState(configuration.SecurityDataProvider, out lastActivityIdFromDb); _messageProvider = configuration.MessageProvider; _messageProvider.MessageReceived += MessageProvider_MessageReceived; Configuration.Identities.SystemUserId = configuration.SystemUserId ?? -1; Configuration.Identities.VisitorUserId = configuration.VisitorUserId ?? 6; Configuration.Identities.EveryoneGroupId = configuration.EveryoneGroupId ?? 8; Configuration.Identities.OwnerGroupId = configuration.OwnerGroupId ?? 9; Configuration.Messaging.CommunicationMonitorRunningPeriodInSeconds = configuration.CommunicationMonitorRunningPeriodInSeconds ?? 30; Configuration.Messaging.SecuritActivityLifetimeInMinutes = configuration.SecuritActivityLifetimeInMinutes ?? 42; Configuration.Messaging.SecuritActivityTimeoutInSeconds = configuration.SecuritActivityTimeoutInSeconds ?? 120; _securityDataProviderPrototype = configuration.SecurityDataProvider; PermissionTypeBase.InferForcedRelations(); using (var op = SnTrace.Security.StartOperation("Security initial loading.")) { _cacheHolder = SecurityCache.Initialize(configuration.SecurityDataProvider); op.Successful = true; } CommunicationMonitor.Initialize(); _generalContext = new SecurityContext(SystemUser); SecurityActivityQueue.Startup(uncompleted, lastActivityIdFromDb); _killed = false; }
public void Start() { GeneralSecurityContext = null; // The message provider must receive ongoing activities at this time. StartedAt = DateTime.UtcNow; var uncompleted = DataHandler.LoadCompletionState(out var lastActivityIdFromDb); PermissionTypeBase.InferForcedRelations(); using (var op = SnTrace.Security.StartOperation("Security initial loading.")) { var cache = new SecurityCache(DataHandler); cache.Initialize(); Cache = cache; op.Successful = true; } EntityManager = new SecurityEntityManager(Cache, DataHandler, MissingEntityHandler); Cache.EntityManager = EntityManager; // Property injection DataHandler.EntityManager = EntityManager; // Property injection PermissionQuery = new PermissionQuery(EntityManager, Cache); CommunicationMonitor = new CommunicationMonitor(DataHandler, Options.Create(MessagingOptions)); GeneralSecurityContext = new SecurityContext(SystemUser, this); SecurityActivityQueue = new SecurityActivityQueue(this, CommunicationMonitor, DataHandler, ActivityHistory); SecurityActivityQueue.Startup(uncompleted, lastActivityIdFromDb); ActivityHistory.SecurityActivityQueue = SecurityActivityQueue; // Property injection MessageProvider.MessageReceived += MessageProvider_MessageReceived; MessageProvider.Initialize(); MessageProvider.Start(StartedAt); _killed = false; }
/********************************************************************************************* 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(); } }
public override string ToString() { var chars = new char[PermissionTypeBase.PermissionCount]; for (var i = 0; i < chars.Length; i++) { chars[i] = '_'; } foreach (var perm in Permissions) { var index = PermissionTypeBase.PermissionCount - PermissionTypeBase.GetPermissionTypeByName(perm.Name).Index - 1; if (perm.Deny) { chars[index] = '-'; } if (perm.Allow) { chars[index] = '+'; } } return($"{EntryType}|{(LocalOnly ? '-' : '+')}({IdentityId}):{new string(chars)}"); }
private static SenseNet.Security.PermissionValue GetValue(ulong allowBits, ulong denyBits, SenseNet.Security.PermissionTypeBase perm) { var mask = 1uL << (perm.Index); if ((denyBits & mask) != 0) { return(SenseNet.Security.PermissionValue.Denied); } if ((allowBits & mask) == mask) { return(SenseNet.Security.PermissionValue.Allowed); } return(SenseNet.Security.PermissionValue.Undefined); }
/*=========================================================================================== Tools */ internal static void SetBits(ref ulong allowBits, ref ulong denyBits, SenseNet.Security.PermissionTypeBase permissionType, SenseNet.Security.PermissionValue permissionValue) { var permCount = PermissionType.PermissionCount; var y = permissionType.Index; var thisbit = 1uL << y; var allowedBefore = (allowBits & thisbit) != 0uL; var deniedBefore = (denyBits & thisbit) != 0uL; var dependencyTable = Providers.Instance.SecurityHandler.PermissionDependencyTable; switch (permissionValue) { case SenseNet.Security.PermissionValue.Allowed: for (var x = 0; x < permCount; x++) { if (dependencyTable[y][x] == 1) { allowBits |= 1uL << x; denyBits &= ~(1uL << x); } } break; case SenseNet.Security.PermissionValue.Denied: for (var x = 0; x < permCount; x++) { if (dependencyTable[x][y] == 1) { allowBits &= ~(1uL << x); denyBits |= 1uL << x; } } break; case SenseNet.Security.PermissionValue.Undefined: if (allowedBefore) { for (var x = 0; x < permCount; x++) { if (dependencyTable[x][y] == 1) { allowBits &= ~(1uL << x); } } } else if (deniedBefore) { for (var x = 0; x < permCount; x++) { if (dependencyTable[y][x] == 1) { denyBits &= ~(1uL << x); } } } break; default: throw new NotSupportedException("Unknown PermissionValue: " + permissionValue); } }
/*=========================================================================================== method for backward compatibility */ /// <summary> /// Allowes, denies or clears a permission on the requested entity for the requested identity. /// This is a backward compatible legacy method. /// </summary> /// <param name="entityId">The requested entity.</param> /// <param name="identityId">The requested identity.</param> /// <param name="localOnly">Determines whether the edited entry is inheritable or not.</param> /// <param name="permission">Permission that will be modified.</param> /// <param name="value">Value that will be set. It can be Undefined, Allowed or Denied.</param> /// <returns>A reference to this instance for calling more operations.</returns> public SnAclEditor SetPermission(int entityId, int identityId, bool localOnly, SenseNet.Security.PermissionTypeBase permission, SenseNet.Security.PermissionValue value) { switch (value) { case SenseNet.Security.PermissionValue.Allowed: Allow(entityId, identityId, localOnly, permission); break; case SenseNet.Security.PermissionValue.Denied: Deny(entityId, identityId, localOnly, permission); break; case SenseNet.Security.PermissionValue.Undefined: ClearPermission(entityId, identityId, localOnly, permission); break; default: throw new SnNotSupportedException("Unknown PermissionValue: " + value); } return(this); }
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); }