// Check read authorization on all the entities of a dataset. usefull when a get, getcollection or save action is configured with includes, to make sure related objects can be read for the given user claims.
        // dataset : the dataset to check
        // entitiesToIgnore : for these entities, the check should be skipped
        // mode : define if an entity not authorized should be removed from the dataset or an exception thrown
        public PermissionLevel CheckReadAuthorizationsOnDataSet(IObjectsDataSet dataset, UserClaims claims, IEnumerable <IDataObject> entitiesToIgnore, DataSetAuthorizationCheckMode mode, Parameters parameters, out string message)
        {
            message = null;
            SecurityPredicate predicate = null;

            // Work on a clone of the dataset so as not to mess with the original (causes save problems otherwise, e.g. if main entity !IsDirty)
            dataset = dataset.Clone();

            foreach (var entity in dataset.GetAllObjects())
            {
                var permissionLevel = CanRead(entity, claims, out message, out predicate);

                if (permissionLevel != PermissionLevel.Authorized)
                {
                    if (mode == DataSetAuthorizationCheckMode.RemoveFromDataSet)
                    {
                        dataset.RemoveObject(entity);
                        continue;
                    }
                    else
                    {
                        string explanation = Explain(EntityAccessEnum.READ, GetEntityAuthorizations(entity).EntityDisplayName);
                        message = FormatAccessDeniedMessage(explanation, predicate);
                        return(PermissionLevel.Denied);
                    }
                }

                if (predicate != null)
                {
                    // If the security filter needs related data, load it first:
                    if (!String.IsNullOrEmpty(predicate.Includes))
                    {
                        DataObjectHelper.RecurseLoadIncludes(entity, parameters, predicate.Includes, skipSecurity: true);
                    }

                    if (!DoesPredicateAccept(entity, predicate.Filter, predicate.Includes, EntityAccessEnum.READ))
                    {
                        if (mode == DataSetAuthorizationCheckMode.RemoveFromDataSet)
                        {
                            dataset.RemoveObject(entity);
                            continue;
                        }
                        else
                        {
                            string explanation = Explain(EntityAccessEnum.READ, GetEntityAuthorizations(entity).EntityDisplayName);
                            message = FormatAccessDeniedMessage(explanation, predicate);
                            return(PermissionLevel.Denied);
                        }
                    }
                }
            }

            return(PermissionLevel.Authorized);
        }
        public bool IsAuthorized(
            IDataObject entity,
            SecurityPredicate predicate,
            EntityAccessEnum action,
            ref string message,
            Parameters parameters = null)
        {
            if (parameters == null)
            {
                // connect to existing transaction by using the existing parameters
                var transaction = ApplicationSettings.Resolve <ITransactionProvider>().GetTransaction(parameters) as DatabaseDataProviderTransaction;
                parameters = transaction.Parameters;
                // this following line is probably no necessary. just for safety
                parameters = parameters ?? new Parameters();
            }

            var entityAuthorizations = GetEntityAuthorizations(entity);

            // If the security filter needs related data, load related data first:
            if (!String.IsNullOrEmpty(predicate.Includes))
            {
                DataObjectHelper.RecurseLoadIncludes(entity, parameters, predicate.Includes, skipSecurity: true);
            }

            // First check the submitted data : is submitted data authorized?
            if (predicate.IsEvaluateDataset)
            {
                if (!DoesPredicateAccept(entity, predicate.DatasetFilter, predicate.Includes, action))
                {
                    string explanation = Explain(action, entityAuthorizations.EntityDisplayName);
                    message = FormatAccessDeniedMessage(explanation, predicate);
                    return(false);
                }
            }

            // Then check existing data in database
            if (predicate.IsEvaluateDatabase && !entity.IsNew)
            {
                // Important: We fetch a fresh copy (including the includes) to eliminate possibility of hacker messing with the dataset
                dynamic provider       = ApplicationSettings.Container.Resolve <IEntityDataProvider>().GetDataProviderForEntity(entity);
                var     existingEntity = provider.Get(entity, null, includes: String.IsNullOrEmpty(predicate.Includes) ? null : predicate.Includes.Split(',').ToList(), parameters: parameters, skipSecurity: true);

                if (!DoesPredicateAccept(existingEntity, predicate.DatasetFilter, predicate.Includes, action))
                {
                    string explanation = Explain(action, entityAuthorizations.EntityDisplayName);
                    message = FormatAccessDeniedMessage(explanation, predicate);
                    return(false);
                }
            }

            return(true);
        }