private static IScopesEvaluator GetNavigationPropertyPropertyOperationPermisions(IList <ODataPathSegment> pathSegments, bool isTargetByKey, IEdmModel model, string method)
        {
            if (pathSegments.Count <= 1)
            {
                return(new DefaultScopesEvaluator());
            }

            var expectedPath = GetPathFromSegments(pathSegments);
            IEdmVocabularyAnnotatable root = (pathSegments[0] as EntitySetSegment).EntitySet as IEdmVocabularyAnnotatable ?? (pathSegments[0] as SingletonSegment).Singleton;

            var navRestrictions = root.VocabularyAnnotations(model).Where(a => a.Term.FullName() == ODataCapabilityRestrictionsConstants.NavigationRestrictions);

            foreach (var restriction in navRestrictions)
            {
                if (restriction.Value is IEdmRecordExpression record)
                {
                    var temp = record.FindProperty("RestrictedProperties");
                    if (temp?.Value is IEdmCollectionExpression restrictedProperties)
                    {
                        foreach (var item in restrictedProperties.Elements)
                        {
                            if (item is IEdmRecordExpression restrictedProperty)
                            {
                                var navigationProperty = restrictedProperty.FindProperty("NavigationProperty").Value as IEdmPathExpression;
                                if (navigationProperty?.Path == expectedPath)

                                {
                                    if (method == "GET")
                                    {
                                        var readRestrictions = restrictedProperty.FindProperty("ReadRestrictions")?.Value as IEdmRecordExpression;

                                        var readPermissions = ExtractPermissionsFromRecord(readRestrictions);
                                        var evaluator       = new WithOrScopesCombiner(readPermissions);

                                        if (isTargetByKey)
                                        {
                                            var readByKeyRestrictions = readRestrictions.FindProperty("ReadByKeyRestrictions")?.Value as IEdmRecordExpression;
                                            var readByKeyPermissions  = ExtractPermissionsFromRecord(readByKeyRestrictions);
                                            evaluator.AddRange(readByKeyPermissions);
                                        }

                                        return(evaluator);
                                    }
                                    else if (method == "POST" || method == "PATCH" || method == "PUT" || method == "MERGE" || method == "DELETE")
                                    {
                                        var updateRestrictions = restrictedProperty.FindProperty("UpdateRestrictions")?.Value as IEdmRecordExpression;
                                        var updatePermissions  = ExtractPermissionsFromRecord(updateRestrictions);
                                        return(new WithOrScopesCombiner(updatePermissions));
                                    }
                                }
                            }
                        }
                    }
                }
            }

            return(new DefaultScopesEvaluator());
        }
        private static IScopesEvaluator GetReadByKeyPermissions(IEnumerable <IEdmVocabularyAnnotation> annotations)
        {
            var evaluator = new WithOrScopesCombiner();

            foreach (var annotation in annotations)
            {
                if (annotation.Term.FullName() == ODataCapabilityRestrictionsConstants.ReadRestrictions && annotation.Value is IEdmRecordExpression record)
                {
                    var readPermissions = ExtractPermissionsFromAnnotation(annotation);
                    evaluator.AddRange(readPermissions);

                    var readByKeyProperty    = record.FindProperty("ReadByKeyRestrictions");
                    var readByKeyValue       = readByKeyProperty?.Value as IEdmRecordExpression;
                    var permissionsProperty  = readByKeyValue?.FindProperty("Permissions");
                    var readByKeyPermissions = ExtractPermissionsFromProperty(permissionsProperty);
                    evaluator.AddRange(readByKeyPermissions);
                }
            }

            return(evaluator);
        }
        internal static IScopesEvaluator ExtractPermissionsForRequest(this IEdmModel model, string method, AspNet.OData.Routing.ODataPath odataPath)
        {
            var template = odataPath.PathTemplate;
            ODataPathSegment prevSegment = null;

            var segments = new List <ODataPathSegment>();

            // this combines the permission scopes across path segments
            // with a logical AND
            var permissionsChain = new WithAndScopesCombiner();

            var lastSegmentIndex = odataPath.Segments.Count - 1;

            if (template.EndsWith("$ref", StringComparison.OrdinalIgnoreCase))
            {
                // for ref segments, we apply the permission of the entity that contains the navigation property
                // e.g. for GET Customers(10)/Products/$ref, we apply the read key permissions of Customers
                // for GET TopCustomer/Products/$ref, we apply the read permissions of TopCustomer
                // for DELETE Customers(10)/Products(10)/$ref we apply the update permissions of Customers
                lastSegmentIndex = odataPath.Segments.Count - 2;
                while (!(odataPath.Segments[lastSegmentIndex] is KeySegment || odataPath.Segments[lastSegmentIndex] is SingletonSegment || odataPath.Segments[lastSegmentIndex] is NavigationPropertySegment) &&
                       lastSegmentIndex > 0)
                {
                    lastSegmentIndex--;
                }
            }

            for (int i = 0; i <= lastSegmentIndex; i++)
            {
                var segment = odataPath.Segments[i];

                if (segment is EntitySetSegment ||
                    segment is SingletonSegment ||
                    segment is NavigationPropertySegment ||
                    segment is OperationSegment ||
                    segment is OperationImportSegment ||
                    segment is KeySegment ||
                    segment is PropertySegment)
                {
                    var parent           = prevSegment;
                    var isPropertyAccess = IsNextSegmentOfType <PropertySegment>(odataPath, i) ||
                                           IsNextSegmentOfType <NavigationPropertyLinkSegment>(odataPath, i) ||
                                           IsNextSegmentOfType <NavigationPropertySegment>(odataPath, i);
                    prevSegment = segment;
                    segments.Add(segment);

                    // if nested segment, extract navigation restrictions of root

                    // else extract entity/set  restrictions
                    if (segment is EntitySetSegment entitySetSegment)
                    {
                        // if Customers(key), then we'll handle it when we reach the key segment
                        // so that we can properly handle ReadByKeyRestrictions
                        if (IsNextSegmentKey(odataPath, i))
                        {
                            continue;
                        }

                        // if Customers/UnboundFunction, then we'll handle it when we reach the operation segment
                        if (IsNextSegmentOfType <OperationSegment>(odataPath, i))
                        {
                            continue;
                        }

                        IScopesEvaluator permissions;

                        permissions = GetNavigationPropertyCrudPermisions(
                            segments,
                            false,
                            model,
                            method);

                        if (permissions is DefaultScopesEvaluator)
                        {
                            permissions = GetNavigationSourceCrudPermissions(entitySetSegment.EntitySet, model, method);
                        }

                        var handler = new WithOrScopesCombiner(permissions);
                        permissionsChain.Add(handler);
                    }
                    else if (segment is SingletonSegment singletonSegment)
                    {
                        // if Customers/UnboundFunction, then we'll handle it when we reach the operation segment
                        if (IsNextSegmentOfType <OperationSegment>(odataPath, i))
                        {
                            continue;
                        }

                        if (isPropertyAccess)
                        {
                            var propertyPermissions = GetSingletonPropertyOperationPermissions(singletonSegment.Singleton, model, method);
                            permissionsChain.Add(new WithOrScopesCombiner(propertyPermissions));
                        }
                        else
                        {
                            var permissions = GetNavigationSourceCrudPermissions(singletonSegment.Singleton, model, method);
                            permissionsChain.Add(new WithOrScopesCombiner(permissions));
                        }
                    }
                    else if (segment is KeySegment keySegment)
                    {
                        // if Customers/UnboundFunction, then we'll handle it when we reach the operation segment
                        if (IsNextSegmentOfType <OperationSegment>(odataPath, i))
                        {
                            continue;
                        }

                        var entitySet   = keySegment.NavigationSource as IEdmEntitySet;
                        var permissions = isPropertyAccess ?
                                          GetEntityPropertyOperationPermissions(entitySet, model, method) :
                                          GetEntityCrudPermissions(entitySet, model, method);

                        var evaluator = new WithOrScopesCombiner(permissions);


                        if (parent is NavigationPropertySegment)
                        {
                            var nestedPermissions = isPropertyAccess ?
                                                    GetNavigationPropertyPropertyOperationPermisions(segments, isTargetByKey: true, model, method) :
                                                    GetNavigationPropertyCrudPermisions(segments, isTargetByKey: true, model, method);

                            evaluator.Add(nestedPermissions);
                        }


                        permissionsChain.Add(evaluator);
                    }
                    else if (segment is NavigationPropertySegment navSegment)
                    {
                        // if Customers/UnboundFunction, then we'll handle it when we reach there
                        if (IsNextSegmentOfType <OperationSegment>(odataPath, i))
                        {
                            continue;
                        }


                        // if Customers(key), then we'll handle it when we reach the key segment
                        // so that we can properly handle ReadByKeyRestrictions
                        if (IsNextSegmentKey(odataPath, i))
                        {
                            continue;
                        }

                        var topLevelPermissions = GetNavigationSourceCrudPermissions(navSegment.NavigationSource as IEdmVocabularyAnnotatable, model, method);
                        var segmentEvaluator    = new WithOrScopesCombiner(topLevelPermissions);

                        var nestedPermissions = GetNavigationPropertyCrudPermisions(
                            segments,
                            isTargetByKey: false,
                            model,
                            method);


                        segmentEvaluator.Add(nestedPermissions);
                        permissionsChain.Add(segmentEvaluator);
                    }
                    else if (segment is OperationImportSegment operationImportSegment)
                    {
                        var annotations = operationImportSegment.OperationImports.First().Operation.VocabularyAnnotations(model);
                        var permissions = GetOperationPermissions(annotations);
                        permissionsChain.Add(new WithOrScopesCombiner(permissions));
                    }
                    else if (segment is OperationSegment operationSegment)
                    {
                        var annotations          = operationSegment.Operations.First().VocabularyAnnotations(model);
                        var operationPermissions = GetOperationPermissions(annotations);
                        permissionsChain.Add(new WithOrScopesCombiner(operationPermissions));
                    }
                }
            }

            return(permissionsChain);
        }