From d572b4f7537a6f13b82a71dda8db36802fb16e7b Mon Sep 17 00:00:00 2001 From: Vikram Rangnekar Date: Sat, 23 May 2020 16:37:15 -0400 Subject: [PATCH] fix: allow unauthenticated operations in seed script --- core/api_test.go | 2 +- core/config.go | 11 +++++---- core/core.go | 3 +-- core/init.go | 12 ++++++---- .../integration_tests/integration_tests.go | 2 +- core/internal/qcode/config.go | 3 +-- core/internal/qcode/qcode.go | 2 +- internal/serv/api.go | 5 ++-- internal/serv/cmd_migrate.go | 8 +++---- internal/serv/cmd_seed.go | 5 ++-- internal/serv/cmd_serv.go | 2 +- internal/serv/config.go | 2 +- internal/serv/init.go | 23 ++++++++++--------- internal/serv/telemetry.go | 4 ++-- 14 files changed, 45 insertions(+), 39 deletions(-) diff --git a/core/api_test.go b/core/api_test.go index e22a48d..35b24b9 100644 --- a/core/api_test.go +++ b/core/api_test.go @@ -19,7 +19,7 @@ func BenchmarkGraphQL(b *testing.B) { defer db.Close() // mock.ExpectQuery(`^SELECT jsonb_build_object`).WithArgs() - c := &Config{DefaultBlock: true} + c := &Config{} sg, err := newSuperGraph(c, db, psql.GetTestDBInfo()) if err != nil { b.Fatal(err) diff --git a/core/config.go b/core/config.go index bbf80df..9c56e54 100644 --- a/core/config.go +++ b/core/config.go @@ -30,11 +30,12 @@ type Config struct { // or other database functions SetUserID bool `mapstructure:"set_user_id"` - // DefaultBlock ensures only tables configured under the `anon` role - // config can be queries if the `anon` role. For example if the table - // `users` is not listed under the anon role then it will be filtered - // out of any unauthenticated queries that mention it. - DefaultBlock bool `mapstructure:"default_block"` + // DefaultAllow reverses the blocked by default behaviour for queries in + // anonymous mode. (anon role) + // For example if the table `users` is not listed under the anon role then + // access to it would by default for unauthenticated queries this reverses + // this behavior (!!! Use with caution !!!!) + DefaultAllow bool `mapstructure:"default_allow"` // Vars is a map of hardcoded variables that can be leveraged in your // queries (eg variable admin_id will be $admin_id in the query) diff --git a/core/core.go b/core/core.go index 989249b..c1e0924 100644 --- a/core/core.go +++ b/core/core.go @@ -93,8 +93,7 @@ func (sg *SuperGraph) initCompilers() error { } sg.qc, err = qcode.NewCompiler(qcode.Config{ - DefaultBlock: sg.conf.DefaultBlock, - Blocklist: sg.conf.Blocklist, + Blocklist: sg.conf.Blocklist, }) if err != nil { return err diff --git a/core/init.go b/core/init.go index 41b1bde..187750c 100644 --- a/core/init.go +++ b/core/init.go @@ -70,8 +70,8 @@ func (sg *SuperGraph) initConfig() error { sg.roles["user"] = &ur } - // If anon role is not defined and DefaultBlock is not then then create it - if _, ok := sg.roles["anon"]; !ok && !c.DefaultBlock { + // If anon role is not defined then create it + if _, ok := sg.roles["anon"]; !ok { ur := Role{ Name: "anon", tm: make(map[string]*RoleTable), @@ -206,7 +206,7 @@ func addForeignKey(di *psql.DBInfo, c Column, t Table) error { func addRoles(c *Config, qc *qcode.Compiler) error { for _, r := range c.Roles { for _, t := range r.Tables { - if err := addRole(qc, r, t); err != nil { + if err := addRole(qc, r, t, c.DefaultAllow); err != nil { return err } } @@ -215,9 +215,13 @@ func addRoles(c *Config, qc *qcode.Compiler) error { return nil } -func addRole(qc *qcode.Compiler, r Role, t RoleTable) error { +func addRole(qc *qcode.Compiler, r Role, t RoleTable, defaultAllow bool) error { ro := true // read-only + if defaultAllow { + ro = false + } + if r.Name != "anon" { ro = false } diff --git a/core/internal/integration_tests/integration_tests.go b/core/internal/integration_tests/integration_tests.go index 6b46b84..5df06d7 100644 --- a/core/internal/integration_tests/integration_tests.go +++ b/core/internal/integration_tests/integration_tests.go @@ -50,7 +50,7 @@ func DropSchema(t *testing.T, db *sql.DB) { } func TestSuperGraph(t *testing.T, db *sql.DB, before func(t *testing.T)) { - config := core.Config{DefaultBlock: true} + config := core.Config{} config.UseAllowList = false config.AllowListFile = "./allow.list" config.RolesQuery = `SELECT * FROM users WHERE id = $user_id` diff --git a/core/internal/qcode/config.go b/core/internal/qcode/config.go index a17ce10..7082226 100644 --- a/core/internal/qcode/config.go +++ b/core/internal/qcode/config.go @@ -7,8 +7,7 @@ import ( ) type Config struct { - Blocklist []string - DefaultBlock bool + Blocklist []string } type QueryConfig struct { diff --git a/core/internal/qcode/qcode.go b/core/internal/qcode/qcode.go index 4a7b08f..4a6ca21 100644 --- a/core/internal/qcode/qcode.go +++ b/core/internal/qcode/qcode.go @@ -180,7 +180,7 @@ var expPool = sync.Pool{ } func NewCompiler(c Config) (*Compiler, error) { - co := &Compiler{db: c.DefaultBlock} + co := &Compiler{} co.tr = make(map[string]map[string]*trval) co.bl = make(map[string]struct{}, len(c.Blocklist)) diff --git a/internal/serv/api.go b/internal/serv/api.go index 60d27ac..2408085 100644 --- a/internal/serv/api.go +++ b/internal/serv/api.go @@ -52,8 +52,9 @@ type Serv struct { // Telemetry struct contains OpenCensus metrics and tracing related config Telemetry struct { - Debug bool - Metrics struct { + Debug bool + Interval *time.Duration + Metrics struct { Exporter string Endpoint string Namespace string diff --git a/internal/serv/cmd_migrate.go b/internal/serv/cmd_migrate.go index 07cd35b..5795cf6 100644 --- a/internal/serv/cmd_migrate.go +++ b/internal/serv/cmd_migrate.go @@ -55,7 +55,7 @@ func cmdDBReset(cmd *cobra.Command, args []string) { func cmdDBCreate(cmd *cobra.Command, args []string) { initConfOnce() - db, err := initDB(conf, false) + db, err := initDB(conf, false, false) if err != nil { log.Fatalf("ERR failed to connect to database: %s", err) } @@ -74,7 +74,7 @@ func cmdDBCreate(cmd *cobra.Command, args []string) { func cmdDBDrop(cmd *cobra.Command, args []string) { initConfOnce() - db, err := initDB(conf, false) + db, err := initDB(conf, false, false) if err != nil { log.Fatalf("ERR failed to connect to database: %s", err) } @@ -132,7 +132,7 @@ func cmdDBMigrate(cmd *cobra.Command, args []string) { initConfOnce() dest := args[0] - conn, err := initDB(conf, true) + conn, err := initDB(conf, true, false) if err != nil { log.Fatalf("ERR failed to connect to database: %s", err) } @@ -224,7 +224,7 @@ func cmdDBMigrate(cmd *cobra.Command, args []string) { func cmdDBStatus(cmd *cobra.Command, args []string) { initConfOnce() - db, err := initDB(conf, true) + db, err := initDB(conf, true, false) if err != nil { log.Fatalf("ERR failed to connect to database: %s", err) } diff --git a/internal/serv/cmd_seed.go b/internal/serv/cmd_seed.go index 4d31b83..5dae858 100644 --- a/internal/serv/cmd_seed.go +++ b/internal/serv/cmd_seed.go @@ -26,10 +26,9 @@ func cmdDBSeed(cmd *cobra.Command, args []string) { if conf, err = initConf(); err != nil { log.Fatalf("ERR failed to read config: %s", err) } - conf.Production = false - db, err = initDB(conf, true) + db, err = initDB(conf, true, false) if err != nil { log.Fatalf("ERR failed to connect to database: %s", err) } @@ -80,6 +79,8 @@ func graphQLFunc(sg *core.SuperGraph, query string, data interface{}, opt map[st if v, ok := opt["user_id"]; ok && len(v) != 0 { ct = context.WithValue(ct, core.UserIDKey, v) + } else { + ct = context.WithValue(ct, core.UserIDKey, "-1") } // var role string diff --git a/internal/serv/cmd_serv.go b/internal/serv/cmd_serv.go index 2ce446e..0158c31 100644 --- a/internal/serv/cmd_serv.go +++ b/internal/serv/cmd_serv.go @@ -19,7 +19,7 @@ func cmdServ(cmd *cobra.Command, args []string) { initWatcher() - db, err = initDB(conf, true) + db, err = initDB(conf, true, true) if err != nil { fatalInProd(err, "failed to connect to database") } diff --git a/internal/serv/config.go b/internal/serv/config.go index 97ff585..f432382 100644 --- a/internal/serv/config.go +++ b/internal/serv/config.go @@ -112,7 +112,7 @@ func GetConfigName() string { } func (c *Config) telemetryEnabled() bool { - return c.Telemetry.Metrics.Exporter != "" || c.Telemetry.Tracing.Exporter != "" + return c.Telemetry.Debug || c.Telemetry.Metrics.Exporter != "" || c.Telemetry.Tracing.Exporter != "" } func (c *Config) relPath(p string) string { diff --git a/internal/serv/init.go b/internal/serv/init.go index de97dcf..7d8eecd 100644 --- a/internal/serv/init.go +++ b/internal/serv/init.go @@ -111,13 +111,10 @@ func initConf() (*Config, error) { c.UseAllowList = true } - // In anon role block all tables that are not defined in the role - c.DefaultBlock = true - return c, nil } -func initDB(c *Config, useDB bool) (*sql.DB, error) { +func initDB(c *Config, useDB bool, useTelemetry bool) (*sql.DB, error) { var db *sql.DB var err error @@ -217,14 +214,22 @@ func initDB(c *Config, useDB bool) (*sql.DB, error) { // return errors.New("failed to open db") // } - if conf.telemetryEnabled() { + if useTelemetry && conf.telemetryEnabled() { driverName, err = ocsql.Register(driverName, ocsql.WithAllTraceOptions(), ocsql.WithInstanceName(conf.AppName)) if err != nil { return nil, fmt.Errorf("unable to register ocsql driver: %v", err) } - ocsql.RegisterAllViews() - //defer ocsql.RecordStats(db, 2*time.Second)() + + var interval time.Duration + + if conf.Telemetry.Interval != nil { + interval = *conf.Telemetry.Interval + } else { + interval = 5 * time.Second + } + + defer ocsql.RecordStats(db, interval)() log.Println("INF OpenCensus telemetry enabled") } @@ -242,9 +247,5 @@ func initDB(c *Config, useDB bool) (*sql.DB, error) { return nil, fmt.Errorf("unable to open db connection: %v", err) } - if conf.telemetryEnabled() { - defer ocsql.RecordStats(db, 2*time.Second)() - } - return db, nil } diff --git a/internal/serv/telemetry.go b/internal/serv/telemetry.go index 9764c6a..2551a1c 100644 --- a/internal/serv/telemetry.go +++ b/internal/serv/telemetry.go @@ -57,7 +57,7 @@ func enableObservability(mux *http.ServeMux) (func(), error) { } case "": - log.Println("INF No OpenCensus metrics exporter initialized") + log.Println("WRN OpenCensus: no metrics exporter defined") default: err = fmt.Errorf("invalid metrics exporter") @@ -96,7 +96,7 @@ func enableObservability(mux *http.ServeMux) (func(), error) { tex = zipkin.NewExporter(re, lep) case "": - log.Println("INF No OpenCensus tracing exporter initialized") + log.Println("WRN OpenCensus: no traceing exporter defined") default: err = fmt.Errorf("invalid tracing exporter")