Add RBAC option to disable functions eg. count

This commit is contained in:
Vikram Rangnekar 2019-10-27 01:52:48 -04:00
parent 4a8af69dd0
commit 34867a2733
16 changed files with 97 additions and 52 deletions

View File

@ -164,7 +164,7 @@ roles:
limit: 50 limit: 50
filters: ["{ user_id: { eq: $user_id } }"] filters: ["{ user_id: { eq: $user_id } }"]
columns: ["id", "name", "description" ] columns: ["id", "name", "description" ]
disable_aggregation: false disable_functions: false
insert: insert:
filters: ["{ user_id: { eq: $user_id } }"] filters: ["{ user_id: { eq: $user_id } }"]

View File

@ -152,7 +152,7 @@ roles:
limit: 50 limit: 50
filters: ["{ user_id: { eq: $user_id } }"] filters: ["{ user_id: { eq: $user_id } }"]
columns: ["id", "name", "description" ] columns: ["id", "name", "description" ]
disable_aggregation: false disable_functions: false
insert: insert:
filters: ["{ user_id: { eq: $user_id } }"] filters: ["{ user_id: { eq: $user_id } }"]

View File

@ -1206,7 +1206,7 @@ roles:
limit: 50 limit: 50
filters: ["{ user_id: { eq: $user_id } }"] filters: ["{ user_id: { eq: $user_id } }"]
columns: ["id", "name", "description" ] columns: ["id", "name", "description" ]
disable_aggregation: false disable_functions: false
insert: insert:
filters: ["{ user_id: { eq: $user_id } }"] filters: ["{ user_id: { eq: $user_id } }"]

View File

@ -1,32 +1,9 @@
// +build gofuzz
package jsn package jsn
import "bytes"
func Fuzz(data []byte) int { func Fuzz(data []byte) int {
err1 := Validate(string(data)) if err := unifiedTest(data); err != nil {
var b1 bytes.Buffer
err2 := Filter(&b1, data, []string{"id", "full_name", "embed"})
path1 := [][]byte{[]byte("data"), []byte("users")}
Strip(data, path1)
from := []Field{
{[]byte("__twitter_id"), []byte(`[{ "name": "hello" }, { "name": "world"}]`)},
{[]byte("__twitter_id"), []byte(`"ABC123"`)},
}
to := []Field{
{[]byte("__twitter_id"), []byte(`"1234567890"`)},
{[]byte("some_list"), []byte(`[{"id":1,"embed":{"id":8}},{"id":2},{"id":3},{"id":4},{"id":5},{"id":6},{"id":7},{"id":8},{"id":9},{"id":10},{"id":11},{"id":12},{"id":13}]`)},
}
var b2 bytes.Buffer
err3 := Replace(&b2, data, from, to)
Keys(data)
if err1 != nil || err2 != nil || err3 != nil {
return 0 return 0
} }

View File

@ -1,6 +1,8 @@
package jsn package jsn
import "testing" import (
"testing"
)
func TestFuzzCrashers(t *testing.T) { func TestFuzzCrashers(t *testing.T) {
var crashers = []string{ var crashers = []string{
@ -53,6 +55,6 @@ func TestFuzzCrashers(t *testing.T) {
} }
for _, f := range crashers { for _, f := range crashers {
Fuzz([]byte(f)) unifiedTest([]byte(f))
} }
} }

37
jsn/test.go Normal file
View File

@ -0,0 +1,37 @@
package jsn
import (
"bytes"
"errors"
)
func unifiedTest(data []byte) error {
err1 := Validate(string(data))
var b1 bytes.Buffer
err2 := Filter(&b1, data, []string{"id", "full_name", "embed"})
path1 := [][]byte{[]byte("data"), []byte("users")}
Strip(data, path1)
from := []Field{
{[]byte("__twitter_id"), []byte(`[{ "name": "hello" }, { "name": "world"}]`)},
{[]byte("__twitter_id"), []byte(`"ABC123"`)},
}
to := []Field{
{[]byte("__twitter_id"), []byte(`"1234567890"`)},
{[]byte("some_list"), []byte(`[{"id":1,"embed":{"id":8}},{"id":2},{"id":3},{"id":4},{"id":5},{"id":6},{"id":7},{"id":8},{"id":9},{"id":10},{"id":11},{"id":12},{"id":13}]`)},
}
var b2 bytes.Buffer
err3 := Replace(&b2, data, from, to)
Keys(data)
if err1 != nil || err2 != nil || err3 != nil {
return errors.New("there was an error")
}
return nil
}

View File

@ -68,7 +68,8 @@ func TestMain(m *testing.M) {
qcompile.AddRole("bad_dude", "users", qcode.TRConfig{ qcompile.AddRole("bad_dude", "users", qcode.TRConfig{
Query: qcode.QueryConfig{ Query: qcode.QueryConfig{
Filters: []string{"false"}, Filters: []string{"false"},
DisableFunctions: true,
}, },
Insert: qcode.InsertConfig{ Insert: qcode.InsertConfig{
Filters: []string{"false"}, Filters: []string{"false"},

View File

@ -373,16 +373,18 @@ func (c *compilerContext) renderJoinTable(sel *qcode.Select) error {
func (c *compilerContext) renderColumns(sel *qcode.Select, ti *DBTableInfo) { func (c *compilerContext) renderColumns(sel *qcode.Select, ti *DBTableInfo) {
i := 0 i := 0
for _, col := range sel.Cols { for _, col := range sel.Cols {
if len(sel.Allowed) != 0 { n := funcPrefixLen(col.Name)
n := funcPrefixLen(col.Name) if n != 0 {
if n != 0 { if sel.Functions == false {
if sel.Functions == false { continue
continue }
} if len(sel.Allowed) != 0 {
if _, ok := sel.Allowed[col.Name[n:]]; !ok { if _, ok := sel.Allowed[col.Name[n:]]; !ok {
continue continue
} }
} else { }
} else {
if len(sel.Allowed) != 0 {
if _, ok := sel.Allowed[col.Name]; !ok { if _, ok := sel.Allowed[col.Name]; !ok {
continue continue
} }

View File

@ -389,6 +389,7 @@ func TestCompileQuery(t *testing.T) {
t.Run("syntheticTables", syntheticTables) t.Run("syntheticTables", syntheticTables)
t.Run("queryWithVariables", queryWithVariables) t.Run("queryWithVariables", queryWithVariables)
t.Run("blockedQuery", blockedQuery) t.Run("blockedQuery", blockedQuery)
t.Run("blockedFunctions", blockedFunctions)
} }
var benchGQL = []byte(`query { var benchGQL = []byte(`query {
@ -435,6 +436,26 @@ func blockedQuery(t *testing.T) {
} }
} }
func blockedFunctions(t *testing.T) {
gql := `query {
users {
count_id
email
}
}`
sql := `SELECT json_object_agg('users', users) FROM (SELECT coalesce(json_agg("sel_json_0"), '[]') AS "users" FROM (SELECT row_to_json((SELECT "sel_0" FROM (SELECT "users_0"."email" AS "email") AS "sel_0")) AS "sel_json_0" FROM (SELECT "users"."email" FROM "users" WHERE (false) LIMIT ('20') :: integer) AS "users_0" LIMIT ('20') :: integer) AS "sel_json_agg_0") AS "done_1337"`
resSQL, err := compileGQLToPSQL(gql, nil, "bad_dude")
if err != nil {
t.Fatal(err)
}
if string(resSQL) != sql {
t.Fatal(errNotExpected)
}
}
func BenchmarkCompile(b *testing.B) { func BenchmarkCompile(b *testing.B) {
w := &bytes.Buffer{} w := &bytes.Buffer{}

View File

@ -1,3 +1,5 @@
// +build gofuzz
package qcode package qcode
// FuzzerEntrypoint for Fuzzbuzz // FuzzerEntrypoint for Fuzzbuzz

View File

@ -293,11 +293,12 @@ func (com *Compiler) compileQuery(qc *QCode, op *Operation, role string) error {
trv := com.getRole(role, field.Name) trv := com.getRole(role, field.Name)
selects = append(selects, Select{ selects = append(selects, Select{
ID: id, ID: id,
ParentID: parentID, ParentID: parentID,
Table: field.Name, Table: field.Name,
Children: make([]int32, 0, 5), Children: make([]int32, 0, 5),
Allowed: trv.allowedColumns(action), Allowed: trv.allowedColumns(action),
Functions: true,
}) })
s := &selects[(len(selects) - 1)] s := &selects[(len(selects) - 1)]

View File

@ -105,11 +105,11 @@ type configRole struct {
Name string Name string
Query struct { Query struct {
Limit int Limit int
Filters []string Filters []string
Columns []string Columns []string
DisableAggregation bool `mapstructure:"disable_aggregation"` DisableFunctions bool `mapstructure:"disable_functions"`
Block bool Block bool
} }
Insert struct { Insert struct {

View File

@ -1,3 +1,5 @@
// +build gofuzz
package serv package serv
func Fuzz(data []byte) int { func Fuzz(data []byte) int {

View File

@ -38,7 +38,7 @@ func initCompilers(c *config) (*qcode.Compiler, *psql.Compiler, error) {
Limit: t.Query.Limit, Limit: t.Query.Limit,
Filters: t.Query.Filters, Filters: t.Query.Filters,
Columns: t.Query.Columns, Columns: t.Query.Columns,
DisableFunctions: t.Query.DisableAggregation, DisableFunctions: t.Query.DisableFunctions,
} }
if t.Query.Block { if t.Query.Block {

View File

@ -164,7 +164,7 @@ roles:
limit: 50 limit: 50
filters: ["{ user_id: { eq: $user_id } }"] filters: ["{ user_id: { eq: $user_id } }"]
columns: ["id", "name", "description" ] columns: ["id", "name", "description" ]
disable_aggregation: false disable_functions: false
insert: insert:
filters: ["{ user_id: { eq: $user_id } }"] filters: ["{ user_id: { eq: $user_id } }"]

View File

@ -152,7 +152,7 @@ roles:
limit: 50 limit: 50
filters: ["{ user_id: { eq: $user_id } }"] filters: ["{ user_id: { eq: $user_id } }"]
columns: ["id", "name", "description" ] columns: ["id", "name", "description" ]
disable_aggregation: false disable_functions: false
insert: insert:
filters: ["{ user_id: { eq: $user_id } }"] filters: ["{ user_id: { eq: $user_id } }"]