/// <summary> /// Validates a <see cref="TopQueryOption" />. /// </summary> /// <param name="selectExpandQueryOption">The $select and $expand query.</param> /// <param name="validationSettings">The validation settings.</param> public virtual void Validate(SelectExpandQueryOption selectExpandQueryOption, ODataValidationSettings validationSettings) { if (selectExpandQueryOption == null) { throw Error.ArgumentNull("selectExpandQueryOption"); } if (validationSettings == null) { throw Error.ArgumentNull("validationSettings"); } IEdmModel model = selectExpandQueryOption.Context.Model; ValidateRestrictions(selectExpandQueryOption.SelectExpandClause, model); if (validationSettings.MaxExpansionDepth > 0) { if (selectExpandQueryOption.LevelsMaxLiteralExpansionDepth > validationSettings.MaxExpansionDepth) { throw new ODataException(Error.Format( SRResources.InvalidExpansionDepthValue, "LevelsMaxLiteralExpansionDepth", "MaxExpansionDepth")); } ValidateDepth(selectExpandQueryOption.SelectExpandClause, validationSettings.MaxExpansionDepth); } }
public virtual void Validate(OrderByQueryOption orderByOption, ODataValidationSettings validationSettings) { if (orderByOption == null) { throw Error.ArgumentNull("orderByOption"); } if (validationSettings == null) { throw Error.ArgumentNull("validationSettings"); } if (validationSettings.AllowedOrderByProperties.Count > 0) { ICollection<OrderByPropertyNode> propertyNodes = orderByOption.PropertyNodes; foreach (OrderByPropertyNode property in propertyNodes) { if (!validationSettings.AllowedOrderByProperties.Contains(property.Property.Name)) { throw new ODataException(Error.Format(SRResources.NotAllowedOrderByProperty, property.Property.Name, "AllowedOrderByProperties")); } } } }
/// <summary> /// Override this method to restrict the 'all' query inside the filter query. /// </summary> /// <remarks> /// This method is intended to be called from method overrides in subclasses. This method also supports unit-testing scenarios and is not intended to be called from user code. /// Call the Validate method to validate a <see cref="FilterQueryOption"/> instance. /// </remarks> /// <param name="allNode"></param> /// <param name="settings"></param> public virtual void ValidateAllNode(AllNode allNode, ODataValidationSettings settings) { if (allNode == null) { throw Error.ArgumentNull("allNode"); } if (settings == null) { throw Error.ArgumentNull("settings"); } EnterLambda(settings); try { ValidateQueryNode(allNode.Source, settings); ValidateQueryNode(allNode.Body, settings); } finally { ExitLambda(); } }
/// <summary> /// Validates a <see cref="CountQueryOption" />. /// </summary> /// <param name="countQueryOption">The $count query.</param> /// <param name="validationSettings">The validation settings.</param> public virtual void Validate(CountQueryOption countQueryOption, ODataValidationSettings validationSettings) { if (countQueryOption == null) { throw Error.ArgumentNull("countQueryOption"); } if (validationSettings == null) { throw Error.ArgumentNull("validationSettings"); } ODataPath path = countQueryOption.Context.Path; if (path != null && path.Segments.Count > 0) { ODataPathSegment lastSegment = path.Segments.Last(); if (lastSegment is CountPathSegment && path.Segments.Count > 1) { ValidateCount(path.Segments[path.Segments.Count - 2], countQueryOption.Context.Model); } else { ValidateCount(lastSegment, countQueryOption.Context.Model); } } }
/// <summary> /// Validates the specified query options. /// </summary> /// <param name="queryOptions">The query options.</param> /// <param name="validationSettings">The validation settings.</param> /// <exception cref="ODataException">Thrown if the validation fails.</exception> internal static void Validate(ODataQueryOptions queryOptions, ODataValidationSettings validationSettings) { if (queryOptions.Filter != null) { if ((validationSettings.AllowedQueryOptions & AllowedQueryOptions.Filter) != AllowedQueryOptions.Filter) { throw new ODataException(Messages.FilterQueryOptionNotSupported); } ValidateFunctions(queryOptions.Filter.RawValue, validationSettings); ValidateStringFunctions(queryOptions.Filter.RawValue, validationSettings); ValidateDateFunctions(queryOptions.Filter.RawValue, validationSettings); ValidateMathFunctions(queryOptions.Filter.RawValue, validationSettings); ValidateLogicalOperators(queryOptions.Filter.RawValue, validationSettings); ValidateArithmeticOperators(queryOptions.Filter.RawValue, validationSettings); } if (queryOptions.RawValues.Expand != null && (validationSettings.AllowedQueryOptions & AllowedQueryOptions.Expand) != AllowedQueryOptions.Expand) { throw new ODataException(Messages.ExpandQueryOptionNotSupported); } if (queryOptions.RawValues.Format != null && (validationSettings.AllowedQueryOptions & AllowedQueryOptions.Format) != AllowedQueryOptions.Format) { throw new ODataException(Messages.FormatQueryOptionNotSupported); } if (queryOptions.RawValues.InlineCount != null && (validationSettings.AllowedQueryOptions & AllowedQueryOptions.InlineCount) != AllowedQueryOptions.InlineCount) { throw new ODataException(Messages.InlineCountQueryOptionNotSupported); } if (queryOptions.RawValues.OrderBy != null && (validationSettings.AllowedQueryOptions & AllowedQueryOptions.OrderBy) != AllowedQueryOptions.OrderBy) { throw new ODataException(Messages.OrderByQueryOptionNotSupported); } if (queryOptions.RawValues.Select != null && (validationSettings.AllowedQueryOptions & AllowedQueryOptions.Select) != AllowedQueryOptions.Select) { throw new ODataException(Messages.SelectQueryOptionNotSupported); } if (queryOptions.RawValues.Skip != null && (validationSettings.AllowedQueryOptions & AllowedQueryOptions.Skip) != AllowedQueryOptions.Skip) { throw new ODataException(Messages.SkipQueryOptionNotSupported); } if (queryOptions.RawValues.Top != null && (validationSettings.AllowedQueryOptions & AllowedQueryOptions.Top) != AllowedQueryOptions.Top) { throw new ODataException(Messages.TopQueryOptionNotSupported); } }
public void Validate_NoException_ForAllowedAndSortableUnlimitedProperty_OnEmptyAllowedPropertiesList() { // Arrange: empty allowed orderby list ODataValidationSettings settings = new ODataValidationSettings(); // Act & Assert Assert.DoesNotThrow(() => _validator.Validate(new OrderByQueryOption("Name asc", _context), settings)); }
public void ValidateAllowsOrderByIt() { // Arrange OrderByQueryOption option = new OrderByQueryOption("$it", _context); ODataValidationSettings settings = new ODataValidationSettings(); // Act & Assert Assert.DoesNotThrow(() => _validator.Validate(option, settings)); }
public void ValidatePassWhenLimitIsNotReached() { ODataValidationSettings settings = new ODataValidationSettings() { MaxSkip = 10 }; Assert.DoesNotThrow(() => _validator.Validate(new SkipQueryOption("9", _context), settings)); }
public void Validate_DoesntThrowNotSortableException_ForNotSortableProperty_OnNonEmptyAllowedPropertiesList(string property) { // Arrange : nonempty allowed orderby list ODataValidationSettings settings = new ODataValidationSettings(); settings.AllowedOrderByProperties.Add(property); // Act & Assert _validator.Validate(new OrderByQueryOption(String.Format("{0} asc", property), _context), settings); }
public void Validate_DoesntThrowUnsortableException_ForUnsortableProperty_OnNonEmptyAllowedPropertiesList() { // Arrange : nonempty allowed orderby list ODataValidationSettings settings = new ODataValidationSettings(); settings.AllowedOrderByProperties.Add("UnsortableProperty"); // Act & Assert _validator.Validate(new OrderByQueryOption("UnsortableProperty asc", _context), settings); }
public FilterQueryValidatorTest() { _validator = new MyFilterValidator(); _builder = new ODataConventionModelBuilder(); _builder.EntitySet<QueryCompositionCustomer>("Customer"); _model = _builder.GetEdmModel(); _settings = new ODataValidationSettings(); _context = new ODataQueryContext(_model, typeof(QueryCompositionCustomer)); }
public void ValidateThrowsOnUnsortable() { ODataValidationSettings settings = new ODataValidationSettings(); settings.AllowedOrderByProperties.Add("UnsortableProperty"); Assert.Throws<ODataException>(() => _validator.Validate(new OrderByQueryOption("UnsortableProperty asc", _context), settings), "The property 'UnsortableProperty' cannot be used in the $orderby query option."); }
public void ValidatePassWhenLimitIsNotReached() { ODataValidationSettings settings = new ODataValidationSettings() { MaxTop = 10 }; _validator.Validate(new TopQueryOption("9", _context), settings); }
public void ValidatePassWhenLimitIsReached() { ODataValidationSettings settings = new ODataValidationSettings() { MaxSkip = 10 }; _validator.Validate(new SkipQueryOption("10", _context), settings); }
public void Validate_ThrowsUnsortableException_ForUnsortableProperty_OnEmptyAllowedPropertiesList() { // Arrange : empty allowed orderby list ODataValidationSettings settings = new ODataValidationSettings(); // Act & Assert Assert.Throws<ODataException>(() => _validator.Validate(new OrderByQueryOption("UnsortableProperty asc", _context), settings), "The property 'UnsortableProperty' cannot be used in the $orderby query option."); }
public void ValidateAllowsOrderByIt() { // Arrange OrderByQueryOption option = new OrderByQueryOption("$it", new ODataQueryContext(EdmCoreModel.Instance, typeof(int))); ODataValidationSettings settings = new ODataValidationSettings(); // Act & Assert Assert.DoesNotThrow(() => _validator.Validate(option, settings)); }
public void ValidateAllowsOrderByIt_IfExplicitlySpecified() { // Arrange OrderByQueryOption option = new OrderByQueryOption("$it", new ODataQueryContext(EdmCoreModel.Instance, typeof(int)), queryTranslator: null); ODataValidationSettings settings = new ODataValidationSettings { AllowedOrderByProperties = { "$it" } }; // Act & Assert Assert.DoesNotThrow(() => _validator.Validate(option, settings)); }
public void Validate_ThrowsNotAllowedException_ForNotAllowedAndSortableLimitedProperty() { // Arrange ODataValidationSettings settings = new ODataValidationSettings(); settings.AllowedOrderByProperties.Add("Name"); // Act & Assert Assert.Throws<ODataException>(() => _validator.Validate(new OrderByQueryOption("UnsortableProperty asc", _context), settings), "Order by 'UnsortableProperty' is not allowed. To allow it, set the 'AllowedOrderByProperties' property on EnableQueryAttribute or QueryValidationSettings."); }
public void ValidateThrowsWhenLimitIsExceeded() { ODataValidationSettings settings = new ODataValidationSettings() { MaxSkip = 10 }; Assert.Throws<ODataException>(() => _validator.Validate(new SkipQueryOption("11", _context), settings)); }
public void ValidateWillAllowId() { // Arrange OrderByQueryOption option = new OrderByQueryOption("Id", _context); ODataValidationSettings settings = new ODataValidationSettings(); settings.AllowedOrderByProperties.Add("Id"); // Act & Assert Assert.DoesNotThrow(() => _validator.Validate(option, settings)); }
public void ValidateThrowsWhenLimitIsExceeded() { ODataValidationSettings settings = new ODataValidationSettings() { MaxSkip = 10 }; Assert.Throws<ODataException>(() => _validator.Validate(new SkipQueryOption("11", _context), settings), "The limit of '10' for Skip query has been exceeded. The value from the incoming request is '11'."); }
public void ValidateWillNotAllowName() { // Arrange OrderByQueryOption option = new OrderByQueryOption("Name", _context); ODataValidationSettings settings = new ODataValidationSettings(); settings.AllowedOrderByProperties.Add("Id"); // Act & Assert Assert.Throws<ODataException>(() => _validator.Validate(option, settings), "Order by 'Name' is not allowed. To allow it, set the 'AllowedOrderByProperties' property on QueryableAttribute or QueryValidationSettings."); }
public void Validate_ThrowsNotSortableException_ForNotSortableProperty_OnEmptyAllowedPropertiesList(string property) { // Arrange : empty allowed orderby list ODataValidationSettings settings = new ODataValidationSettings(); // Act & Assert Assert.Throws<ODataException>(() => _validator.Validate( new OrderByQueryOption(String.Format("{0} asc", property), _context), settings), String.Format("The property '{0}' cannot be used in the $orderby query option.", property)); }
public void ValidateDisallowsOrderByIt_IfTurnedOff() { // Arrange _context = new ODataQueryContext(EdmCoreModel.Instance, typeof(int)); OrderByQueryOption option = new OrderByQueryOption("$it", _context, queryTranslator: null); ODataValidationSettings settings = new ODataValidationSettings(); settings.AllowedOrderByProperties.Add("dummy"); // Act & Assert Assert.Throws<ODataException>( () => _validator.Validate(option, settings), "Order by '$it' is not allowed. To allow it, set the 'AllowedOrderByProperties' property on EnableQueryAttribute or QueryValidationSettings."); }
/// <summary> /// The entry point of this validator class. Use this method to validate the FilterQueryOption /// </summary> public virtual void Validate(FilterQueryOption filterQueryOption, ODataValidationSettings settings) { if (filterQueryOption == null) { throw Error.ArgumentNull("filterQueryOption"); } if (settings == null) { throw Error.ArgumentNull("settings"); } ValidateQueryNode(filterQueryOption.FilterClause.Expression, settings); }
public void ValidateWillNotAllowMultipleProperties() { // Arrange OrderByQueryOption option = new OrderByQueryOption("Name desc, Id asc", _context); ODataValidationSettings settings = new ODataValidationSettings(); Assert.DoesNotThrow(() => _validator.Validate(option, settings)); settings.AllowedOrderByProperties.Add("Address"); settings.AllowedOrderByProperties.Add("Name"); // Act & Assert Assert.Throws<ODataException>(() => _validator.Validate(option, settings), "Order by 'Id' is not allowed. To allow it, set the 'AllowedOrderByProperties' property on QueryableAttribute or QueryValidationSettings."); }
public void ValidateAllowOrderBy() { // Arrange HttpRequestMessage message = new HttpRequestMessage( HttpMethod.Get, new Uri("http://localhost/?$orderby=Name") ); ODataQueryOptions option = new ODataQueryOptions(_context, message); ODataValidationSettings settings = new ODataValidationSettings() { AllowedQueryOptions = AllowedQueryOptions.OrderBy }; // Act & Assert Assert.DoesNotThrow(() => _validator.Validate(option, settings)); }
/// <summary> /// Override this method to restrict the 'all' query inside the filter query /// </summary> /// <param name="allNode"></param> /// <param name="settings"></param> public virtual void ValidateAllNode(AllNode allNode, ODataValidationSettings settings) { if (allNode == null) { throw Error.ArgumentNull("allNode"); } if (settings == null) { throw Error.ArgumentNull("settings"); } ValidateQueryNode(allNode.Source, settings); ValidateQueryNode(allNode.Body, settings); }
public void Validate_Throws_DollarCountAppliedOnNotCountableCollection(string uri, string message) { // Arrange IEdmModel model = GetEdmModel(); var pathHandler = new DefaultODataPathHandler(); string serviceRoot = "http://localhost/"; ODataPath path = pathHandler.Parse(model, serviceRoot, uri); var context = new ODataQueryContext( model, EdmCoreModel.Instance.GetInt32(false).Definition, path); var option = new CountQueryOption("true", context); var settings = new ODataValidationSettings(); // Act & Assert Assert.Throws<InvalidOperationException>(() => _validator.Validate(option, settings), message); }
/// <summary> /// Validates a <see cref="SkipQueryOption" />. /// </summary> /// <param name="skipQueryOption">The $skip query.</param> /// <param name="validationSettings">The validation settings.</param> public virtual void Validate(SkipQueryOption skipQueryOption, ODataValidationSettings validationSettings) { if (skipQueryOption == null) { throw Error.ArgumentNull("skipQueryOption"); } if (validationSettings == null) { throw Error.ArgumentNull("validationSettings"); } if (skipQueryOption.Value > validationSettings.MaxSkip) { throw new ODataException(Error.Format(SRResources.SkipTopLimitExceeded, validationSettings.MaxSkip, AllowedQueryOptions.Skip, skipQueryOption.Value)); } }
public async Task <HttpResponseMessage> Get(ODataQueryOptions <Watch> options) { var validationSettings = new ODataValidationSettings { MaxTop = 100, AllowedArithmeticOperators = AllowedArithmeticOperators.None, AllowedFunctions = AllowedFunctions.None, AllowedLogicalOperators = AllowedLogicalOperators.Equal | AllowedLogicalOperators.And | AllowedLogicalOperators.GreaterThan | AllowedLogicalOperators.GreaterThanOrEqual | AllowedLogicalOperators.LessThan | AllowedLogicalOperators.LessThanOrEqual, AllowedQueryOptions = AllowedQueryOptions.Filter | AllowedQueryOptions.OrderBy | AllowedQueryOptions.Skip | AllowedQueryOptions.Top | AllowedQueryOptions.InlineCount }; validationSettings.AllowedOrderByProperties.Add("Name"); validationSettings.AllowedOrderByProperties.Add("Created"); validationSettings.AllowedOrderByProperties.Add("HitsCount"); // Validating OData try { options.Validate(validationSettings); } catch (Exception) { throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.BadRequest, ResponseMessages.InvalidQueryOptions)); } // Parsing filter parameters DataQueryOptions filter; try { filter = _mapper.Map <ODataQueryOptions, DataQueryOptions>(options); } catch (AutoMapperMappingException) { throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.BadRequest, ResponseMessages.InvalidQueryOptions)); } // Special instructions for UserId filtering DataFilterRule userIdFilter = filter.Filters.FirstOrDefault(f => string.Compare(f.Name, NameOfHelper.PropertyName <Watch>(x => x.UserId), StringComparison.OrdinalIgnoreCase) == 0 && f.Type == DataFilterTypes.Equal); if (userIdFilter == null || userIdFilter.Value == null) { // For backward compatibility we treats not specified or empty UserId as current user if (string.IsNullOrEmpty(UserId)) { throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.Unauthorized, ResponseMessages.UnathorizedRequest)); } if (userIdFilter == null) { userIdFilter = new DataFilterRule { Name = NameOfHelper.PropertyName <Watch>(x => x.UserId), Type = DataFilterTypes.Equal, Value = UserId }; filter.Filters.Add(userIdFilter); } else { userIdFilter.Value = UserId; } } else if (string.Compare(userIdFilter.Value.ToString(), UserIdAllConstant, StringComparison.OrdinalIgnoreCase) == 0) { // special constant $all means not filtering by UserId userIdFilter.Value = null; } // Retrieving projects DataResult <Watch> watchProjects; try { watchProjects = await _watchProjectRepository.GetSequenceAsync(filter, UserId); } catch (NotSupportedException) { throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.BadRequest, ResponseMessages.BadRequest)); } if (filter.Count) { var pageResult = new PageResult <Watch>(watchProjects.Results, null, watchProjects.Count); return(Request.CreateResponse(HttpStatusCode.OK, pageResult)); } return(Request.CreateResponse(HttpStatusCode.OK, watchProjects.Results)); }
/// <summary> /// Initializes a new instance of the <see cref="ODataValidationSettingsConvention"/> class. /// </summary> /// <param name="validationSettings">The <see cref="ODataValidationSettings">validation settings</see> the convention is based on.</param> /// <param name="settings">The <see cref="ODataQueryOptionSettings">settings</see> used by the convention.</param> public ODataValidationSettingsConvention(ODataValidationSettings validationSettings, ODataQueryOptionSettings settings) { ValidationSettings = validationSettings; Settings = settings; }
/// <summary> /// Validates the OData query. /// </summary> /// <param name="options">The OData query to validate.</param> /// <param name="validationSettings">The validation settings.</param> public virtual void Validate(ODataQueryOptions options, ODataValidationSettings validationSettings) { if (options == null) { throw Error.ArgumentNull("options"); } if (validationSettings == null) { throw Error.ArgumentNull("validationSettings"); } // Validate each query options if (options.Skip != null) { ValidateQueryOptionAllowed(AllowedQueryOptions.Skip, validationSettings.AllowedQueryOptions); options.Skip.Validate(validationSettings); } if (options.Top != null) { ValidateQueryOptionAllowed(AllowedQueryOptions.Top, validationSettings.AllowedQueryOptions); options.Top.Validate(validationSettings); } if (options.OrderBy != null) { ValidateQueryOptionAllowed(AllowedQueryOptions.OrderBy, validationSettings.AllowedQueryOptions); options.OrderBy.Validate(validationSettings); } if (options.Filter != null) { ValidateQueryOptionAllowed(AllowedQueryOptions.Filter, validationSettings.AllowedQueryOptions); options.Filter.Validate(validationSettings); } if (options.Count != null || ODataCountMediaTypeMapping.IsCountRequest(options.Request)) { ValidateQueryOptionAllowed(AllowedQueryOptions.Count, validationSettings.AllowedQueryOptions); if (options.Count != null) { options.Count.Validate(validationSettings); } } if (options.RawValues.Expand != null) { ValidateQueryOptionAllowed(AllowedQueryOptions.Expand, validationSettings.AllowedQueryOptions); } if (options.RawValues.Select != null) { ValidateQueryOptionAllowed(AllowedQueryOptions.Select, validationSettings.AllowedQueryOptions); } if (options.SelectExpand != null) { options.SelectExpand.Validate(validationSettings); } if (options.RawValues.Format != null) { ValidateQueryOptionAllowed(AllowedQueryOptions.Format, validationSettings.AllowedQueryOptions); } if (options.RawValues.SkipToken != null) { ValidateQueryOptionAllowed(AllowedQueryOptions.SkipToken, validationSettings.AllowedQueryOptions); } if (options.RawValues.DeltaToken != null) { ValidateQueryOptionAllowed(AllowedQueryOptions.DeltaToken, validationSettings.AllowedQueryOptions); } }
/// <summary> /// Override this method if you want to validate casts on single entities. /// </summary> /// <remarks> /// This method is intended to be called from method overrides in subclasses. This method also supports unit-testing scenarios and is not intended to be called from user code. /// Call the Validate method to validate a <see cref="FilterQueryOption"/> instance. /// </remarks> /// <param name="singleEntityCastNode"></param> /// <param name="settings"></param> public virtual void ValidateSingleEntityCastNode(SingleEntityCastNode singleEntityCastNode, ODataValidationSettings settings) { if (singleEntityCastNode == null) { throw Error.ArgumentNull("singleEntityCastNode"); } ValidateQueryNode(singleEntityCastNode.Source, settings); }
protected virtual ODataValidationSettings OnCreateODataValidationSettings() { var oDataValidationSettings = new ODataValidationSettings(); return(oDataValidationSettings); }
private static void ValidateLogicalOperators(ODataQueryOptions queryOptions, ODataValidationSettings validationSettings) { if (validationSettings.AllowedLogicalOperators == AllowedLogicalOperators.All) { return; } string rawFilterValue = queryOptions.RawValues.Filter; if ((validationSettings.AllowedLogicalOperators & AllowedLogicalOperators.And) != AllowedLogicalOperators.And && rawFilterValue.Contains(" and ")) { throw ODataException.NotImplemented("Unsupported operator and", "$filter"); } if ((validationSettings.AllowedLogicalOperators & AllowedLogicalOperators.Or) != AllowedLogicalOperators.Or && rawFilterValue.Contains(" or ")) { throw ODataException.NotImplemented("Unsupported operator or", "$filter"); } if ((validationSettings.AllowedLogicalOperators & AllowedLogicalOperators.Equal) != AllowedLogicalOperators.Equal && rawFilterValue.Contains(" eq ")) { throw ODataException.NotImplemented("Unsupported operator eq", "$filter"); } if ((validationSettings.AllowedLogicalOperators & AllowedLogicalOperators.NotEqual) != AllowedLogicalOperators.NotEqual && rawFilterValue.Contains(" ne ")) { throw ODataException.NotImplemented("Unsupported operator ne", "$filter"); } if ((validationSettings.AllowedLogicalOperators & AllowedLogicalOperators.GreaterThan) != AllowedLogicalOperators.GreaterThan && rawFilterValue.Contains(" gt ")) { throw ODataException.NotImplemented("Unsupported operator gt", "$filter"); } if ((validationSettings.AllowedLogicalOperators & AllowedLogicalOperators.GreaterThanOrEqual) != AllowedLogicalOperators.GreaterThanOrEqual && rawFilterValue.Contains(" ge ")) { throw ODataException.NotImplemented("Unsupported operator ge", "$filter"); } if ((validationSettings.AllowedLogicalOperators & AllowedLogicalOperators.LessThan) != AllowedLogicalOperators.LessThan && rawFilterValue.Contains(" lt ")) { throw ODataException.NotImplemented("Unsupported operator lt", "$filter"); } if ((validationSettings.AllowedLogicalOperators & AllowedLogicalOperators.LessThanOrEqual) != AllowedLogicalOperators.LessThanOrEqual && rawFilterValue.Contains(" le ")) { throw ODataException.NotImplemented("Unsupported operator le", "$filter"); } if ((validationSettings.AllowedLogicalOperators & AllowedLogicalOperators.Has) != AllowedLogicalOperators.Has && rawFilterValue.Contains(" has ")) { throw ODataException.NotImplemented("Unsupported operator has", "$filter"); } if ((validationSettings.AllowedLogicalOperators & AllowedLogicalOperators.Not) != AllowedLogicalOperators.Not && rawFilterValue.Contains("not ")) { throw ODataException.NotImplemented("Unsupported operator not", "$filter"); } }
private static void ValidateArithmeticOperators(ODataQueryOptions queryOptions, ODataValidationSettings validationSettings) { if (validationSettings.AllowedArithmeticOperators == AllowedArithmeticOperators.All) { return; } string rawFilterValue = queryOptions.RawValues.Filter; if ((validationSettings.AllowedArithmeticOperators & AllowedArithmeticOperators.Add) != AllowedArithmeticOperators.Add && rawFilterValue.Contains(" add ")) { throw ODataException.NotImplemented("Unsupported operator add", "$filter"); } if ((validationSettings.AllowedArithmeticOperators & AllowedArithmeticOperators.Divide) != AllowedArithmeticOperators.Divide && rawFilterValue.Contains(" div ")) { throw ODataException.NotImplemented("Unsupported operator div", "$filter"); } if ((validationSettings.AllowedArithmeticOperators & AllowedArithmeticOperators.Modulo) != AllowedArithmeticOperators.Modulo && rawFilterValue.Contains(" mod ")) { throw ODataException.NotImplemented("Unsupported operator mod", "$filter"); } if ((validationSettings.AllowedArithmeticOperators & AllowedArithmeticOperators.Multiply) != AllowedArithmeticOperators.Multiply && rawFilterValue.Contains(" mul ")) { throw ODataException.NotImplemented("Unsupported operator mul", "$filter"); } if ((validationSettings.AllowedArithmeticOperators & AllowedArithmeticOperators.Subtract) != AllowedArithmeticOperators.Subtract && rawFilterValue.Contains(" sub ")) { throw ODataException.NotImplemented("Unsupported operator sub", "$filter"); } }
/// <summary> /// override this method to restrict the binary operators inside the filter query. That includes all the logical operators except 'not' and all math operators. /// </summary> /// <remarks> /// This method is intended to be called from method overrides in subclasses. This method also supports unit-testing scenarios and is not intended to be called from user code. /// Call the Validate method to validate a <see cref="FilterQueryOption"/> instance. /// </remarks> /// <param name="binaryOperatorNode"></param> /// <param name="settings"></param> public virtual void ValidateBinaryOperatorNode(BinaryOperatorNode binaryOperatorNode, ODataValidationSettings settings) { if (binaryOperatorNode == null) { throw Error.ArgumentNull("binaryOperatorNode"); } if (settings == null) { throw Error.ArgumentNull("settings"); } // base case goes switch (binaryOperatorNode.OperatorKind) { case BinaryOperatorKind.Equal: case BinaryOperatorKind.NotEqual: case BinaryOperatorKind.And: case BinaryOperatorKind.GreaterThan: case BinaryOperatorKind.GreaterThanOrEqual: case BinaryOperatorKind.LessThan: case BinaryOperatorKind.LessThanOrEqual: case BinaryOperatorKind.Or: // binary logical operators ValidateLogicalOperator(binaryOperatorNode, settings); break; default: // math operators ValidateArithmeticOperator(binaryOperatorNode, settings); break; } }
/// <summary> /// Override this method for the Arithmetic operators, including add, sub, mul, div, mod. /// </summary> /// <remarks> /// This method is intended to be called from method overrides in subclasses. This method also supports unit-testing scenarios and is not intended to be called from user code. /// Call the Validate method to validate a <see cref="FilterQueryOption"/> instance. /// </remarks> /// <param name="binaryNode"></param> /// <param name="settings"></param> public virtual void ValidateArithmeticOperator(BinaryOperatorNode binaryNode, ODataValidationSettings settings) { if (binaryNode == null) { throw Error.ArgumentNull("binaryNode"); } if (settings == null) { throw Error.ArgumentNull("settings"); } AllowedArithmeticOperators arithmeticOperator = ToArithmeticOperator(binaryNode); if ((settings.AllowedArithmeticOperators & arithmeticOperator) != arithmeticOperator) { // this means the given logical operator is not allowed throw new ODataException(Error.Format(SRResources.NotAllowedArithmeticOperator, arithmeticOperator, "AllowedArithmeticOperators")); } // recursion case goes here ValidateQueryNode(binaryNode.Left, settings); ValidateQueryNode(binaryNode.Right, settings); }
/// <summary> /// Override this method for the navigation property node. /// </summary> /// <remarks> /// This method is intended to be called from method overrides in subclasses. This method also supports unit-testing scenarios and is not intended to be called from user code. /// Call the Validate method to validate a <see cref="FilterQueryOption"/> instance. /// </remarks> /// <param name="sourceNode"></param> /// <param name="navigationProperty"></param> /// <param name="settings"></param> public virtual void ValidateNavigationPropertyNode(QueryNode sourceNode, IEdmNavigationProperty navigationProperty, ODataValidationSettings settings) { if (settings == null) { throw Error.ArgumentNull("settings"); } // no default validation logic here // recursion if (sourceNode != null) { ValidateQueryNode(sourceNode, settings); } }
/// <summary> /// Override this method to validate collection property accessor. /// </summary> /// <remarks> /// This method is intended to be called from method overrides in subclasses. This method also supports unit-testing scenarios and is not intended to be called from user code. /// Call the Validate method to validate a <see cref="FilterQueryOption"/> instance. /// </remarks> /// <param name="propertyAccessNode"></param> /// <param name="settings"></param> public virtual void ValidateCollectionPropertyAccessNode(CollectionPropertyAccessNode propertyAccessNode, ODataValidationSettings settings) { if (propertyAccessNode == null) { throw Error.ArgumentNull("propertyAccessNode"); } if (settings == null) { throw Error.ArgumentNull("settings"); } // no default validation logic here ValidateQueryNode(propertyAccessNode.Source, settings); }
/// <summary> /// Override this method to validate Function calls, such as 'length', 'years', etc. /// </summary> /// <remarks> /// This method is intended to be called from method overrides in subclasses. This method also supports unit-testing scenarios and is not intended to be called from user code. /// Call the Validate method to validate a <see cref="FilterQueryOption"/> instance. /// </remarks> /// <param name="node"></param> /// <param name="settings"></param> public virtual void ValidateSingleValueFunctionCallNode(SingleValueFunctionCallNode node, ODataValidationSettings settings) { if (node == null) { throw Error.ArgumentNull("node"); } if (settings == null) { throw Error.ArgumentNull("settings"); } ValidateFunction(node.Name, settings); foreach (QueryNode argumentNode in node.Arguments) { ValidateQueryNode(argumentNode, settings); } }
/// <summary> /// Override this method to validate the Not operator. /// </summary> /// <remarks> /// This method is intended to be called from method overrides in subclasses. This method also supports unit-testing scenarios and is not intended to be called from user code. /// Call the Validate method to validate a <see cref="FilterQueryOption"/> instance. /// </remarks> /// <param name="unaryOperatorNode"></param> /// <param name="settings"></param> public virtual void ValidateUnaryOperatorNode(UnaryOperatorNode unaryOperatorNode, ODataValidationSettings settings) { ValidateQueryNode(unaryOperatorNode.Operand, settings); switch (unaryOperatorNode.OperatorKind) { case UnaryOperatorKind.Negate: case UnaryOperatorKind.Not: if ((settings.AllowedLogicalOperators & AllowedLogicalOperators.Not) != AllowedLogicalOperators.Not) { throw new ODataException(Error.Format(SRResources.NotAllowedLogicalOperator, unaryOperatorNode.OperatorKind, "AllowedLogicalOperators")); } break; } }
/// <summary> /// Override this method if you want to validate casts on entity collections. /// </summary> /// <remarks> /// This method is intended to be called from method overrides in subclasses. This method also supports unit-testing scenarios and is not intended to be called from user code. /// Call the Validate method to validate a <see cref="FilterQueryOption"/> instance. /// </remarks> /// <param name="entityCollectionCastNode"></param> /// <param name="settings"></param> public virtual void ValidateEntityCollectionCastNode(EntityCollectionCastNode entityCollectionCastNode, ODataValidationSettings settings) { if (entityCollectionCastNode == null) { throw Error.ArgumentNull("entityCollectionCastNode"); } ValidateQueryNode(entityCollectionCastNode.Source, settings); }
public override void Validate(FilterQueryOption filterQueryOption, ODataValidationSettings settings) { ValidateQueryNode(filterQueryOption.FilterClause.Expression, settings); }
private static void ValidateDateTimeFunctions(ODataQueryOptions queryOptions, ODataValidationSettings validationSettings) { if (validationSettings.AllowedFunctions == AllowedFunctions.AllFunctions || validationSettings.AllowedFunctions == AllowedFunctions.AllDateTimeFunctions) { return; } string rawFilterValue = queryOptions.RawValues.Filter; if ((validationSettings.AllowedFunctions & AllowedFunctions.Date) != AllowedFunctions.Date && rawFilterValue.Contains("date(")) { throw ODataException.NotImplemented("Unsupported function date", "$filter"); } if ((validationSettings.AllowedFunctions & AllowedFunctions.Day) != AllowedFunctions.Day && rawFilterValue.Contains("day(")) { throw ODataException.NotImplemented("Unsupported function day", "$filter"); } if ((validationSettings.AllowedFunctions & AllowedFunctions.FractionalSeconds) != AllowedFunctions.FractionalSeconds && rawFilterValue.Contains("fractionalseconds(")) { throw ODataException.NotImplemented("Unsupported function fractionalseconds", "$filter"); } if ((validationSettings.AllowedFunctions & AllowedFunctions.Hour) != AllowedFunctions.Hour && rawFilterValue.Contains("hour(")) { throw ODataException.NotImplemented("Unsupported function hour", "$filter"); } if ((validationSettings.AllowedFunctions & AllowedFunctions.MaxDateTime) != AllowedFunctions.MaxDateTime && rawFilterValue.Contains("maxdatetime(")) { throw ODataException.NotImplemented("Unsupported function maxdatetime", "$filter"); } if ((validationSettings.AllowedFunctions & AllowedFunctions.MinDateTime) != AllowedFunctions.MinDateTime && rawFilterValue.Contains("mindatetime(")) { throw ODataException.NotImplemented("Unsupported function mindatetime", "$filter"); } if ((validationSettings.AllowedFunctions & AllowedFunctions.Minute) != AllowedFunctions.Minute && rawFilterValue.Contains("minute(")) { throw ODataException.NotImplemented("Unsupported function minute", "$filter"); } if ((validationSettings.AllowedFunctions & AllowedFunctions.Month) != AllowedFunctions.Month && rawFilterValue.Contains("month(")) { throw ODataException.NotImplemented("Unsupported function month", "$filter"); } if ((validationSettings.AllowedFunctions & AllowedFunctions.Now) != AllowedFunctions.Now && rawFilterValue.Contains("now(")) { throw ODataException.NotImplemented("Unsupported function now", "$filter"); } if ((validationSettings.AllowedFunctions & AllowedFunctions.Second) != AllowedFunctions.Second && rawFilterValue.Contains("second(")) { throw ODataException.NotImplemented("Unsupported function second", "$filter"); } if ((validationSettings.AllowedFunctions & AllowedFunctions.Time) != AllowedFunctions.Time && (rawFilterValue.StartsWith("$filter=time(", StringComparison.Ordinal) || rawFilterValue.Contains(" time("))) { throw ODataException.NotImplemented("Unsupported function time", "$filter"); } if ((validationSettings.AllowedFunctions & AllowedFunctions.TotalOffsetMinutes) != AllowedFunctions.TotalOffsetMinutes && rawFilterValue.Contains("totaloffsetminutes(")) { throw ODataException.NotImplemented("Unsupported function totaloffsetminutes", "$filter"); } if ((validationSettings.AllowedFunctions & AllowedFunctions.TotalSeconds) != AllowedFunctions.TotalSeconds && rawFilterValue.Contains("totalseconds(")) { throw ODataException.NotImplemented("Unsupported function totalseconds", "$filter"); } if ((validationSettings.AllowedFunctions & AllowedFunctions.Year) != AllowedFunctions.Year && rawFilterValue.Contains("year(")) { throw ODataException.NotImplemented("Unsupported function year", "$filter"); } }
public override void ValidateAllNode(AllNode allNode, ODataValidationSettings settings) { base.ValidateAllNode(allNode, settings); }
private static void ValidateStringFunctions(ODataQueryOptions queryOptions, ODataValidationSettings validationSettings) { if (validationSettings.AllowedFunctions == AllowedFunctions.AllFunctions || validationSettings.AllowedFunctions == AllowedFunctions.AllStringFunctions) { return; } string rawFilterValue = queryOptions.RawValues.Filter; if ((validationSettings.AllowedFunctions & AllowedFunctions.Contains) != AllowedFunctions.Contains && rawFilterValue.Contains("contains(")) { throw ODataException.NotImplemented("Unsupported function contains", "$filter"); } if ((validationSettings.AllowedFunctions & AllowedFunctions.Concat) != AllowedFunctions.Concat && rawFilterValue.Contains("concat(")) { throw ODataException.NotImplemented("Unsupported function concat", "$filter"); } if ((validationSettings.AllowedFunctions & AllowedFunctions.EndsWith) != AllowedFunctions.EndsWith && rawFilterValue.Contains("endswith(")) { throw ODataException.NotImplemented("Unsupported function endswith", "$filter"); } if ((validationSettings.AllowedFunctions & AllowedFunctions.IndexOf) != AllowedFunctions.IndexOf && rawFilterValue.Contains("indexof(")) { throw ODataException.NotImplemented("Unsupported function indexof", "$filter"); } if ((validationSettings.AllowedFunctions & AllowedFunctions.Length) != AllowedFunctions.Length && rawFilterValue.Contains("length(")) { throw ODataException.NotImplemented("Unsupported function length", "$filter"); } if ((validationSettings.AllowedFunctions & AllowedFunctions.StartsWith) != AllowedFunctions.StartsWith && rawFilterValue.Contains("startswith(")) { throw ODataException.NotImplemented("Unsupported function startswith", "$filter"); } if ((validationSettings.AllowedFunctions & AllowedFunctions.Substring) != AllowedFunctions.Substring && rawFilterValue.Contains("substring(")) { throw ODataException.NotImplemented("Unsupported function substring", "$filter"); } if ((validationSettings.AllowedFunctions & AllowedFunctions.ToLower) != AllowedFunctions.ToLower && rawFilterValue.Contains("tolower(")) { throw ODataException.NotImplemented("Unsupported function tolower", "$filter"); } if ((validationSettings.AllowedFunctions & AllowedFunctions.ToUpper) != AllowedFunctions.ToUpper && rawFilterValue.Contains("toupper(")) { throw ODataException.NotImplemented("Unsupported function toupper", "$filter"); } if ((validationSettings.AllowedFunctions & AllowedFunctions.Trim) != AllowedFunctions.Trim && rawFilterValue.Contains("trim(")) { throw ODataException.NotImplemented("Unsupported function trim", "$filter"); } }
public override void ValidateSingleValuePropertyAccessNode(SingleValuePropertyAccessNode propertyAccessNode, ODataValidationSettings settings) { if (restrictedProperties.Contains <string>(propertyAccessNode.Property.Name)) { throw new ODataException(string.Format("{0} is an invalid filter property")); } base.ValidateSingleValuePropertyAccessNode(propertyAccessNode, settings); }
/// <summary> /// Validates a <see cref="TopQueryOption" />. /// </summary> /// <param name="selectExpandQueryOption">The $select and $expand query.</param> /// <param name="validationSettings">The validation settings.</param> public virtual void Validate(SelectExpandQueryOption selectExpandQueryOption, ODataValidationSettings validationSettings) { if (selectExpandQueryOption == null) { throw Error.ArgumentNull("selectExpandQueryOption"); } if (validationSettings == null) { throw Error.ArgumentNull("validationSettings"); } _orderByQueryValidator = new OrderByModelLimitationsValidator(selectExpandQueryOption.Context, _defaultQuerySettings.EnableOrderBy); _selectExpandQueryOption = selectExpandQueryOption; ValidateRestrictions(null, 0, selectExpandQueryOption.SelectExpandClause, null, validationSettings); if (validationSettings.MaxExpansionDepth > 0) { if (selectExpandQueryOption.LevelsMaxLiteralExpansionDepth < 0) { selectExpandQueryOption.LevelsMaxLiteralExpansionDepth = validationSettings.MaxExpansionDepth; } else if (selectExpandQueryOption.LevelsMaxLiteralExpansionDepth > validationSettings.MaxExpansionDepth) { throw new ODataException(Error.Format( SRResources.InvalidExpansionDepthValue, "LevelsMaxLiteralExpansionDepth", "MaxExpansionDepth")); } ValidateDepth(selectExpandQueryOption.SelectExpandClause, validationSettings.MaxExpansionDepth); } }
private void ValidateRestrictions( int?remainDepth, int currentDepth, SelectExpandClause selectExpandClause, IEdmNavigationProperty navigationProperty, ODataValidationSettings validationSettings) { IEdmModel edmModel = _selectExpandQueryOption.Context.Model; int? depth = remainDepth; if (remainDepth < 0) { throw new ODataException( Error.Format(SRResources.MaxExpandDepthExceeded, currentDepth - 1, "MaxExpansionDepth")); } IEdmProperty pathProperty; IEdmStructuredType pathStructuredType; if (navigationProperty == null) { pathProperty = _selectExpandQueryOption.Context.TargetProperty; pathStructuredType = _selectExpandQueryOption.Context.TargetStructuredType; } else { pathProperty = navigationProperty; pathStructuredType = navigationProperty.ToEntityType(); } foreach (SelectItem selectItem in selectExpandClause.SelectedItems) { ExpandedNavigationSelectItem expandItem = selectItem as ExpandedNavigationSelectItem; if (expandItem != null) { NavigationPropertySegment navigationSegment = (NavigationPropertySegment)expandItem.PathToNavigationProperty.LastSegment; IEdmNavigationProperty property = navigationSegment.NavigationProperty; if (EdmLibHelpers.IsNotExpandable(property, edmModel)) { throw new ODataException(Error.Format(SRResources.NotExpandablePropertyUsedInExpand, property.Name)); } if (edmModel != null) { ValidateOtherQueryOptionInExpand(property, edmModel, expandItem, validationSettings); bool isExpandable; ExpandConfiguration expandConfiguration; isExpandable = EdmLibHelpers.IsExpandable(property.Name, pathProperty, pathStructuredType, edmModel, out expandConfiguration); if (isExpandable) { int maxDepth = expandConfiguration.MaxDepth; if (maxDepth > 0 && (remainDepth == null || maxDepth < remainDepth)) { remainDepth = maxDepth; } } else if (!isExpandable) { if (!_defaultQuerySettings.EnableExpand || (expandConfiguration != null && expandConfiguration.ExpandType == SelectExpandType.Disabled)) { throw new ODataException(Error.Format(SRResources.NotExpandablePropertyUsedInExpand, property.Name)); } } } if (remainDepth.HasValue) { remainDepth--; if (expandItem.LevelsOption != null) { ValidateLevelsOption(expandItem.LevelsOption, remainDepth.Value, currentDepth + 1, edmModel, property); } } ValidateRestrictions(remainDepth, currentDepth + 1, expandItem.SelectAndExpand, property, validationSettings); remainDepth = depth; } ValidateSelectItem(selectItem, pathProperty, pathStructuredType, edmModel); } }
public void apply_to_should_use_enable_query_attribute(ApiDescription description) { // arrange var validationSettings = new ODataValidationSettings() { AllowedQueryOptions = AllowedQueryOptions.None, AllowedArithmeticOperators = AllowedArithmeticOperators.None, AllowedLogicalOperators = AllowedLogicalOperators.None, AllowedFunctions = AllowedFunctions.None, }; var settings = new TestODataQueryOptionSettings(); var convention = new ODataValidationSettingsConvention(validationSettings, settings); // act convention.ApplyTo(description); // assert description.ParameterDescriptions.Should().BeEquivalentTo( new[] { new { Name = "$select", Documentation = "Test", Source = FromUri, ParameterDescriptor = new { ParameterName = "$select", ParameterType = typeof(string), Prefix = "$", IsOptional = true, DefaultValue = default(object), } }, new { Name = "$expand", Documentation = "Test", Source = FromUri, ParameterDescriptor = new { ParameterName = "$expand", ParameterType = typeof(string), Prefix = "$", IsOptional = true, DefaultValue = default(object), } }, new { Name = "$filter", Documentation = "Test", Source = FromUri, ParameterDescriptor = new { ParameterName = "$filter", ParameterType = typeof(string), Prefix = "$", IsOptional = true, DefaultValue = default(object), } }, }, options => options.ExcludingMissingMembers()); }
public void apply_to_should_use_model_bound_query_attributes() { // arrange var builder = new ODataConventionModelBuilder().EnableLowerCamelCase(); builder.EntitySet <Order>("Orders"); var validationSettings = new ODataValidationSettings() { AllowedQueryOptions = AllowedQueryOptions.None, AllowedArithmeticOperators = AllowedArithmeticOperators.None, AllowedLogicalOperators = AllowedLogicalOperators.None, AllowedFunctions = AllowedFunctions.None, }; var settings = new TestODataQueryOptionSettings(); var convention = new ODataValidationSettingsConvention(validationSettings, settings); var model = builder.GetEdmModel(); var description = NewApiDescription(typeof(OrdersController), typeof(IEnumerable <Order>), model); // act convention.ApplyTo(description); // assert description.ParameterDescriptions.Should().BeEquivalentTo( new[] { new { Name = "$select", Documentation = "Test", Source = FromUri, ParameterDescriptor = new { ParameterName = "$select", ParameterType = typeof(string), Prefix = "$", IsOptional = true, DefaultValue = default(object), } }, new { Name = "$filter", Documentation = "Test", Source = FromUri, ParameterDescriptor = new { ParameterName = "$filter", ParameterType = typeof(string), Prefix = "$", IsOptional = true, DefaultValue = default(object), } }, new { Name = "$orderby", Documentation = "Test", Source = FromUri, ParameterDescriptor = new { ParameterName = "$orderby", ParameterType = typeof(string), Prefix = "$", IsOptional = true, DefaultValue = default(object), } }, new { Name = "$count", Documentation = "Test", Source = FromUri, ParameterDescriptor = new { ParameterName = "$count", ParameterType = typeof(bool), Prefix = "$", IsOptional = true, DefaultValue = (object)false, } }, }, options => options.ExcludingMissingMembers()); }