Beispiel #1
0
        /// <summary>
        /// Creates the filter function for reading, updating or deleting data from an enumeration of models
        /// </summary>
        /// <param name="operation">The database operation that is being performed</param>
        /// <param name="identityService">The identity service to fetch the user from</param>
        /// <param name="userManager">A userManager to pass to the ACLs</param>
        /// <param name="dbContext">A dbContext to pass to the ACLs</param>
        /// <param name="serviceProvider">Service provider to pass to the ACLs</param>
        /// <typeparam name="TModel">The type of the model to add security to</typeparam>
        /// <returns>An expression that can be user for the where condition of a linq query</returns>
        public static Expression <Func <TModel, bool> > CreateSecurityFilter <TModel>(
            DATABASE_OPERATION operation,
            IIdentityService identityService,
            UserManager <User> userManager,
            LactalisDBContext dbContext,
            IServiceProvider serviceProvider)
            where TModel : IOwnerAbstractModel, new()
        {
            identityService.RetrieveUserAsync().Wait();
            var model         = new TModel();
            var userGroups    = identityService.Groups;
            var userModelAcls = model.Acls.Where(x => userGroups.Contains(x.Group) || x.IsVisitorAcl);

            Expression <Func <TModel, bool> > baseRule = _ => false;
            var filter = Expression.OrElse(baseRule.Body, baseRule.Body);

            if (!userModelAcls.Any())
            {
                // If we have no rules on this model then we should inherit from the model driven base rule
                Expression <Func <TModel, bool> > defaultFilter = _ => ALLOW_DEFAULT;
                filter = Expression.OrElse(filter, defaultFilter.Body);
            }
            else
            {
                // Otherwise combine the filter on acl with any existing filters
                var securityContext = new SecurityContext
                {
                    DbContext       = dbContext,
                    UserManager     = userManager,
                    Groups          = identityService.Groups,
                    ServiceProvider = serviceProvider,
                };
                IEnumerable <Expression <Func <TModel, bool> > > acls = null;
                switch (operation)
                {
                case DATABASE_OPERATION.READ:
                    acls = userModelAcls.Select(acl => acl.GetReadConditions <TModel>(identityService.User, securityContext));
                    break;

                case DATABASE_OPERATION.UPDATE:
                    acls = userModelAcls.Select(acl => acl.GetUpdateConditions <TModel>(identityService.User, securityContext));
                    break;

                case DATABASE_OPERATION.DELETE:
                    acls = userModelAcls.Select(acl => acl.GetDeleteConditions <TModel>(identityService.User, securityContext));
                    break;

                default:
                    break;
                }

                filter = acls.Aggregate(filter, (current, expression) =>
                                        Expression.OrElse(current, expression.Body));
            }

            var param    = Expression.Parameter(typeof(TModel), "model");
            var replacer = new ParameterReplacer(param);

            return(Expression.Lambda <Func <TModel, bool> >(replacer.Visit(filter), param));
        }
Beispiel #2
0
        /// <inheritdoc />
        public async Task <BooleanObject> ConditionalUpdate <T>(
            IQueryable <T> models,
            MemberInitExpression updateMemberInitExpression,
            CancellationToken cancellation = default)
            where T : class, IOwnerAbstractModel, new()
        {
            var param         = Expression.Parameter(typeof(T), "model");
            var replacer      = new ParameterReplacer(param);
            var updateFactory = Expression.Lambda <Func <T, T> >(replacer.Visit(updateMemberInitExpression), param);
            await models.AddUpdateSecurityFiltering(_identityService, _userManager, _dbContext, _serviceProvider).UpdateAsync(updateFactory, cancellation);


            var errors = await _securityService.CheckDbSecurityChanges(_identityService, _dbContext);

            if (errors.Any())
            {
                throw new AggregateException(errors.Select(error => new InvalidOperationException(error)));
            }
            await _dbContext.SaveChangesAsync(cancellation);

            return(new BooleanObject {
                Value = true
            });
        }