156 lines
4.1 KiB
Go
156 lines
4.1 KiB
Go
package influxdb
|
|
|
|
import (
|
|
"fmt"
|
|
"regexp"
|
|
"strings"
|
|
|
|
"code.google.com/p/go.crypto/bcrypt"
|
|
"github.com/influxdb/go-cache"
|
|
)
|
|
|
|
var userCache = cache.New(0, 0)
|
|
|
|
type Matcher struct {
|
|
IsRegex bool
|
|
Name string
|
|
}
|
|
|
|
func (m *Matcher) Matches(name string) bool {
|
|
if m.IsRegex {
|
|
matches, _ := regexp.MatchString(m.Name, name)
|
|
return matches
|
|
}
|
|
return m.Name == name
|
|
}
|
|
|
|
type CommonUser struct {
|
|
Name string `json:"name"`
|
|
Hash string `json:"hash"`
|
|
IsUserDeleted bool `json:"is_deleted"`
|
|
CacheKey string `json:"cache_key"`
|
|
}
|
|
|
|
func (u *CommonUser) GetName() string { return u.Name }
|
|
func (u *CommonUser) IsDeleted() bool { return u.IsUserDeleted }
|
|
func (u *CommonUser) IsClusterAdmin() bool { return false }
|
|
func (u *CommonUser) IsDbAdmin(db string) bool { return false }
|
|
func (u *CommonUser) GetDb() string { return "" }
|
|
func (u *CommonUser) HasWriteAccess(name string) bool { return false }
|
|
func (u *CommonUser) HasReadAccess(name string) bool { return false }
|
|
|
|
func (u *CommonUser) ChangePassword(hash string) error {
|
|
u.Hash = hash
|
|
userCache.Delete(u.CacheKey)
|
|
return nil
|
|
}
|
|
|
|
func (u *CommonUser) isValidPwd(password string) bool {
|
|
if pwd, ok := userCache.Get(u.CacheKey); ok {
|
|
return password == pwd.(string)
|
|
}
|
|
|
|
isValid := bcrypt.CompareHashAndPassword([]byte(u.Hash), []byte(password)) == nil
|
|
if isValid {
|
|
userCache.Set(u.CacheKey, password, 0)
|
|
}
|
|
return isValid
|
|
}
|
|
|
|
type ClusterAdmin struct {
|
|
CommonUser `json:"common"`
|
|
}
|
|
|
|
func (u *ClusterAdmin) IsClusterAdmin() bool { return true }
|
|
func (u *ClusterAdmin) IsDbAdmin(_ string) bool { return true }
|
|
func (u *ClusterAdmin) HasWriteAccess(_ string) bool { return true }
|
|
func (u *ClusterAdmin) GetWritePermission() string { return ".*" }
|
|
func (u *ClusterAdmin) HasReadAccess(_ string) bool { return true }
|
|
func (u *ClusterAdmin) GetReadPermission() string { return ".*" }
|
|
|
|
// clusterAdmins represents a list of cluster admins, sortable by name.
|
|
type clusterAdmins []*ClusterAdmin
|
|
|
|
func (p clusterAdmins) Len() int { return len(p) }
|
|
func (p clusterAdmins) Less(i, j int) bool { return p[i].Name < p[j].Name }
|
|
func (p clusterAdmins) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
|
|
|
|
type DBUser struct {
|
|
CommonUser `json:"common"`
|
|
DB string `json:"db"`
|
|
ReadFrom []*Matcher `json:"read_matchers"`
|
|
WriteTo []*Matcher `json:"write_matchers"`
|
|
IsAdmin bool `json:"is_admin"`
|
|
}
|
|
|
|
func (u *DBUser) IsDBAdmin(db string) bool {
|
|
return u.IsAdmin && u.DB == db
|
|
}
|
|
|
|
func (u *DBUser) HasWriteAccess(name string) bool {
|
|
for _, matcher := range u.WriteTo {
|
|
if matcher.Matches(name) {
|
|
return true
|
|
}
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
func (u *DBUser) GetWritePermission() string {
|
|
if len(u.WriteTo) > 0 {
|
|
matcher := u.WriteTo[0]
|
|
return matcher.Name
|
|
}
|
|
return ""
|
|
}
|
|
|
|
func (u *DBUser) HasReadAccess(name string) bool {
|
|
for _, matcher := range u.ReadFrom {
|
|
if matcher.Matches(name) {
|
|
return true
|
|
}
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
func (u *DBUser) GetReadPermission() string {
|
|
if len(u.ReadFrom) > 0 {
|
|
matcher := u.ReadFrom[0]
|
|
return matcher.Name
|
|
}
|
|
return ""
|
|
}
|
|
|
|
func (u *DBUser) GetDb() string {
|
|
return u.DB
|
|
}
|
|
|
|
func (u *DBUser) ChangePermissions(readPermissions, writePermissions string) {
|
|
u.ReadFrom = []*Matcher{{true, readPermissions}}
|
|
u.WriteTo = []*Matcher{{true, writePermissions}}
|
|
}
|
|
|
|
// dbUsers represents a list of database users, sortable by name.
|
|
type dbUsers []*DBUser
|
|
|
|
func (p dbUsers) Len() int { return len(p) }
|
|
func (p dbUsers) Less(i, j int) bool { return p[i].Name < p[j].Name }
|
|
func (p dbUsers) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
|
|
|
|
func HashPassword(password string) ([]byte, error) {
|
|
if length := len(password); length < 4 || length > 56 {
|
|
return nil, fmt.Errorf("Password must be more than 4 and less than 56 characters")
|
|
}
|
|
|
|
// The second arg is the cost of the hashing, higher is slower but makes it harder
|
|
// to brute force, since it will be really slow and impractical
|
|
return bcrypt.GenerateFromPassword([]byte(password), 10)
|
|
}
|
|
|
|
// isValidName returns true if the name contains no invalid characters.
|
|
func isValidName(name string) bool {
|
|
return !strings.Contains(name, "%")
|
|
}
|