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);
        }
コード例 #2
0
        public string ExplainAccessDenied(EntityAccessEnum change, string entityDisplayName)
        {
            switch (change)
            {
            case EntityAccessEnum.READ:
                return($"Access denied: You're not authorized to view this {entityDisplayName} data");

            case EntityAccessEnum.CREATE:
                return($"Access denied: You're not authorized to create this {entityDisplayName} data");

            case EntityAccessEnum.UPDATE:
                return($"Access denied: You're not authorized to modify this {entityDisplayName} data");

            case EntityAccessEnum.DELETE:
                return($"Access denied: You're not authorized to delete this {entityDisplayName} data");

            default:
                return("Access denied");
            }
        }
        private bool DoesPredicateAccept(IDataObject entity, LambdaExpression predicate, string includes, EntityAccessEnum access)
        {
            try
            {
                return(System.Linq.Dynamic.DynamicExpression.ParseAndExecutePredicate(entity, predicate));
            }
            catch (Exception e)
            {
                // Development time exception - could make this a configuration thing if we want to be sure users never see these messages.
                // But this is a lot more helpful than allowing the default exception to bubble up - no way to know what's wrong currently.
                throw new GOServerException("securityPredicateExecutionFailure",
                                            $@"Error executing {access.ToString().ToUpper()} security predicate for entity '{entity.GetType().Name.Replace("DataObject", "")}'. 

						Predicate:
						{predicate.ToString()}

						Includes:
						{(String.IsNullOrEmpty(includes) ? "(none)" : includes)}
						
						Error:
						{(e.InnerException == null ? e.Message : e.InnerException.Message)}

						Diagnosis:
							* Is the include path correct? If not, please raise a support ticket.
							* Can any of the related entities along the include path be null? And if so, have you remembered to check for nulls in the predicate?
					"                    ,
                                            e);
            }
        }
 private static string Explain(EntityAccessEnum change, string entityDisplayName)
 {
     return(ApplicationSettings.Container.Resolve <IAuthentication>().ExplainAccessDenied(change, entityDisplayName));
 }