WebApi icon indicating copy to clipboard operation
WebApi copied to clipboard

Filter on a property is being allowed, even though attribute is set as not filterable using Filter Attribute [Filter(Disabled = true)]

Open reddaiahnethi opened this issue 4 years ago • 2 comments

Filter on a property is being allowed, even though attribute is set as not filterable using Filter Attribute [Filter(Disabled = true)]

Assemblies affected

Microsoft.AspNetCore.OData 7.4.0

Reproduce steps

Define a property as filterable false as shown below

 public class CosmosBaseEntity : IBaseEntity
    {
        /// <summary>
        /// Gets or sets the identifier.
        /// </summary>
        [JsonProperty("id")]
        [ExcludeFromResponse]
        [System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.NamingRules", "SA1300:Element should begin with upper-case letter", Justification = "for Cosmos")]
        public string id { get; set; }

        /// <summary>
        /// Gets or sets the type of the entity.
        /// </summary>
        [ExcludeFromResponse]
        public string EntityType { get; set; }

        /// <summary>
        /// Gets or sets the type of the partition key of Document.
        /// </summary>
        [ExcludeFromResponse]
        public string PartitionKey { get; set; }

        /// <summary>
        /// Gets or sets the action.
        /// </summary>
        [ExcludeFromResponse]
        public string Action { get; set; }

        /// <summary>
        /// Gets or sets a value indicating whether deleted.
        /// </summary>
        /// <value>
        ///   <c>true</c> if this instance is deleted; otherwise, <c>false</c>.
        /// </value>
        [ExcludeFromResponse]
        public bool? IsDeleted { get; set; }

        /// <summary>
        /// Gets or sets CreatedBy.
        /// </summary>
        [Filter(Disabled = true)]
        public string CreatedBy { get; set; }

        /// <summary>
        /// Gets or sets SourceCreatedOn.
        /// </summary>
        public DateTime CreatedOn { get; set; }

        /// <summary>
        /// Gets or sets ModifiedBy.
        /// </summary>
        public string ModifiedBy { get; set; }

        /// <summary>
        /// Gets or sets ModifiedOn.
        /// </summary>
        public DateTime ModifiedOn { get; set; }

        /// <summary>
        /// Gets or sets the e tag.
        /// </summary>
        [JsonProperty(PropertyName= "_etag")]
        [ExcludeFromResponse]
        public string ETag { get; set; }
    }

public class Candidate : CosmosBaseEntity
    {
        /// <summary>
        /// Gets or sets CandidateId.
        /// </summary>
        [Key]
        public int CandidateId { get; set; }

        /// <summary>
        /// Gets or sets the first name of the candidate.
        /// </summary>
        /// <value>
        /// The first name of the candidate.
        /// </value>
        public string CandidateFirstName { get; set; }

        /// <summary>
        /// Gets or sets the last name of the candidate.
        /// </summary>
        /// <value>
        /// The last name of the candidate.
        /// </value>
        public string CandidateLastName { get; set; }

        /// <summary>
        /// Gets or sets the name of the candidate middle.
        /// </summary>
        /// <value>
        /// The name of the candidate middle.
        /// </value>
        public string CandidateMiddleName { get; set; }

        /// <summary>
        /// Gets or sets the first name of the candidate preferred.
        /// </summary>
        /// <value>
        /// The first name of the candidate preferred.
        /// </value>
        public string CandidatePreferredFirstName { get; set; }
        
    }

And in the controller

validate the filters as below


[HttpGet]
        [ODataRoute]
        [Authorize]
        [EnableQuery(PageSize = 100)]
        public ActionResult<IQueryable<Candidate>> Get(ODataQueryOptions<Candidate> options)
        {
            var traceProps = new Dictionary<string, string>();
            traceProps[Constants.Filter] = options.Filter?.RawValue;
            this.logger.TraceInformation("In OData Candidate", traceProps);
            options.Filter?.Validate(new ODataValidationSettings { });
            var candidates = this.Cosmos.GetAllByEntityType<Candidate>(Constants.Candidate);
            return this.Ok(candidates);
        }

Expected result

If filter applied on the attributes which are set to disabled. It should not allow

Actual result

Filtering is allowed

Additional detail

*Its a simple repro, have a Filter attribute on any property. In Odata filter use that https://localhost:44371/odata/candidate?$filter=createdBy eq 'MICROSOFT' *

reddaiahnethi avatar Jun 18 '20 09:06 reddaiahnethi

@reddaiahnethi I looked at this issue while investigating #2203. What I found is that if you applied FilterAttribute at the class level and supply the list of properties that the rule applies to, it works, e.g.

[Filter("Property1", "InheritedProperty1", "etc", Disabled = true)]
public class Candidate
{
// ...
}

We'll need to figure out why it's ignored when applied to the property directly, unless it's not intended to work that way - https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnet.odata.query.filterattribute?view=odata-aspnetcore-7.0 cc. @Sreejithpin

gathogojr avatar Jun 29 '20 14:06 gathogojr

@gathogojr I tried setting allowing filtering and it didn't work either on the property level, for the latest version of OData (but at class level it worked).

In case it doesn't work at property level and only works at class level, it would be easier if the attribute had at the top (to disallow misusage): [AttributeUsage(AttributeTargets.Class)]

alexandruchirita4192 avatar Jan 14 '22 14:01 alexandruchirita4192