/// <summary> /// Called to gather audit log entity details for delete. /// </summary> /// <param name="accessRule">The access rule.</param> /// <returns></returns> protected override AuditLogAccessRuleDetails OnGatherAuditLogEntityDetailsForDelete(AccessRule accessRule) { var accessRuleDetails = new AuditLogAccessRuleDetails { IsTemporaryId = false }; SecurableEntity controlAccess = accessRule.ControlAccess; if (controlAccess != null) { accessRuleDetails.SecuredTypeName = controlAccess.Name; } Subject allowAccessBy = accessRule.AllowAccessBy; if (allowAccessBy != null) { accessRuleDetails.SubjectName = allowAccessBy.Name; } Report accessRuleReport = accessRule.AccessRuleReport; if (accessRuleReport != null) { accessRuleDetails.AccessRuleReportName = accessRuleReport.Name; } return(accessRuleDetails); }
private void CreateAccessRules(IAccessRuleFactory accessRuleFactory, IAccessRuleReportFactory accessRuleReportFactory, Subject subject, IList <string> typeNames, IList <EntityRef> permissions, string aliasTemplate, Solution solution = null) { AccessRule accessRule; foreach (string typeName in typeNames) { SecurableEntity targetType = Entity.Get <SecurableEntity>(typeName); Assert.That(targetType, Is.Not.Null, string.Format("Type {0} does not exist", typeName)); accessRule = accessRuleFactory.AddAllowByQuery( subject, targetType, permissions, accessRuleReportFactory.GetDisplayReportForSecurableEntity(targetType)); accessRule = accessRule.AsWritable <AccessRule>(); accessRule.Alias = string.Format(aliasTemplate, new EntityRef(typeName).Alias); accessRule.AccessRuleHidden = true; if (solution != null) { accessRule.InSolution = solution; } accessRule.Save(); Console.WriteLine("Create access rule {0} {1}", accessRule.Alias, accessRule.Id); } }
/// <summary> /// Given the <paramref name="subject" /> the specified access to <paramref name="securableEntity" /> governed by /// the query <paramref name="report" />. /// </summary> /// <param name="subject">The subject (user or role). This cannot be null.</param> /// <param name="securableEntity">The secured entity (type). This cannot be null.</param> /// <param name="permissions">The permission(s) to add. This cannot be null or contain null.</param> /// <param name="report">The query (as a <see cref="Report" />) to add. This should be a new report, not used for any security. /// This cannot be null.</param> /// <param name="enabled">True if the access rule should be enabled on creation, false if disabled.</param> /// <param name="solution">The solution.</param> /// <returns> /// The <see cref="AccessRule" /> object representing the new query. /// </returns> /// <exception cref="System.ArgumentNullException">subject /// or /// securableEntity /// or /// permissions /// or /// report</exception> /// <exception cref="System.ArgumentException">Cannot contain null - permissions</exception> /// <exception cref="ArgumentNullException">No argument can be null.</exception> /// <exception cref="ArgumentException"> /// <paramref name="permissions" /> cannot contain null.</exception> public AccessRule AddAllowByQuery(Subject subject, SecurableEntity securableEntity, IEnumerable <EntityRef> permissions, Report report, bool enabled = true, Solution solution = null) { if (subject == null) { throw new ArgumentNullException("subject"); } if (securableEntity == null) { throw new ArgumentNullException("securableEntity"); } if (permissions == null) { throw new ArgumentNullException("permissions"); } if (permissions.Contains(null)) { throw new ArgumentException("Cannot contain null", "permissions"); } if (report == null) { throw new ArgumentNullException("report"); } AccessRule accessRule; // Give a name to avoid warnings about unnamed reports if (string.IsNullOrWhiteSpace(report.Name)) { report.Name = "Security report"; } accessRule = Entity.Create <AccessRule>( ); accessRule.Name = string.Format("'{0}' accessing '{1}'", subject.Name ?? string.Empty, securableEntity.Name ?? string.Empty); accessRule.AccessRuleEnabled = enabled; accessRule.PermissionAccess.AddRange(permissions.Select(x => x.Entity.As <Permission>( ))); accessRule.ControlAccess = securableEntity; accessRule.AccessRuleReport = report; accessRule.AllowAccessBy = subject; if (solution != null) { accessRule.InSolution = solution; } accessRule.Save( ); subject.Save( ); return(accessRule); }
/// <summary> /// Called to gather audit log entity details for save. /// </summary> /// <param name="report">The report.</param> /// <returns></returns> protected override AuditLogReportDetails OnGatherAuditLogEntityDetailsForSave(Report report) { var reportInternal = report as IEntityInternal; IEntityFieldValues fields; IDictionary <long, IChangeTracker <IMutableIdKey> > forwardRelationships; IDictionary <long, IChangeTracker <IMutableIdKey> > reverseRelationships; report.GetChanges(out fields, out forwardRelationships, out reverseRelationships); var reportDetails = new AuditLogReportDetails(); if (reportInternal.IsTemporaryId) { return(reportDetails); } if ((fields != null && fields.Any()) || (reverseRelationships != null && reverseRelationships.Count > 0) || (forwardRelationships != null && forwardRelationships.Count > 0)) { AccessRule accessRule = report.ReportForAccessRule; if (accessRule != null) { // gather info to notify that an access rule's query has changed reportDetails.IsAccessRuleReport = true; reportDetails.AccessRuleReportName = report.Name; SecurableEntity controlAccess = accessRule.ControlAccess; if (controlAccess != null) { reportDetails.SecuredTypeName = controlAccess.Name; } Subject allowAccessBy = accessRule.AllowAccessBy; if (allowAccessBy != null) { reportDetails.SubjectName = allowAccessBy.Name; } } } return(reportDetails); }
/// <summary> /// Get the default display report for the given <see cref="EntityType" />. /// If there is no display report, do a breadth-first recursion through /// the inherited types to find a suitable display report. /// </summary> /// <param name="securableEntity"> /// The type (or other <see cref="SecurableEntity" /> the report will be for. /// Note that the current implementation requires this to be an <see cref="EntityType" />. /// </param> /// <param name="structuredQuery"> /// An optional <see cref="StructuredQuery" /> to use for the report.. /// </param> /// <returns> /// A <see cref="ReadiNow.Model.Report" /> or null, if not report is found. /// </returns> /// <exception cref="ArgumentNullException"> /// <paramref name="securableEntity" /> cannot be null. /// </exception> /// <exception cref="ArgumentException"> /// <paramref name="securableEntity" /> must be an <see cref="EntityType" />. /// </exception> public Report GetDisplayReportForSecurableEntity(SecurableEntity securableEntity, StructuredQuery structuredQuery = null) { if (securableEntity == null) { throw new ArgumentNullException("securableEntity"); } // TODO: Test the RootEntity of structuredQuery to ensure it is the correct ype. var entityType = securableEntity.As <EntityType>( ); if (entityType == null) { throw new ArgumentException(@"securableEntity is not an EntityType", "securableEntity"); } // Place in separate, uniquely named folder to ensure (1) security reports // do not appear inthe UI elsewhere and (2) the report name resource key // does not block the saving of the report. Folder folder = Model.Entity.Create <Folder>( ); folder.Name = string.Format("{0}{1}", Guid.NewGuid( ), DateTime.Now); folder.Save( ); // The report creation code is hardly the most efficient but // it has been working reliably in automated tests. This operation // also occurs rarely. if (structuredQuery == null) { string typeName = entityType.Name ?? "Name"; structuredQuery = CreateEntitiesQuery(entityType, typeName); } Report result = ToReport(structuredQuery); result.Name = entityType.Name ?? DefaultReportName; result.Description = string.Empty; result.ResourceInFolder.Add(folder.As <NavContainer>( )); // For cascading deletes result.Save( ); return(result); }
/// <summary> /// Called to gather audit log entity details for save. /// </summary> /// <param name="accessRule">The access rule.</param> /// <returns></returns> protected override AuditLogAccessRuleDetails OnGatherAuditLogEntityDetailsForSave(AccessRule accessRule) { var accessRuleInternal = accessRule as IEntityInternal; IEntityFieldValues fields; IDictionary <long, IChangeTracker <IMutableIdKey> > forwardRelationships; IDictionary <long, IChangeTracker <IMutableIdKey> > reverseRelationships; accessRule.GetChanges(out fields, out forwardRelationships, out reverseRelationships); var oldAccessRule = new Lazy <AccessRule>(() => Entity.Get <AccessRule>(accessRule.Id)); IEnumerable <EntityRef> idsToLoad = new List <EntityRef> { "core:accessRuleEnabled", "core:permissionAccess", "core:accessRuleReport" }; Dictionary <string, IEntity> fieldEntities = Entity.Get(idsToLoad).ToDictionary(e => e.Alias); var accessRuleDetails = new AuditLogAccessRuleDetails { IsTemporaryId = accessRuleInternal.IsTemporaryId }; if (fields != null && fields.Any()) { object fieldObj; if (fields.TryGetValue(fieldEntities["accessRuleEnabled"].Id, out fieldObj)) { // Enabled was changed accessRuleDetails.Enabled = fieldObj as bool?; accessRuleDetails.OldEnabled = oldAccessRule.Value.AccessRuleEnabled; } } SecurableEntity controlAccess = accessRule.ControlAccess; if (controlAccess != null) { accessRuleDetails.SecuredTypeName = controlAccess.Name; } Subject allowAccessBy = accessRule.AllowAccessBy; if (allowAccessBy != null) { accessRuleDetails.SubjectName = allowAccessBy.Name; } Report accessRuleReport = accessRule.AccessRuleReport; if (accessRuleReport != null) { accessRuleDetails.AccessRuleReportName = accessRuleReport.Name; } if (forwardRelationships != null && forwardRelationships.Count > 0) { IChangeTracker <IMutableIdKey> permissionsTracker; if (forwardRelationships.TryGetValue(fieldEntities["permissionAccess"].Id, out permissionsTracker)) { IEntityCollection <Permission> oldPermissions = oldAccessRule.Value.PermissionAccess; if (oldPermissions != null) { accessRuleDetails.OldPermissions.UnionWith(oldPermissions.Select(e => e.Name)); } IEntityCollection <Permission> newPermissions = accessRule.PermissionAccess; if (newPermissions != null) { accessRuleDetails.NewPermissions.UnionWith(newPermissions.Select(e => e.Name)); } } IChangeTracker <IMutableIdKey> reportTracker; if (forwardRelationships.TryGetValue(fieldEntities["accessRuleReport"].Id, out reportTracker)) { accessRuleDetails.IsAccessRuleReportChanged = true; } } return(accessRuleDetails); }
/// <summary> /// Given the <paramref name="subject"/> the specified access to <paramref name="securableEntity"/>. /// </summary> /// <param name="subject"> /// The subject (user or role). This cannot be null. /// </param> /// <param name="permissions"> /// The permission(s) to add. This cannot be null or contain null. /// </param> /// <param name="securableEntity"> /// The secured entity (type). This cannot be null. /// </param> /// <returns> /// The <see cref="AccessRule"/> object representing the new query. /// </returns> /// <exception cref="ArgumentNullException"> /// No argument can be null. /// </exception> /// <exception cref="ArgumentException"> /// <paramref name="permissions"/> cannot contain null. /// </exception> public AccessRule AddAllow(Subject subject, IEnumerable <EntityRef> permissions, SecurableEntity securableEntity) { if (subject == null) { throw new ArgumentNullException("subject"); } if (permissions == null) { throw new ArgumentNullException("permissions"); } if (permissions.Contains(null)) { throw new ArgumentException("Cannot contain null", "permissions"); } if (securableEntity == null) { throw new ArgumentNullException("securableEntity"); } AccessRule accessRule; accessRule = Entity.Create <AccessRule>(); accessRule.Name = string.Format("'{0}' accessing '{1}'", subject.Name ?? string.Empty, securableEntity.Name ?? string.Empty); accessRule.AccessRuleEnabled = true; accessRule.PermissionAccess.AddRange(permissions.Select(x => x.Entity.As <Permission>())); accessRule.ControlAccess = securableEntity; accessRule.AllowAccessBy = subject; accessRule.Save(); subject.Save(); return(accessRule); }
/// <summary> /// Given the <paramref name="subject"/> create access to <paramref name="securableEntity"/>. /// </summary> /// <param name="subject"> /// The subject (user or role). This cannot be null. /// </param> /// <param name="securableEntity"> /// The secured entity (type). This cannot be null. /// </param> /// <returns> /// The <see cref="AccessRule"/> object representing the new query. /// </returns> /// <exception cref="ArgumentNullException"> /// No argument can be null. /// </exception> public AccessRule AddAllowCreate(Subject subject, SecurableEntity securableEntity) { return(AddAllow(subject, Permissions.Create.ToEnumerable(), securableEntity)); }
/// <summary> /// Given the <paramref name="subject"/> delete access to <paramref name="securableEntity"/> governed by /// the query <paramref name="query"/>. /// </summary> /// <param name="subject"> /// The subject (user or role). This cannot be null. /// </param> /// <param name="securableEntity"> /// The secured entity (type). This cannot be null. /// </param> /// <param name="query"> /// The query (as a <see cref="Report"/>) to add. This should be a new report, not used for any security. /// This cannot be null. /// </param> /// <returns> /// The <see cref="AccessRule"/> object representing the new query. /// </returns> /// <exception cref="ArgumentNullException"> /// No argument can be null. /// </exception> public AccessRule AddAllowDeleteQuery(Subject subject, SecurableEntity securableEntity, Report query) { return(AddAllowByQuery(subject, securableEntity, Permissions.Delete.ToEnumerable(), query)); }
/// <summary> /// Get the access rules for a given user and permission or operation. /// </summary> /// <param name="subjectId"> /// The ID of the <see cref="Subject"/>, that is a <see cref="UserAccount"/> or <see cref="Role"/> instance. /// This cannot be negative. /// </param> /// <param name="permission"> /// The permission to get the query for. This may be null or should be one of <see cref="Permissions.Read"/>, /// <see cref="Permissions.Modify"/> or <see cref="Permissions.Delete"/>. /// </param> /// <param name="securableEntityTypes"> /// The IDs of <see cref="SecurableEntity"/> types being accessed. This may be null. /// </param> /// <returns> /// The queries to run. /// </returns> /// <exception cref="ArgumentException"> /// <paramref name="subjectId"/> does not exist. Also, <paramref name="permission"/> should /// be one of <see cref="Permissions.Read"/>, <see cref="Permissions.Modify"/> or <see cref="Permissions.Delete"/> /// </exception> public ICollection <AccessRule> GetAccessRules(long subjectId, [CanBeNull] EntityRef permission, [CanBeNull] ICollection <long> securableEntityTypes) { Subject subject; List <AccessRule> accessRules; List <AccessRule> result = new List <AccessRule>( ); subject = Entity.Get <Subject>(new EntityRef(subjectId)); if (subject == null) { throw new ArgumentException("Subject not found", "subjectId"); } // Entity model overview: // +---------------+ // ------- PermissionAccess ----------> | Permission | // | +---------------+ // | // +-------+ +---------------------+ +-----------------+ // |Subject| -- AllowAccess --> | AccessRule | -- ControlAccess --> | SecurableEntity | // +-------+ +---------------------+ +-----------------+ // | // | +---------------+ // ------- AR to Report -------------> | Report | // +---------------+ // // Create ignores any associated report. accessRules = new List <AccessRule>(); accessRules.AddRange(subject.AllowAccess); // Store the enties that, when changed, should invalidate this cache entry. using (CacheContext cacheContext = CacheContext.GetContext()) using (new SecurityBypassContext()) { cacheContext.Entities.Add(subject.Id); foreach (AccessRule allowAccess in accessRules) { if (allowAccess == null) { continue; } cacheContext.Entities.Add(allowAccess.Id); SecurableEntity controlAccess = allowAccess.ControlAccess; if (controlAccess != null) { cacheContext.Entities.Add(controlAccess.Id); } IEnumerable <EntityRef> permissionsRef = allowAccess.PermissionAccess.WhereNotNull().Select(x => new EntityRef(x)).ToList(); if ((allowAccess.AccessRuleEnabled ?? false)) { if (permission == null || permissionsRef.Any(p => p.Equals(permission))) { if (securableEntityTypes == null || (controlAccess != null && securableEntityTypes.Contains(controlAccess.Id))) { result.Add(allowAccess); } } } cacheContext.Entities.Add(permissionsRef.Select(p => p.Id)); cacheContext.EntityInvalidatingRelationshipTypes.Add(SecurityQueryCacheInvalidatorHelper.SecurityQueryRelationships); } } return(result); }