public void Test_Demand_Failure()
        {
            EntityAccessControlService         entityAccessControlService;
            Mock <IEntityAccessControlChecker> entityAccessControlChecker;

            EntityRef[] entities;
            EntityRef[] permissions;

            entities    = new EntityRef[] { 1 };
            permissions = new[] { Permissions.Read };

            entityAccessControlChecker = new Mock <IEntityAccessControlChecker>(MockBehavior.Strict);
            entityAccessControlChecker.Setup(eacc => eacc.CheckAccess(
                                                 It.Is <IList <EntityRef> >(e => e.SequenceEqual(entities, EntityRefComparer.Instance)),
                                                 It.Is <IList <EntityRef> >(p => p.SequenceEqual(permissions, EntityRefComparer.Instance)),
                                                 It.IsAny <EntityRef>()))
            .Returns(new Dictionary <long, bool>()
            {
                { entities[0].Id, false }
            });

            entityAccessControlService = new EntityAccessControlService(entityAccessControlChecker.Object);

            Assert.That(() => entityAccessControlService.Demand(entities, permissions),
                        Throws.TypeOf <PlatformSecurityException>());

            entityAccessControlChecker.VerifyAll();
        }
        public void Test_CanCreateEntityTypes()
        {
            EntityAccessControlService         entityAccessControlService;
            Mock <IEntityAccessControlChecker> entityAccessControlChecker;
            EntityType entityType;

            entityType = Entity.Get <EntityType>("core:person");
            Assert.That(entityType, Is.Not.Null, "Person type not found");

            entityAccessControlChecker = new Mock <IEntityAccessControlChecker>(MockBehavior.Strict);
            entityAccessControlChecker.Setup(eacc => eacc.CheckTypeAccess(
                                                 It.Is <IList <EntityType> >(ets => ets.SequenceEqual(new [] { entityType }, new EntityEqualityComparer())),
                                                 It.Is <EntityRef>(perm => perm.Id == Permissions.Create.Id),
                                                 It.IsAny <EntityRef>()))
            .Returns <IList <EntityType>, EntityRef, EntityRef>(
                (ets, perm, user) => new Dictionary <long, bool> {
                { entityType.Id, true }
            });

            entityAccessControlService = new EntityAccessControlService(entityAccessControlChecker.Object);

            Assert.That(entityAccessControlService.CanCreate(new [] { entityType }),
                        Is.EquivalentTo(new [] { new KeyValuePair <long, bool>(entityType.Id, true) }));

            entityAccessControlChecker.VerifyAll();
        }
        public void Test_Demand_Success()
        {
            EntityAccessControlService         entityAccessControlService;
            Mock <IEntityAccessControlChecker> entityAccessControlChecker;

            EntityRef[] entities;
            EntityRef[] permissions;

            using (DatabaseContext.GetContext(true))
            {
                entities    = new EntityRef[] { 1 };
                permissions = new[] { Permissions.Read };

                entityAccessControlChecker = new Mock <IEntityAccessControlChecker>(MockBehavior.Strict);
                entityAccessControlChecker.Setup(eacc => eacc.CheckAccess(
                                                     It.Is <IList <EntityRef> >(e => e.SequenceEqual(entities, EntityRefComparer.Instance)),
                                                     It.Is <IList <EntityRef> >(p => p.SequenceEqual(permissions, EntityRefComparer.Instance)),
                                                     It.IsAny <EntityRef>()))
                .Returns(new Dictionary <long, bool>()
                {
                    { entities[0].Id, true }
                });

                entityAccessControlService = new EntityAccessControlService(entityAccessControlChecker.Object);

                Assert.That(() => entityAccessControlService.Demand(entities, permissions), Throws.Nothing);

                entityAccessControlChecker.VerifyAll();
            }
        }
        public void Test_Check_MultipleEntities()
        {
            EntityAccessControlService         entityAccessControlService;
            Mock <IEntityAccessControlChecker> entityAccessControlChecker;

            EntityRef[] entities;
            EntityRef[] permissions;
            IDictionary <long, bool> result;

            using (DatabaseContext.GetContext(true))
            {
                entities    = new EntityRef[] { 1 };
                permissions = new[] { Permissions.Read };

                entityAccessControlChecker = new Mock <IEntityAccessControlChecker>(MockBehavior.Strict);
                entityAccessControlChecker.Setup(eacc => eacc.CheckAccess(
                                                     It.Is <IList <EntityRef> >(e => e.SequenceEqual(entities, EntityRefComparer.Instance)),
                                                     It.Is <IList <EntityRef> >(p => p.SequenceEqual(permissions, EntityRefComparer.Instance)),
                                                     It.IsAny <EntityRef>()))
                .Returns(new Dictionary <long, bool>()
                {
                    { entities[0].Id, true }
                });

                entityAccessControlService = new EntityAccessControlService(entityAccessControlChecker.Object);

                result = entityAccessControlService.Check(entities, permissions);
                Assert.That(result, Has.Property("Count").EqualTo(1));
                Assert.That(result, Has.Exactly(1).Property("Key").EqualTo(entities[0].Id).And.Property("Value").EqualTo(true));

                entityAccessControlChecker.VerifyAll();
            }
        }
        public void Test_Check_SingleEntity()
        {
            EntityAccessControlService         entityAccessControlService;
            Mock <IEntityAccessControlChecker> entityAccessControlChecker;
            Resource entity;

            EntityRef[] permissions;

            using (DatabaseContext.GetContext(true))
            {
                entity      = Entity.Create <Resource>();
                permissions = new[] { Permissions.Read };

                entityAccessControlChecker = new Mock <IEntityAccessControlChecker>(MockBehavior.Strict);
                entityAccessControlChecker.Setup(eacc => eacc.CheckAccess(
                                                     It.Is <IList <EntityRef> >(e => e.SequenceEqual(new EntityRef[] { entity }, EntityRefComparer.Instance)),
                                                     It.Is <IList <EntityRef> >(p => p.SequenceEqual(permissions, EntityRefComparer.Instance)),
                                                     It.IsAny <EntityRef>()))
                .Returns(new Dictionary <long, bool>()
                {
                    { entity.Id, true }
                });

                entityAccessControlService = new EntityAccessControlService(entityAccessControlChecker.Object);

                Assert.That(entityAccessControlService.Check(entity, permissions), Is.True);

                entityAccessControlChecker.VerifyAll();
            }
        }
예제 #6
0
        /// <summary>
        /// Runs the report specified by ID.
        /// </summary>
        /// <param name="reportId">The report unique identifier.</param>
        /// <param name="settings">The settings for the report to be run.</param>
        /// <returns>ReportResult.</returns>
        /// <exception cref="System.ArgumentException">
        /// The report identifier resource is not a report.
        /// </exception>
        /// <exception cref="PlatformSecurityException">
        /// The user lacks read access to <paramref name="reportId"/>.
        /// </exception>
        public ReportCompletionData PrepareReport(long reportId, ReportSettings settings)
        {
            using (Profiler.Measure("ReportingInterface.PrepareReport {0}", reportId))
                using (CacheContext cacheContext = new CacheContext( ))
                {
                    // Check user has permission to report
                    EntityAccessControlService.Demand(new[] { new EntityRef(reportId) }, new[] { Permissions.Read });

                    cacheContext.Entities.Add(reportId);

                    using (CacheManager.ExpectCacheHits(true))
                        using (new SecurityBypassContext())
                        {
                            // Validate the report entity Identifier
                            Model.Report report;
                            using (Profiler.Measure("GraphEntityRepository.Get", reportId))
                            {
                                // Get the report from the graph database
                                report = GraphEntityRepository.Get <Model.Report>(reportId, ReportHelpers.ReportPreloaderQuery);

                                if (report == null)
                                {
                                    throw new WebArgumentException("reportId");
                                }
                            }

                            settings = settings ?? new ReportSettings( );
                            settings.UseStructuredQueryCache = true;

                            return(PrepareReport(report, settings, true));
                        }
                }
        }
        public void Test_TraceCacheInvalidations_CanCreate(SecurityTraceLevel traceLevel)
        {
            EntityType entityType;
            EntityAccessControlService entityAccessControlService;
            UserAccount userAccount;
            int         expectedOccurrences;

            userAccount = new UserAccount
            {
                Name = "Test User " + Guid.NewGuid()
            };
            userAccount.Save();

            entityType = new EntityType();
            entityType.Save();

            entityAccessControlService = new EntityAccessControlService(
                new EntityAccessControlChecker(), () => (int)traceLevel);

            using (new SetUser(userAccount))
            {
                entityAccessControlService.CanCreate(entityType);
            }

            expectedOccurrences = -1;
            switch (traceLevel)
            {
            case SecurityTraceLevel.DenyVerbose:
            case SecurityTraceLevel.DenyBasic:
            case SecurityTraceLevel.AllVerbose:
            case SecurityTraceLevel.AllBasic:
                expectedOccurrences = 1;
                break;

            case SecurityTraceLevel.None:
                expectedOccurrences = 0;
                break;

            default:
                Assert.Fail("Unknown security trace level.");
                break;
            }

            IList <LogActivityLogEntry> activityLogEntries;

            activityLogEntries = Entity.GetInstancesOfType <LogActivityLogEntry>().ToList();
            Assert.That(activityLogEntries,
                        Has.Exactly(expectedOccurrences)
                        .Property("LogEntrySeverity_Enum").EqualTo(LogSeverityEnum_Enumeration.InformationSeverity).And
                        .Property("LogEventTime").EqualTo(DateTime.UtcNow).Within(TimeSpan.FromSeconds(10)).And
                        .Property("Description").StartsWith(
                            string.Format(
                                "Access control check: Does user '{0}' have '{1}' access to entity(ies) '{2}'",
                                userAccount.Name, Permissions.Create.Alias, entityType.Id)));
        }
        public void Test_GetBehavior_Null()
        {
            EntityAccessControlService entityAccessControlService;

            entityAccessControlService = new EntityAccessControlService(
                new EntityAccessControlChecker(), () => (int)SecurityTraceLevel.None);

            Assert.That(
                () => entityAccessControlService.GetBehavior(null),
                Throws.TypeOf <ArgumentNullException>().And.Property("ParamName").EqualTo("entityIds"));
        }
        public void Test_GetBehavior_Empty()
        {
            EntityAccessControlService entityAccessControlService;

            entityAccessControlService = new EntityAccessControlService(
                new EntityAccessControlChecker(), () => (int)SecurityTraceLevel.None);

            Assert.That(
                () => entityAccessControlService.GetBehavior(new long[0]),
                Is.EqualTo(MessageContextBehavior.New));
        }
        public void Test_GetBehavior_RequestContextNotSet()
        {
            EntityAccessControlService entityAccessControlService;

            entityAccessControlService = new EntityAccessControlService(
                new EntityAccessControlChecker(), () => (int)SecurityTraceLevel.None);

            Assert.That(
                () => entityAccessControlService.GetBehavior(new long[0]),
                Throws.InvalidOperationException);
        }
        public void Test_GetBehavior_ForceTrace_Overlap()
        {
            EntityAccessControlService entityAccessControlService;

            entityAccessControlService = new EntityAccessControlService(
                new EntityAccessControlChecker(), () => (int)SecurityTraceLevel.None);

            using (new ForceSecurityTraceContext(1))
            {
                Assert.That(
                    () => entityAccessControlService.GetBehavior(new long[] { 1 }),
                    Is.EqualTo(MessageContextBehavior.New | MessageContextBehavior.Capturing));
            }
        }
        public void Test_Creation()
        {
            EntityAccessControlService  entityAccessControlService;
            IEntityAccessControlChecker entityAccessControlChecker;

            entityAccessControlChecker = new EntityAccessControlChecker();
            entityAccessControlService = new EntityAccessControlService(entityAccessControlChecker);
            Assert.That(entityAccessControlService,
                        Has.Property("EntityAccessControlChecker").EqualTo(entityAccessControlChecker));
            Assert.That(entityAccessControlService,
                        Has.Property("TraceLevelFactory").EqualTo((Func <int>)entityAccessControlService.GetTraceLevelSetting));
            Assert.That(entityAccessControlService,
                        Has.Property("TraceLevel").Not.Null);
        }
        public void Test_GetBehavior_ForceTrace_NoOverlap()
        {
            EntityAccessControlService entityAccessControlService;
            const long entityId = 1;

            entityAccessControlService = new EntityAccessControlService(
                new EntityAccessControlChecker(), () => (int)SecurityTraceLevel.None);

            using (new ForceSecurityTraceContext(entityId))
            {
                Assert.That(
                    () => entityAccessControlService.GetBehavior(new long[] { entityId + 1 }),
                    Is.EqualTo(MessageContextBehavior.New));
            }
        }
예제 #14
0
        /// <summary>
        ///     Verify that the current user has permission to perform an import.
        /// </summary>
        /// <remarks>
        ///     Loads all entities that are specified in the data source, then looks up the current user/tenant to see
        ///     if those entities are present. Performs a security demand on those that are present.
        /// </remarks>
        /// <param name="source">Data source to read entities from.</param>
        /// <param name="permissions">Permission(s) to demand.</param>
        /// <param name="context">Processing context for reading the source.</param>
        /// <exception cref="PlatformSecurityException">Thrown if permission is denied.</exception>
        public void CheckEntityPermissions(IDataSource source, IList <EntityRef> permissions, IProcessingContext context)
        {
            // Load entities that would be imported
            IEnumerable <Guid> upgradeIds =
                source.GetEntities(context)
                .Select(e => e.EntityId).Distinct( );

            // Note: UpgradeIdProvider will drop any upgradeIds that don't exist in the tenant.
            IList <EntityRef> entityIds =
                UpgradeIdProvider.GetIdsFromUpgradeIds(upgradeIds)
                .Select(pair => new EntityRef(pair.Value)).ToList( );

            // Demand 'modify' for instances
            EntityAccessControlService.Demand(entityIds, permissions);
        }
        public void Test_GetBehavior_Inspect_Overlap()
        {
            EntityAccessControlService entityAccessControlService;
            EventLogSettings           eventLogSettings;
            IEntity testEntity;

            testEntity = Entity.Get <Resource>("core:name");

            eventLogSettings = Entity.Get <EventLogSettings>(ForceSecurityTraceContext.EventLogSettingsAlias, true);
            eventLogSettings.InspectSecurityChecksOnResource.Add(Entity.Get <Resource>(testEntity.Id));
            eventLogSettings.Save();

            entityAccessControlService = new EntityAccessControlService(
                new EntityAccessControlChecker(), () => (int)SecurityTraceLevel.None);

            Assert.That(
                () => entityAccessControlService.GetBehavior(new [] { testEntity.Id }),
                Is.EqualTo(MessageContextBehavior.New | MessageContextBehavior.Capturing));
        }
        public void Test_GetBehavior_Inspect_NoOverlap()
        {
            EntityAccessControlService entityAccessControlService;
            EventLogSettings           eventLogSettings;
            IEntity testEntity;

            testEntity = Entity.Get <Resource>("core:name");

            eventLogSettings = Entity.Get <EventLogSettings>(ForceSecurityTraceContext.EventLogSettingsAlias, true);
            eventLogSettings.InspectSecurityChecksOnResource.Add(Entity.Get <Resource>("core:name"));
            eventLogSettings.Save();

            Thread.Sleep(new TimeSpan(ForceSecurityTraceContext.TicksToWaitBeforeRefreshing));

            entityAccessControlService = new EntityAccessControlService(
                new EntityAccessControlChecker(), () => (int)SecurityTraceLevel.None);

            Assert.That(
                () => entityAccessControlService.GetBehavior(new [] { testEntity.Id + 1 }),
                Is.EqualTo(MessageContextBehavior.New));
        }
        public void Test_GetTraceCacheInvalidationSetting()
        {
            int oldSetting;
            int newSetting;
            EntityAccessControlService entityAccessControlService;

            oldSetting = ConfigurationSettings.GetServerConfigurationSection().Security.Trace;
            try
            {
                newSetting = oldSetting + 1;
                ConfigurationSettings.GetServerConfigurationSection().Security.Trace = newSetting;

                entityAccessControlService = new EntityAccessControlService();

                Assert.That(entityAccessControlService.GetTraceLevelSetting(), Is.EqualTo(newSetting));
            }
            finally
            {
                ConfigurationSettings.GetServerConfigurationSection().Security.Trace = oldSetting;
            }
        }
예제 #18
0
        /// <summary>
        ///     Verify that the current user has permission to create instances of types mentioned in a data source.
        /// </summary>
        /// <remarks>
        ///     Loads all relationship instances and searches for 'isOfType' relationships.
        ///     Then performs a 'can create' check on those types, if they are present in the current tenant.
        /// </remarks>
        /// <param name="source">Data source to read relationships from.</param>
        /// <param name="context">Processing context for reading the source.</param>
        /// <exception cref="PlatformSecurityException">Thrown if permission is denied.</exception>
        public void CheckTypeCreatePermissions(IDataSource source, IProcessingContext context)
        {
            // Load types that would be imported
            IEnumerable <Guid> typeUpgradeIds =
                source.GetRelationships(context)
                .Where(rel => rel.TypeId == Helpers.IsOfTypeRelationshipUpgradeId)
                .Select(rel => rel.ToId).Distinct( );

            // Note: UpgradeIdProvider will drop any upgradeIds that don't exist in the tenant.
            IEnumerable <long> typeIds =
                UpgradeIdProvider.GetIdsFromUpgradeIds(typeUpgradeIds)
                .Select(pair => pair.Value);
            IDictionary <long, EntityType> types = EntityRepository.Get <EntityType>(typeIds).ToDictionary(e => e.Id);

            // Demand 'create' for types
            IDictionary <long, bool> canCreate = EntityAccessControlService.CanCreate(types.Values.ToList( ));
            IList <long>             denied    = canCreate.Where(pair => !pair.Value).Select(pair => pair.Key).ToList( );

            if (denied.Count > 0)
            {
                string message = "Permission denied to create records of type: " + string.Join(", ", denied.Select(id => types[id].Name));
                throw new PlatformSecurityException(message);
            }
        }
예제 #19
0
        /// <summary>
        ///     Sets up this instance.
        /// </summary>
        void IDataSource.Setup(IProcessingContext context)
        {
            if (RootEntities == null)
            {
                throw new InvalidOperationException("RootEntities is not set.");
            }

            // Perform demand on root entity(ies).
            if (DemandReadPermission)
            {
                EntityAccessControlService.Demand(RootEntities.Select(id => new EntityRef(id)).ToList( ), new[]
                {
                    Permissions.Read
                });
            }

            using (new TenantAdministratorContext(TenantId))
            {
                _aliasFieldId        = WellKnownAliases.CurrentTenant.Alias;
                _reverseAliasFieldId = WellKnownAliases.CurrentTenant.ReverseAlias;

                // Get the instance to be exported
                IEnumerable <IEntity> instances = EntityRepository.Get(RootEntities);
                ICollection <long>    typeIds   = instances.Select(inst => inst.TypeIds.FirstOrDefault( )).Distinct().ToList();
                if (typeIds.Count == 0)
                {
                    typeIds = new[] { WellKnownAliases.CurrentTenant.Resource }
                }
                ;

                // Generate a cloning request factory for loading the data
                CloneEntityMemberRequestFactory requestFactory = new CloneEntityMemberRequestFactory(EntityRepository);
                EntityMemberRequest             memberRequest  = requestFactory.CreateRequest(typeIds);

                EntityRequest entityRequest = new EntityRequest
                {
                    Request  = memberRequest,
                    Entities = RootEntities.Select(id => new EntityRef(id))
                };

                // Load data, unsecured, via EntityInfoService cache
                _bulkResult = BulkResultCache.GetBulkResult(entityRequest);

                // Load all UpgradeIDs
                IEnumerable <long> allIds = _bulkResult.AllEntities.Keys
                                            .Union(_bulkResult.Relationships.Keys.Select(k => k.TypeId))
                                            .Union(_bulkResult.FieldValues.Keys.Select(k => k.FieldId));

                _idToUpgradeId = UpgradeIdProvider.GetUpgradeIds(allIds);

                IEnumerable <long>         relTypes      = _bulkResult.Relationships.Keys.Select(key => key.TypeId).Distinct( );
                IEnumerable <Relationship> relationships = EntityRepository.Get <Relationship>(relTypes);
                _relationshipTypeCache = relationships.ToDictionary(
                    rel => _idToUpgradeId[rel.Id],
                    rel => new RelationshipTypeEntry
                {
                    CloneAction        = rel.CloneAction_Enum,
                    ReverseCloneAction = rel.ReverseCloneAction_Enum,
                    Alias        = rel.Alias,
                    ReverseAlias = rel.ReverseAlias
                });

                LoadDocumentCaches(context);
            }

            // Read permissions - for reading internal entities
            if (DemandReadPermission)
            {
                _canRead = BulkRequestResultSecurityHelper.GetEntityReadability(Factory.EntityAccessControlService, _bulkResult);
            }
            else
            {
                _canRead = id => true;
            }
        }

        /// <summary>
        ///     Loads the application metadata.
        /// </summary>
        /// <param name="context">The context.</param>
        /// <returns></returns>
        /// <exception cref="System.InvalidOperationException">@Invalid package Id</exception>
        Metadata IDataSource.GetMetadata(IProcessingContext context)
        {
            List <Guid> roots = new List <Guid>( );

            foreach (long rootId in RootEntities)
            {
                Guid rootGuid;
                if (_idToUpgradeId.TryGetValue(rootId, out rootGuid))
                {
                    roots.Add(rootGuid);
                }
            }

            var metadata = new Metadata
            {
                AppName      = "Exported data",
                AppVerId     = Guid.Empty,
                AppId        = Guid.Empty,
                Description  = "Exported data",
                Name         = "Exported data",
                Version      = "1.0",
                RootEntities = roots,
                //Dependencies = solutionDependencies,
                Type                     = SourceType.DataExport,
                PlatformVersion          = SystemInfo.PlatformVersion,
                RelationshipTypeCallback = GetRelationshipMetadata
            };


            return(metadata);
        }
예제 #20
0
            /// <summary>
            ///     Traverses the identifiers.
            /// </summary>
            /// <returns>
            ///     True if the next identifier was found; False otherwise.
            /// </returns>
            private bool TraverseIdentifiers( )
            {
                /////
                // Single bulk security check
                /////
                if (_identifiersEnumerator == null)
                {
                    if (!SecurityBypassContext.IsActive)
                    {
                        IList <EntityRef> permissions = new List <EntityRef>( );

                        permissions.Add(Permissions.Read);

                        if (IsWriteable)
                        {
                            permissions.Add(Permissions.Modify);
                        }

                        IList <EntityRef> identifiers = _identifiers as IList <EntityRef> ?? _identifiers.ToList( );

                        if (_securityOption == SecurityOption.SkipDenied)
                        {
                            IDictionary <long, bool> accessControlCheckResult = EntityAccessControlService.Check(identifiers, permissions);
                            _identifiersEnumerator = _identifiers.Where(er => accessControlCheckResult[er.Id]).GetEnumerator( );
                        }
                        else if (_securityOption == SecurityOption.DemandAll)
                        {
                            EntityAccessControlService.Demand(identifiers, permissions);
                            _identifiersEnumerator = _identifiers.GetEnumerator( );
                        }
                        else
                        {
                            throw new ArgumentException(string.Format("Unknown SecurityOption: {0}", _securityOption));
                        }
                    }
                    else
                    {
                        _identifiersEnumerator = _identifiers.GetEnumerator( );
                    }
                }

                while (_identifiersEnumerator.MoveNext( ))
                {
                    /////
                    // Get the current identifier.
                    /////
                    EntityRef entityRef = _identifiersEnumerator.Current;

                    IEntity entity = RetrieveEntity(entityRef);

                    if (entity != null && entity.TenantId == RequestContext.TenantId)
                    {
                        /////
                        // Ensure the fields are loaded for this entity.
                        /////
                        _bulkFieldLoadAction(entity);

                        if ((_writable && !entity.IsReadOnly) || (!_writable && entity.IsReadOnly))
                        {
                            /////
                            // Use this instance.
                            /////
                            CurrentValue = entity;
                            return(true);
                        }

                        /////
                        // Get a writable instance.
                        /////
                        CurrentValue = entity.AsWritable( );
                        return(true);
                    }
                }

                Dispose( );
                return(false);
            }