Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 24 additions & 1 deletion filter/filter.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,17 @@ func validateExpression(ref schema.Schema, e filter.Expression) error {
}
return nil
case *filter.AttributeExpression:
if _, err := validateAttributePath(ref, e.AttributePath); err != nil {
attr, err := validateAttributePath(ref, e.AttributePath)
if err != nil {
return err
}
resolved := attr
if sub := e.AttributePath.SubAttributeName(); sub != "" {
if a, ok := attr.SubAttributes().ContainsAttribute(sub); ok {
resolved = a
}
}
if err := validateOperator(resolved, e.Operator); err != nil {
return err
}
return nil
Expand All @@ -70,6 +80,19 @@ func validateExpression(ref schema.Schema, e filter.Expression) error {
}
}

// validateOperator checks whether the given operator is compatible with the attribute type.
// Per RFC 7644 Section 3.4.2.2, boolean and binary attributes do not support gt, lt, ge, or le.
func validateOperator(attr schema.CoreAttribute, op filter.CompareOperator) error {
switch attr.AttributeType() {
case "boolean", "binary":
switch op {
case filter.GT, filter.LT, filter.GE, filter.LE:
return fmt.Errorf("operator %q is not supported for %s attributes", op, attr.AttributeType())
}
}
return nil
}

// validateSubAttribute checks whether the given attribute name is a attribute within the given reference attribute.
func validateSubAttribute(attr schema.CoreAttribute, subAttrName string) error {
if !attr.HasSubAttributes() {
Expand Down
35 changes: 35 additions & 0 deletions filter/filter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,7 @@ func TestValidator_Validate(t *testing.T) {
`userType eq "Employee" and (emails.type eq "work")`,
`userType eq "Employee" and emails[type eq "work" and value co "@example.com"]`,
`emails[type eq "work" and value co "@example.com"] or ims[type eq "xmpp" and value co "@foo.com"]`,
`active eq true`,
} {
validator, err := filter.NewValidator(f, userSchema)
if err != nil {
Expand All @@ -222,6 +223,40 @@ func TestValidator_Validate(t *testing.T) {
}
}

func TestValidator_Validate_orderingOperatorOnBinaryAttribute(t *testing.T) {
ref := schema.Schema{
Attributes: []schema.CoreAttribute{
schema.SimpleCoreAttribute(schema.SimpleBinaryParams(schema.BinaryParams{
Name: "bin",
})),
},
}
for _, op := range []string{"gt", "lt", "ge", "le"} {
f := `bin ` + op + ` "aGVsbG8="`
validator, err := filter.NewValidator(f, ref)
if err != nil {
t.Fatal(err)
}
if err := validator.Validate(); err == nil {
t.Errorf("expected error for %q on binary attribute, got nil", f)
}
}
}

func TestValidator_Validate_orderingOperatorOnBooleanAttribute(t *testing.T) {
userSchema := schema.CoreUserSchema()
for _, op := range []string{"gt", "lt", "ge", "le"} {
f := "active " + op + " true"
validator, err := filter.NewValidator(f, userSchema)
if err != nil {
t.Fatal(err)
}
if err := validator.Validate(); err == nil {
t.Errorf("expected error for %q on boolean attribute, got nil", f)
}
}
}

func testResources() []map[string]interface{} {
return []map[string]interface{}{
{
Expand Down
Loading