Ejemplo n.º 1
0
        /// <summary>
        /// Returns the entities as per the specifications in the get request
        /// </summary>
        protected virtual async Task <GetAggregateResponse> GetAggregateImplAsync(GetAggregateArguments args)
        {
            // Parse the parameters
            var filter = FilterExpression.Parse(args.Filter);
            var select = AggregateSelectExpression.Parse(args.Select);

            // Prepare the query
            var query = GetRepository().AggregateQuery <TEntity>();

            // Retrieve the user permissions for the current view
            var permissions = await UserPermissions(Constants.Read);

            var permissionsCount = permissions.Count();

            // Filter out permissions with masks that would be violated by the filter argument
            // orderby on the other hand is always mandated to be a subset of the selected parameters
            // and those in turn must be universally visible to the user, so no need to check orderby
            var defaultMask = GetDefaultMask() ?? new MaskTree();

            permissions = FilterViolatedPermissionsForAggregateQuery(permissions, defaultMask, filter, select);
            var filteredPermissionCount = permissions.Count();
            var isPartial = permissionsCount != filteredPermissionCount;

            // Apply read permissions
            FilterExpression permissionsCriteria = GetReadPermissionsCriteria(permissions);

            query = query.Filter(permissionsCriteria);

            // Filter
            query = query.Filter(filter);

            // Apply the top parameter
            var top = args.Top == 0 ? int.MaxValue : args.Top; // 0 means get all

            top   = Math.Min(top, MAXIMUM_AGGREGATE_RESULT_SIZE + 1);
            query = query.Top(top);

            // Apply the select, which has the general format 'Select=A,B/C,D'
            query = query.Select(select);

            // Load the data in memory
            var result = await query.ToListAsync();

            // Put a limit on the number of data points returned, to prevent DoS attacks
            if (result.Count > MAXIMUM_AGGREGATE_RESULT_SIZE)
            {
                var msg = _localizer["Error_NumberOfDataPointsExceedsMaximum0", MAXIMUM_AGGREGATE_RESULT_SIZE];
                throw new BadRequestException(msg);
            }

            // Finally return the result
            return(new GetAggregateResponse
            {
                Top = args.Top,
                IsPartial = isPartial,

                Result = result,
                RelatedEntities = new Dictionary <string, IEnumerable <Entity> >() // TODO: Add ancestors of tree dimensions
            });
        }
Ejemplo n.º 2
0
        private MaskTree UpdateUserMaskAsPerAggregateSelect(AggregateSelectExpression select, MaskTree userMask)
        {
            if (select != null)
            {
                var aggSelectPaths  = select.Select(e => (e.Path, e.Property));
                var aggSelectMask   = MaskTree.GetMaskTree(aggSelectPaths);
                var aggSelectAccess = Normalize(aggSelectMask);

                userMask = userMask.UnionWith(aggSelectAccess);
            }

            return(userMask);
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Removes from the permissions all permissions that would be violated by the filter or aggregate select, the behavior
        /// of the system here is that when a user orders by a field that she has no full access too, she only sees the
        /// rows where she can see that field, sometimes resulting in a shorter list, this is to prevent the user gaining
        /// any insight over fields she has no access to by filter or order the data
        /// </summary>
        protected IEnumerable <AbstractPermission> FilterViolatedPermissionsForAggregateQuery(IEnumerable <AbstractPermission> permissions, MaskTree defaultMask, FilterExpression filter, AggregateSelectExpression select)
        {
            // Step 1 - Build the "User Mask", i.e the mask containing the fields mentioned in the relevant components of the user query
            var userMask = MaskTree.BasicFieldsMaskTree();

            userMask = UpdateUserMaskAsPerFilter(filter, userMask);
            userMask = UpdateUserMaskAsPerAggregateSelect(select, userMask);

            // Filter out those permissions whose mask does not cover the entire user mask
            return(FilterViolatedPermissionsInner(permissions, defaultMask, userMask));
        }