Add RBAC option to disable functions eg. count
This commit is contained in:
parent
4a8af69dd0
commit
34867a2733
|
@ -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 } }"]
|
||||||
|
|
|
@ -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 } }"]
|
||||||
|
|
|
@ -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 } }"]
|
||||||
|
|
29
jsn/fuzz.go
29
jsn/fuzz.go
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
|
@ -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"},
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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{}
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
// +build gofuzz
|
||||||
|
|
||||||
package qcode
|
package qcode
|
||||||
|
|
||||||
// FuzzerEntrypoint for Fuzzbuzz
|
// FuzzerEntrypoint for Fuzzbuzz
|
||||||
|
|
|
@ -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)]
|
||||||
|
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
// +build gofuzz
|
||||||
|
|
||||||
package serv
|
package serv
|
||||||
|
|
||||||
func Fuzz(data []byte) int {
|
func Fuzz(data []byte) int {
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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 } }"]
|
||||||
|
|
|
@ -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 } }"]
|
||||||
|
|
Loading…
Reference in New Issue