Example #1
0
        /// <summary>
        /// Returns a secured version of the list of entity IDs.
        /// </summary>
        /// <remarks>
        /// The first instance of an actual security check will result in security being calculated for the entire graph.
        /// The applicable user is noted, and if a different user attempts to access, then an exception is thrown.
        /// Note: this does not affect the cacheability, as caching happens at BulkRequestResult, which is unsecured.
        /// </remarks>
        /// <param name="list">The entities to secure</param>
        /// <param name="securityOption"></param>
        /// <param name="relTypeAndDir">Optionally, the relationship along which the entities were reached. Use negative for reverse.</param>
        /// <returns>The list to which the user has read permission.</returns>
        internal IReadOnlyCollection <long> SecureList(IReadOnlyCollection <long> list, SecurityOption securityOption, long relTypeAndDir = 0)
        {
            // Apply security bypass context
            if (SecurityBypassContext.IsActive)
            {
                return(list);
            }

            // If this relationship implies security, then immediately return results
            if (relTypeAndDir != 0)
            {
                RelationshipInfo relationshipInfo;
                if (_unsecuredGraphData.BulkSqlQuery.Relationships.TryGetValue(relTypeAndDir, out relationshipInfo))
                {
                    if (relationshipInfo.ImpliesSecurity)
                    {
                        return(list);
                    }
                }
                // else assert false
            }

            // Determine if we have pre-calculated security
            if (_canRead == null)
            {
                // Security check on entire graph excluding implicitly secured)
                // Results returned as a predicate that performs fast lookup
                _canRead = BulkRequestResultSecurityHelper.GetEntityReadability(_entityAccessControlService, _unsecuredGraphData);

                _securedForUser = RequestContext.GetContext( ).Identity.Id;
            }
            else
            {
                // Ensure we are still accessing as the same user.
                long currentUser = RequestContext.GetContext( ).Identity.Id;
                if (currentUser != _securedForUser)
                {
                    throw new InvalidOperationException("An entity graph may only be accessed by a single user.");
                }
            }

            if (securityOption == SecurityOption.DemandAll)
            {
                if (list.Any(id => !_canRead(id)))
                {
                    // Security access has already failed, but for consistency of code paths, let Demand throw the exception.
                    var ids = list.Select(id => new EntityRef(id)).ToList();
                    _entityAccessControlService.Demand(ids, new [] { Permissions.Read });
                    throw new Exception("Assert false - Demand should have thrown PlatformSecurityException");
                }
                return(list);
            }
            else
            {
                List <long> result = list.Where(id => _canRead(id)).ToList( );
                return(result);
            }
        }
Example #2
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);
        }