Exemple #1
0
        /// <summary>
        /// Invokes authorization of the request using the resource currently in context but wit
        /// an override action (e.g. for converting the "Upsert" action to either "Create" or "Update").
        /// </summary>
        /// <param name="entity">The request/entity being authorized.</param>
        /// <param name="actionUri">The action being performed with the request/entity.</param>
        protected async Task AuthorizeSingleItemAsync(T entity, string actionUri, CancellationToken cancellationToken)
        {
            // Make sure Authorization context is present before proceeding
            _authorizationContextProvider.VerifyAuthorizationContextExists();

            // Build the AuthorizationContext
            EdFiAuthorizationContext authorizationContext = new EdFiAuthorizationContext(
                ClaimsPrincipal.Current,
                _authorizationContextProvider.GetResourceUris(),
                actionUri,
                entity);

            // Authorize the call
            await _authorizationProvider.AuthorizeSingleItemAsync(authorizationContext, cancellationToken);
        }
        /// <summary>
        /// Invokes authorization of the request using the resource currently in context but wit
        /// an override action (e.g. for converting the "Upsert" action to either "Create" or "Update").
        /// </summary>
        /// <param name="entity">The request/entity being authorized.</param>
        /// <param name="actionUri">The action being performed with the request/entity.</param>
        /// <param name="cancellationToken"></param>
        protected async Task AuthorizeSingleItemAsync(TEntity entity, string actionUri, CancellationToken cancellationToken)
        {
            // Make sure Authorization context is present before proceeding
            _authorizationContextProvider.VerifyAuthorizationContextExists();

            // Build the AuthorizationContext
            var authorizationContext = new EdFiAuthorizationContext(
                _apiKeyContextProvider.GetApiKeyContext(),
                ClaimsPrincipal.Current,
                _authorizationContextProvider.GetResourceUris(),
                actionUri,
                entity);

            var authorizationBasisMetadata = _authorizationBasisMetadataSelector.SelectAuthorizationBasisMetadata(authorizationContext);

            ExecuteAuthorizationValidationRules(authorizationContext, authorizationBasisMetadata);

            // Get the authorization filtering information
            var authorizationFiltering =
                _authorizationFilteringProvider.GetAuthorizationFiltering(authorizationContext, authorizationBasisMetadata);

            var andResults = PerformInstanceBasedAuthorization(authorizationFiltering, authorizationContext, FilterOperator.And);

            // If any failures occurred with the AND strategies, throw the first exception now
            ThrowInstanceBasedFailureFromResults(andResults);

            // For remaining pending authorizations requiring database access, get the existence checks SQL fragments
            var pendingAndStrategies = andResults
                                       // Only check any strategies that have no failures
                                       .Where(x => x.FilterResults.Any(f => f.Result.State == AuthorizationState.NotPerformed))
                                       .Select(x =>
                                               new AuthorizationStrategyFilterResults
            {
                AuthorizationStrategyName = x.AuthorizationStrategyName,
                Operator      = x.Operator,
                FilterResults = x.FilterResults
                                .Where(y => y.Result.State == AuthorizationState.NotPerformed)
                                .ToArray(),
            })
                                       .ToArray();

            var orResults = PerformInstanceBasedAuthorization(authorizationFiltering, authorizationContext, FilterOperator.Or);

            bool orConditionAlreadySatisfied = orResults
                                               .Any(r => r.FilterResults.All(f => f.Result.State == AuthorizationState.Success));

            if (orConditionAlreadySatisfied || !orResults.Any())
            {
                // Check for pending ANDs
                if (pendingAndStrategies.Any())
                {
                    // Execute SQL to determine AND results
                    await PerformViewBasedAuthorizationAsync(pendingAndStrategies, authorizationContext, cancellationToken);
                }

                // We're authorized...
                return;
            }

            // We'll need to go to the database to check for relationship existence
            var pendingOrStrategies = orResults
                                      // Only check any strategies that have no failures
                                      .Where(x => x.FilterResults.All(f => f.Result.State != AuthorizationState.Failed))
                                      .Select(
                x => new AuthorizationStrategyFilterResults
            {
                AuthorizationStrategyName = x.AuthorizationStrategyName,
                Operator      = x.Operator,
                FilterResults = x.FilterResults
                                .Where(y => y.Result.State == AuthorizationState.NotPerformed)
                                .ToArray(),
            });

            var allPendingExistenceChecks =
                pendingAndStrategies.Where(x => x.FilterResults.Any())
                .Concat(pendingOrStrategies.Where(x => x.FilterResults.Any()))
                .ToArray();

            // If there are no pending view-based checks to be performed and we're still here, the authorization failure is held in the orResults
            if (!allPendingExistenceChecks.Any())
            {
                ThrowInstanceBasedFailureFromResults(orResults);
            }

            await PerformViewBasedAuthorizationAsync(allPendingExistenceChecks, authorizationContext, cancellationToken);

            bool IsCreateUpdateOrDelete(EdFiAuthorizationContext authorizationContext)
            {
                return((_bitValuesByAction.Value[authorizationContext.Action.Single().Value]
                        & (Actions.Create | Actions.Update | Actions.Delete)) != 0);
            }

            void ExecuteAuthorizationValidationRules(
                EdFiAuthorizationContext edFiAuthorizationContext,
                AuthorizationBasisMetadata authorizationBasisMetadata1)
            {
                // If there are explicit object validators, and we're modifying data
                if (_explicitObjectValidators.Any() && IsCreateUpdateOrDelete(edFiAuthorizationContext))
                {
                    // Validate the object using explicit validation
                    var validationResults = _explicitObjectValidators.ValidateObject(
                        edFiAuthorizationContext.Data,
                        authorizationBasisMetadata1.ValidationRuleSetName);

                    if (!validationResults.IsValid())
                    {
                        throw new ValidationException(
                                  string.Format(
                                      "Validation of '{0}' failed.\n{1}",
                                      edFiAuthorizationContext.Data.GetType().Name,
                                      string.Join("\n", validationResults.GetAllMessages(indentLevel: 1))));
                    }
                }
            }

            AuthorizationStrategyFilterResults[] PerformInstanceBasedAuthorization(
                IReadOnlyList <AuthorizationStrategyFiltering> authorizationStrategyFilterings,
                EdFiAuthorizationContext authorizationContext1,
                FilterOperator filterOperator)
            {
                var andResults = authorizationStrategyFilterings
                                 .Where(asf => asf.Operator == filterOperator)
                                 .Select(
                    s => new AuthorizationStrategyFilterResults
                {
                    AuthorizationStrategyName = s.AuthorizationStrategyName,
                    Operator      = s.Operator,
                    FilterResults = s.Filters
                                    .Select(
                        f => new
                    {
                        FilterDefinition = _authorizationFilterDefinitionProvider.GetFilterDefinition(f.FilterName),
                        FilterContext    = f
                    })
                                    .Select(
                        x => new FilterAuthorizationResult
                    {
                        FilterDefinition = x.FilterDefinition,
                        FilterContext    = x.FilterContext,
                        Result           = x.FilterDefinition.AuthorizeInstance(authorizationContext1, x.FilterContext)
                    })
                                    .ToArray()
                })
                                 .ToArray();

                return(andResults);
            }

            void ThrowInstanceBasedFailureFromResults(AuthorizationStrategyFilterResults[] results)
            {
                results.SelectMany(x => x.FilterResults)
                .Where(fr => fr.Result.State == AuthorizationState.Failed)
                .ForEach(fr => throw fr.Result.Exception);
            }
        }