Skip to content

Commit 1adc031

Browse files
committed
fix: reject ordering operators on boolean/binary attributes during validation
Validate() only checked attribute path existence, not type-operator compatibility. Filters like `active gt true` passed validation despite RFC 7644 Section 3.4.2.2 requiring a 400 response for boolean/binary attributes with gt, lt, ge, or le operators.
1 parent 74aeaa1 commit 1adc031

2 files changed

Lines changed: 59 additions & 1 deletion

File tree

‎filter/filter.go‎

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,17 @@ func validateExpression(ref schema.Schema, e filter.Expression) error {
4848
}
4949
return nil
5050
case *filter.AttributeExpression:
51-
if _, err := validateAttributePath(ref, e.AttributePath); err != nil {
51+
attr, err := validateAttributePath(ref, e.AttributePath)
52+
if err != nil {
53+
return err
54+
}
55+
resolved := attr
56+
if sub := e.AttributePath.SubAttributeName(); sub != "" {
57+
if a, ok := attr.SubAttributes().ContainsAttribute(sub); ok {
58+
resolved = a
59+
}
60+
}
61+
if err := validateOperator(resolved, e.Operator); err != nil {
5262
return err
5363
}
5464
return nil
@@ -70,6 +80,19 @@ func validateExpression(ref schema.Schema, e filter.Expression) error {
7080
}
7181
}
7282

83+
// validateOperator checks whether the given operator is compatible with the attribute type.
84+
// Per RFC 7644 Section 3.4.2.2, boolean and binary attributes do not support gt, lt, ge, or le.
85+
func validateOperator(attr schema.CoreAttribute, op filter.CompareOperator) error {
86+
switch attr.AttributeType() {
87+
case "boolean", "binary":
88+
switch op {
89+
case filter.GT, filter.LT, filter.GE, filter.LE:
90+
return fmt.Errorf("operator %q is not supported for %s attributes", op, attr.AttributeType())
91+
}
92+
}
93+
return nil
94+
}
95+
7396
// validateSubAttribute checks whether the given attribute name is a attribute within the given reference attribute.
7497
func validateSubAttribute(attr schema.CoreAttribute, subAttrName string) error {
7598
if !attr.HasSubAttributes() {

‎filter/filter_test.go‎

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,7 @@ func TestValidator_Validate(t *testing.T) {
211211
`userType eq "Employee" and (emails.type eq "work")`,
212212
`userType eq "Employee" and emails[type eq "work" and value co "@example.com"]`,
213213
`emails[type eq "work" and value co "@example.com"] or ims[type eq "xmpp" and value co "@foo.com"]`,
214+
`active eq true`,
214215
} {
215216
validator, err := filter.NewValidator(f, userSchema)
216217
if err != nil {
@@ -222,6 +223,40 @@ func TestValidator_Validate(t *testing.T) {
222223
}
223224
}
224225

226+
func TestValidator_Validate_orderingOperatorOnBinaryAttribute(t *testing.T) {
227+
ref := schema.Schema{
228+
Attributes: []schema.CoreAttribute{
229+
schema.SimpleCoreAttribute(schema.SimpleBinaryParams(schema.BinaryParams{
230+
Name: "bin",
231+
})),
232+
},
233+
}
234+
for _, op := range []string{"gt", "lt", "ge", "le"} {
235+
f := `bin ` + op + ` "aGVsbG8="`
236+
validator, err := filter.NewValidator(f, ref)
237+
if err != nil {
238+
t.Fatal(err)
239+
}
240+
if err := validator.Validate(); err == nil {
241+
t.Errorf("expected error for %q on binary attribute, got nil", f)
242+
}
243+
}
244+
}
245+
246+
func TestValidator_Validate_orderingOperatorOnBooleanAttribute(t *testing.T) {
247+
userSchema := schema.CoreUserSchema()
248+
for _, op := range []string{"gt", "lt", "ge", "le"} {
249+
f := "active " + op + " true"
250+
validator, err := filter.NewValidator(f, userSchema)
251+
if err != nil {
252+
t.Fatal(err)
253+
}
254+
if err := validator.Validate(); err == nil {
255+
t.Errorf("expected error for %q on boolean attribute, got nil", f)
256+
}
257+
}
258+
}
259+
225260
func testResources() []map[string]interface{} {
226261
return []map[string]interface{}{
227262
{

0 commit comments

Comments
 (0)