Example #1
0
        /// <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);
        }
Example #2
0
        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);
            }
        }
Example #3
0
        /// <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);
        }
Example #6
0
        /// <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);
        }
Example #7
0
        /// <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);
        }
Example #8
0
 /// <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));
 }
Example #9
0
 /// <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));
 }
Example #10
0
        /// <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);
        }