Skip to content

Commit

Permalink
fix: support both slices and values in
Browse files Browse the repository at this point in the history
  • Loading branch information
fredmaggiowski committed Apr 27, 2023
1 parent 0e9f266 commit 9c3347e
Show file tree
Hide file tree
Showing 3 changed files with 93 additions and 29 deletions.
14 changes: 12 additions & 2 deletions internal/opatranslator/mongo.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
package opatranslator

import (
"reflect"

"go.mongodb.org/mongo-driver/bson"
)

Expand All @@ -30,7 +32,8 @@ const (
EqOp = "eq"
EqualOp = "equal"
NeqOp = "neq"
InOp = "internal.member_2"
// https://github.com/open-policy-agent/opa/blob/main/ast/builtins.go#L345
InOp = "internal.member_2"
)

var rangeOperatorStrategies = map[string]func(pipeline *[]bson.M, fieldName string, fieldValue interface{}){
Expand Down Expand Up @@ -60,7 +63,14 @@ func HandleEquals(pipeline *[]bson.M, fieldName string, fieldValue interface{})

// Parse the in operator into equivalent mongo query.
func HandleIn(pipeline *[]bson.M, fieldName string, fieldValue interface{}) {
filter := bson.M{fieldName: bson.M{"$in": fieldValue}}
reflectValue := reflect.ValueOf(fieldValue)

mongoInOperatorValue := fieldValue
if reflectValue.Kind() != reflect.Slice {
mongoInOperatorValue = []interface{}{fieldValue}
}

filter := bson.M{fieldName: bson.M{"$in": mongoInOperatorValue}}
*pipeline = append(*pipeline, filter)
}

Expand Down
1 change: 0 additions & 1 deletion internal/opatranslator/opa_translator.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,6 @@ func (c *OPAClient) ProcessQuery(pq *rego.PartialQueries) (bson.M, error) {
return nil, nil
}
stringifiedOperator := expr.Operator().String()
fmt.Printf("STRINGIFIED TRANSLATOR IS %s\n", stringifiedOperator)
operationHandled := HandleOperations(stringifiedOperator, pipeline, processedTerm[1], value)
if !operationHandled {
return nil, fmt.Errorf("invalid expression: operator not supported: %v", expr.Operator().String())
Expand Down
107 changes: 81 additions & 26 deletions service/handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -817,15 +817,16 @@ allow {
})

t.Run("sends filter query with $in", func(t *testing.T) {
policy := `package policies
t.Run("as array", func(t *testing.T) {

import future.keywords.in
policy := `package policies
import future.keywords.in
allow {
input.request.method == "GET"
employee := data.resources[_]
employee.membership in "member_test"
["member_test"] in employee.membership
}
allow {
Expand All @@ -836,35 +837,89 @@ allow {
}
`

mockBodySting := "I am a body"
mockBodySting := "I am a body"

body := strings.NewReader(mockBodySting)
body := strings.NewReader(mockBodySting)

partialEvaluators, err := core.SetupEvaluators(ctx, nil, &oasWithFilter, mockOPAModule, envs)
require.NoError(t, err, "Unexpected error")
partialEvaluators, err := core.SetupEvaluators(ctx, nil, &oasWithFilter, mockOPAModule, envs)
require.NoError(t, err, "Unexpected error")

ctx := createContext(t,
context.Background(),
env,
nil,
mockRondConfigWithQueryGen,
&core.OPAModuleConfig{Name: "mypolicy.rego", Content: policy},
partialEvaluators,
)
ctx := createContext(t,
context.Background(),
env,
nil,
mockRondConfigWithQueryGen,
&core.OPAModuleConfig{Name: "mypolicy.rego", Content: policy},
partialEvaluators,
)

r, err := http.NewRequestWithContext(ctx, "GET", "http://www.example.com:8080/api", body)
require.NoError(t, err, "Unexpected error")
r.Header.Set("miauserproperties", `{"name":"gianni"}`)
r.Header.Set("examplekey", "value")
r.Header.Set("Content-Type", "text/plain")
w := httptest.NewRecorder()
r, err := http.NewRequestWithContext(ctx, "GET", "http://www.example.com:8080/api", body)
require.NoError(t, err, "Unexpected error")
r.Header.Set("miauserproperties", `{"name":"gianni"}`)
r.Header.Set("examplekey", "value")
r.Header.Set("Content-Type", "text/plain")
w := httptest.NewRecorder()

rbacHandler(w, r)
rbacHandler(w, r)

require.Equal(t, http.StatusOK, w.Result().StatusCode, "Unexpected status code.")
filterQuery := r.Header.Get("rowfilterquery")
expectedQuery := `{"$or":[{"$and":[{"membership":{"$in":["member_test"]}}]},{"$and":[{"salary":{"$gt":0}}]}]}`
require.Equal(t, expectedQuery, filterQuery)
})

t.Run("as single item", func(t *testing.T) {

policy := `package policies
import future.keywords.in
allow {
input.request.method == "GET"
groups := {"groupid":123}
query := data.resources[_]
query.membership in groups.groupid
}
allow {
input.request.method == "GET"
input.request.path == "/api"
employee := data.resources[_]
employee.salary > 0
}
`

mockBodySting := "I am a body"

body := strings.NewReader(mockBodySting)

partialEvaluators, err := core.SetupEvaluators(ctx, nil, &oasWithFilter, mockOPAModule, envs)
require.NoError(t, err, "Unexpected error")

ctx := createContext(t,
context.Background(),
env,
nil,
mockRondConfigWithQueryGen,
&core.OPAModuleConfig{Name: "mypolicy.rego", Content: policy},
partialEvaluators,
)

r, err := http.NewRequestWithContext(ctx, "GET", "http://www.example.com:8080/api", body)
require.NoError(t, err, "Unexpected error")
r.Header.Set("miauserproperties", `{"name":"gianni"}`)
r.Header.Set("examplekey", "value")
r.Header.Set("Content-Type", "text/plain")
w := httptest.NewRecorder()

rbacHandler(w, r)

require.Equal(t, http.StatusOK, w.Result().StatusCode, "Unexpected status code.")
filterQuery := r.Header.Get("rowfilterquery")
expectedQuery := `{"$or":[{"$and":[{"membership":{"$in":[123]}}]},{"$and":[{"salary":{"$gt":0}}]}]}`
require.Equal(t, expectedQuery, filterQuery)
})

require.Equal(t, http.StatusOK, w.Result().StatusCode, "Unexpected status code.")
filterQuery := r.Header.Get("rowfilterquery")
expectedQuery := `{"$or":[{"$and":[{"membership":{"$in":"member_test"}}]},{"$and":[{"salary":{"$gt":0}}]}]}`
require.Equal(t, expectedQuery, filterQuery)
})

t.Run("sends empty filter query", func(t *testing.T) {
Expand Down

0 comments on commit 9c3347e

Please sign in to comment.