Skip to content

Commit

Permalink
test: in and contains are dangerous
Browse files Browse the repository at this point in the history
The `in` and `contains` operators work on multiple data types: strings
(as a substring test) and containers (as a membership test).

Unfortunately it has been observed that some authorization servers will
mix types in their responses which are processed by bexpr in auth
binding rules.

For example an authorization server may return either:

```
{"Name": "Alice", "Role": "db_admin"}
{"Name": "Bob",   "Role": ["admin", "foo"]}
```

A binding rule attempting to match on the `admin` role would be written
as:

```
admin in Role
Role contains admin
```

Unfortunately these bexpr expressions will match *both* Alice and Bob
due to substring matching.
  • Loading branch information
schmichael committed Dec 18, 2024
1 parent 381879b commit b366ded
Showing 1 changed file with 41 additions and 0 deletions.
41 changes: 41 additions & 0 deletions evaluate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -622,6 +622,47 @@ func TestCustomTag(t *testing.T) {
}
}

func TestInOnOperator(t *testing.T) {
type testStruct struct {
Role any
Match bool
}

exprs := []string{
"Role contains admin",
"admin in Role",
}
cases := []testStruct{
{
Role: []string{"admin", "foo"},
Match: true,
},
{
Role: "admin",
Match: true,
},
{
Role: "dbadmin",
Match: true, // dangerous!
},
{
Role: []string{"dbadmin", "foo"},
Match: false,
},
}

for _, q := range exprs {
expr, err := CreateEvaluator(q)
require.NoError(t, err)

for _, tc := range cases {
match, err := expr.Evaluate(tc)
require.NoError(t, err)
require.Equal(t, tc.Match, match)
}
}
}

func BenchmarkEvaluate(b *testing.B) {
for name, tcase := range evaluateTests {
// capture these values in the closure
Expand Down

0 comments on commit b366ded

Please sign in to comment.