influxdb/influx/permissions.go

261 lines
6.3 KiB
Go
Raw Normal View History

2017-02-19 06:54:52 +00:00
package influx
import (
"context"
2017-02-19 06:54:52 +00:00
"fmt"
"github.com/influxdata/chronograf"
)
var (
2017-03-10 20:53:30 +00:00
// AllowAllDB means a user gets both read and write permissions for a db
AllowAllDB = chronograf.Allowances{"WRITE", "READ"}
// AllowAllAdmin means a user gets both read and write permissions for an admin
AllowAllAdmin = chronograf.Allowances{"ALL"}
2017-02-19 06:54:52 +00:00
// AllowRead means a user is only able to read the database.
AllowRead = chronograf.Allowances{"READ"}
// AllowWrite means a user is able to only write to the database
AllowWrite = chronograf.Allowances{"WRITE"}
// NoPrivileges occasionally shows up as a response for a users grants.
NoPrivileges = "NO PRIVILEGES"
// AllPrivileges means that a user has both read and write perms
AllPrivileges = "ALL PRIVILEGES"
// All means a user has both read and write perms. Alternative to AllPrivileges
All = "ALL"
// Read means a user can read a database
Read = "READ"
// Write means a user can write to a database
Write = "WRITE"
)
// Permissions return just READ and WRITE for OSS Influx
func (c *Client) Permissions(context.Context) chronograf.Permissions {
return chronograf.Permissions{
{
Scope: chronograf.AllScope,
2017-03-10 20:53:30 +00:00
Allowed: AllowAllAdmin,
},
{
Scope: chronograf.DBScope,
2017-03-10 20:53:30 +00:00
Allowed: AllowAllDB,
},
}
}
2017-02-19 06:54:52 +00:00
// showResults is used to deserialize InfluxQL SHOW commands
type showResults []struct {
Series []struct {
Values [][]interface{} `json:"values"`
} `json:"series"`
}
// Users converts SHOW USERS to chronograf Users
func (r *showResults) Users() []chronograf.User {
res := []chronograf.User{}
for _, u := range *r {
for _, s := range u.Series {
for _, v := range s.Values {
if name, ok := v[0].(string); !ok {
continue
} else if admin, ok := v[1].(bool); !ok {
continue
} else {
c := chronograf.User{
Name: name,
Permissions: chronograf.Permissions{},
}
if admin {
c.Permissions = adminPerms()
}
res = append(res, c)
}
}
}
}
return res
}
2017-03-22 08:40:30 +00:00
// Databases converts SHOW DATABASES to chronograf Databases
func (r *showResults) Databases() []chronograf.Database {
res := []chronograf.Database{}
for _, u := range *r {
for _, s := range u.Series {
for _, v := range s.Values {
if name, ok := v[0].(string); !ok {
continue
} else {
d := chronograf.Database{Name: name}
res = append(res, d)
}
}
}
}
return res
}
2017-03-23 10:06:59 +00:00
func (r *showResults) RetentionPolicies() []chronograf.RetentionPolicy {
res := []chronograf.RetentionPolicy{}
for _, u := range *r {
for _, s := range u.Series {
for _, v := range s.Values {
if name, ok := v[0].(string); !ok {
continue
} else if duration, ok := v[1].(string); !ok {
continue
} else if sduration, ok := v[2].(string); !ok {
continue
2017-03-23 10:37:32 +00:00
} else if replication, ok := v[3].(float64); !ok {
2017-03-23 10:06:59 +00:00
continue
} else if def, ok := v[4].(bool); !ok {
continue
} else {
d := chronograf.RetentionPolicy{
Name: name,
Duration: duration,
ShardDuration: sduration,
2017-03-23 10:37:32 +00:00
Replication: int32(replication),
2017-03-23 10:06:59 +00:00
Default: def,
}
res = append(res, d)
}
}
}
}
return res
}
2017-02-19 06:54:52 +00:00
// Permissions converts SHOW GRANTS to chronograf.Permissions
func (r *showResults) Permissions() chronograf.Permissions {
res := []chronograf.Permission{}
for _, u := range *r {
for _, s := range u.Series {
for _, v := range s.Values {
if db, ok := v[0].(string); !ok {
continue
} else if priv, ok := v[1].(string); !ok {
continue
} else {
c := chronograf.Permission{
Name: db,
Scope: chronograf.DBScope,
}
switch priv {
case AllPrivileges, All:
2017-03-10 20:53:30 +00:00
c.Allowed = AllowAllDB
2017-02-19 06:54:52 +00:00
case Read:
c.Allowed = AllowRead
case Write:
c.Allowed = AllowWrite
default:
// sometimes influx reports back NO PRIVILEGES
continue
}
res = append(res, c)
}
}
}
}
return res
}
func adminPerms() chronograf.Permissions {
return []chronograf.Permission{
{
Scope: chronograf.AllScope,
2017-03-10 20:53:30 +00:00
Allowed: AllowAllAdmin,
2017-02-19 06:54:52 +00:00
},
}
}
// ToInfluxQL converts the permission into InfluxQL
func ToInfluxQL(action, preposition, username string, perm chronograf.Permission) string {
if perm.Scope == chronograf.AllScope {
return fmt.Sprintf(`%s ALL PRIVILEGES %s "%s"`, action, preposition, username)
} else if len(perm.Allowed) == 0 {
// All privileges are to be removed for this user on this database
return fmt.Sprintf(`%s ALL PRIVILEGES ON "%s" %s "%s"`, action, perm.Name, preposition, username)
}
priv := ToPriv(perm.Allowed)
if priv == NoPrivileges {
return ""
}
return fmt.Sprintf(`%s %s ON "%s" %s "%s"`, action, priv, perm.Name, preposition, username)
}
// ToRevoke converts the permission into InfluxQL revokes
func ToRevoke(username string, perm chronograf.Permission) string {
return ToInfluxQL("REVOKE", "FROM", username, perm)
}
// ToGrant converts the permission into InfluxQL grants
func ToGrant(username string, perm chronograf.Permission) string {
if len(perm.Allowed) == 0 {
return ""
}
2017-02-19 06:54:52 +00:00
return ToInfluxQL("GRANT", "TO", username, perm)
}
// ToPriv converts chronograf allowances to InfluxQL
func ToPriv(a chronograf.Allowances) string {
if len(a) == 0 {
return NoPrivileges
}
hasWrite := false
hasRead := false
for _, aa := range a {
if aa == Read {
hasRead = true
} else if aa == Write {
hasWrite = true
} else if aa == All {
hasRead, hasWrite = true, true
}
}
if hasWrite && hasRead {
return All
} else if hasWrite {
return Write
} else if hasRead {
return Read
}
return NoPrivileges
}
// Difference compares two permission sets and returns a set to be revoked and a set to be added
func Difference(wants chronograf.Permissions, haves chronograf.Permissions) (revoke chronograf.Permissions, add chronograf.Permissions) {
for _, want := range wants {
found := false
for _, got := range haves {
if want.Scope != got.Scope || want.Name != got.Name {
continue
}
found = true
if len(want.Allowed) == 0 {
revoke = append(revoke, want)
} else {
add = append(add, want)
}
break
}
if !found {
add = append(add, want)
}
}
for _, got := range haves {
found := false
for _, want := range wants {
if want.Scope != got.Scope || want.Name != got.Name {
continue
}
found = true
break
}
if !found {
revoke = append(revoke, got)
}
}
return
}