Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion db/session.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ func (db *Db) Execute(query string, options *QueryOptions, values ...interface{}
}

func (db *Db) ExecuteNoResult(query string, options *QueryOptions, values ...interface{}) error {
return db.session.Execute(query, options, values)
return db.session.Execute(query, options, values...)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch

}

func (session *GoCqlSession) Execute(query string, options *QueryOptions, values ...interface{}) error {
Expand Down
48 changes: 35 additions & 13 deletions graphql/keyspace.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,11 @@ type dataCenterValue struct {
}

type ksValue struct {
Name string `json:"name"`
DCs []dataCenterValue `json:"dcs"`
keyspace *gocql.KeyspaceMetadata
Name string `json:"name"`
DCs []dataCenterValue `json:"dcs"`
keyspace *gocql.KeyspaceMetadata
userOrRole string
sg *SchemaGenerator
}

var dataCenterType = graphql.NewObject(graphql.ObjectConfig{
Expand Down Expand Up @@ -63,14 +65,14 @@ var keyspaceType = graphql.NewObject(graphql.ObjectConfig{
},
Resolve: func(p graphql.ResolveParams) (i interface{}, err error) {
parent := p.Source.(ksValue)
return getTables(parent.keyspace, p.Args)
return parent.sg.getTables(parent.keyspace, parent.userOrRole, p.Args)
},
},
"tables": &graphql.Field{
Type: graphql.NewList(tableType),
Resolve: func(p graphql.ResolveParams) (i interface{}, err error) {
parent := p.Source.(ksValue)
return getTables(parent.keyspace, p.Args)
return parent.sg.getTables(parent.keyspace, parent.userOrRole, p.Args)
},
},
},
Expand All @@ -84,7 +86,7 @@ func (sg *SchemaGenerator) BuildKeyspaceSchema(singleKeyspace string, ops config
})
}

func (sg *SchemaGenerator) buildKeyspaceValue(keyspace *gocql.KeyspaceMetadata) ksValue {
func (sg *SchemaGenerator) buildKeyspaceValue(keyspace *gocql.KeyspaceMetadata, userOrRole string) ksValue {
dcs := make([]dataCenterValue, 0)
if strings.Contains(keyspace.StrategyClass, "NetworkTopologyStrategy") {
for dc, replicas := range keyspace.StrategyOptions {
Expand All @@ -105,6 +107,8 @@ func (sg *SchemaGenerator) buildKeyspaceValue(keyspace *gocql.KeyspaceMetadata)
keyspace.Name,
dcs,
keyspace,
userOrRole,
sg,
}
}

Expand All @@ -120,21 +124,30 @@ func (sg *SchemaGenerator) buildKeyspaceQuery(singleKeyspace string) *graphql.Ob
},
},
Resolve: func(params graphql.ResolveParams) (interface{}, error) {
userOrRole, err := sg.checkUserOrRoleAuth(params)
if err != nil {
return nil, err
}
ksName := params.Args["name"].(string)
if sg.isKeyspaceExcludedOrNotSingle(ksName, singleKeyspace) {
if sg.isKeyspaceExcludedOrNotSingle(ksName, singleKeyspace) || !sg.checkAuthorizedForKeyspace(ksName, userOrRole) {
return nil, fmt.Errorf("keyspace does not exist '%s'", ksName)
}
keyspace, err := sg.dbClient.Keyspace(ksName)
if err != nil {
return nil, err
}

return sg.buildKeyspaceValue(keyspace), nil
return sg.buildKeyspaceValue(keyspace, userOrRole), nil
},
},
"keyspaces": &graphql.Field{
Type: graphql.NewList(keyspaceType),
Resolve: func(params graphql.ResolveParams) (interface{}, error) {
userOrRole, err := sg.checkUserOrRoleAuth(params)
if err != nil {
return nil, err
}

ksValues := make([]ksValue, 0)
if singleKeyspace == "" {
ksNames, err := sg.dbClient.Keyspaces()
Expand All @@ -143,18 +156,18 @@ func (sg *SchemaGenerator) buildKeyspaceQuery(singleKeyspace string) *graphql.Ob
}

for _, ksName := range ksNames {
if sg.isKeyspaceExcluded(ksName) {
if sg.isKeyspaceExcluded(ksName) || !sg.checkAuthorizedForKeyspace(ksName, userOrRole) {
continue
}
keyspace, err := sg.dbClient.Keyspace(ksName)
if err != nil {
return nil, err
}
ksValues = append(ksValues, sg.buildKeyspaceValue(keyspace))
ksValues = append(ksValues, sg.buildKeyspaceValue(keyspace, userOrRole))
}
} else {
} else if sg.checkAuthorizedForKeyspace(singleKeyspace, userOrRole) {
if keyspace, err := sg.dbClient.Keyspace(singleKeyspace); err == nil {
ksValues = append(ksValues, sg.buildKeyspaceValue(keyspace))
ksValues = append(ksValues, sg.buildKeyspaceValue(keyspace, userOrRole))
} else {
sg.logger.Warn("unable to get single keyspace",
"keyspace", singleKeyspace,
Expand Down Expand Up @@ -339,7 +352,7 @@ func (sg *SchemaGenerator) buildKeyspaceMutation(singleKeyspace string, ops conf
func (sg *SchemaGenerator) checkKeyspace(singleKeyspace string, p graphql.ResolveParams,
op func(params graphql.ResolveParams) (i interface{}, err error)) (i interface{}, err error) {
ksName := p.Args["keyspaceName"].(string)
if sg.isKeyspaceExcludedOrNotSingle(ksName, singleKeyspace){
if sg.isKeyspaceExcludedOrNotSingle(ksName, singleKeyspace) {
return nil, fmt.Errorf("keyspace does not exist '%s'", ksName)
}
return op(p)
Expand All @@ -349,6 +362,15 @@ func (sg *SchemaGenerator) isKeyspaceExcludedOrNotSingle(ksName string, singleKe
return sg.isKeyspaceExcluded(ksName) || singleKeyspace != "" && ksName != singleKeyspace
}

func (sg *SchemaGenerator) checkAuthorizedForKeyspace(ksName string, userOrRole string) bool {
if userOrRole == "" { // Disabled if no user or role provided
return true
}
err := sg.dbClient.ExecuteNoResult("SELECT keyspace_name FROM system_schema.keyspaces keyspace_name = ?",
db.NewQueryOptions().WithUserOrRole(userOrRole), ksName)
return err != nil
}

func getBoolArg(args map[string]interface{}, name string) bool {
if value, ok := args[name]; ok {
return value.(bool)
Expand Down
16 changes: 14 additions & 2 deletions graphql/table.go
Original file line number Diff line number Diff line change
Expand Up @@ -166,12 +166,12 @@ var tableType = graphql.NewObject(graphql.ObjectConfig{
},
})

func getTables(keyspace *gocql.KeyspaceMetadata, args map[string]interface{}) (interface{}, error) {
func (sg *SchemaGenerator) getTables(keyspace *gocql.KeyspaceMetadata, userOrRole string, args map[string]interface{}) (interface{}, error) {
if args["name"] != nil {
// Filter by name
name := args["name"].(string)
table := keyspace.Tables[name]
if table == nil {
if table == nil || !sg.checkAuthorizedForTable(keyspace.Name, name, userOrRole) {
return nil, fmt.Errorf("table does not exist '%s'", name)
}

Expand All @@ -188,6 +188,9 @@ func getTables(keyspace *gocql.KeyspaceMetadata, args map[string]interface{}) (i

tableValues := make([]*tableValue, 0)
for _, table := range keyspace.Tables {
if !sg.checkAuthorizedForTable(keyspace.Name, table.Name, userOrRole) {
continue
}
columns, err := toColumnValues(table.Columns)
if err != nil {
return nil, err
Expand Down Expand Up @@ -370,6 +373,15 @@ func (sg *SchemaGenerator) dropTable(params graphql.ResolveParams) (interface{},
return err != nil, err
}

func (sg *SchemaGenerator) checkAuthorizedForTable(ksName string, tableName string, userOrRole string) bool {
if userOrRole == "" { // Disabled if no user or role provided
return true
}
err := sg.dbClient.ExecuteNoResult("SELECT table_name FROM system_schema.tables keyspace_name = ? AND table_name = ?",
db.NewQueryOptions().WithUserOrRole(userOrRole), ksName, tableName)
return err != nil
}

func toColumnType(info gocql.TypeInfo) (*dataTypeValue, error) {
var subTypeInfo *dataTypeInfo = nil
switch info.Type() {
Expand Down