add read/write access information to the user structure.
parent
b4851b712e
commit
429fdcf0b9
|
@ -100,12 +100,100 @@ func (self *User) RemoveDbAdmin(u *User, db string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (self *User) AddReadMatcher(u *User, m *protocol.Matcher) error {
|
||||
var err error
|
||||
u.u.ReadFrom, err = self.addMatcher(u, m, u.u.ReadFrom)
|
||||
return err
|
||||
}
|
||||
|
||||
func (self *User) RemoveReadMatcher(u *User, m *protocol.Matcher) error {
|
||||
var err error
|
||||
u.u.ReadFrom, err = self.removeMatcher(u, m, u.u.ReadFrom)
|
||||
return err
|
||||
}
|
||||
|
||||
func (self *User) AddWriteMatcher(u *User, m *protocol.Matcher) error {
|
||||
var err error
|
||||
u.u.WriteTo, err = self.addMatcher(u, m, u.u.WriteTo)
|
||||
return err
|
||||
}
|
||||
|
||||
func (self *User) RemoveWriteMatcher(u *User, m *protocol.Matcher) error {
|
||||
var err error
|
||||
u.u.WriteTo, err = self.removeMatcher(u, m, u.u.WriteTo)
|
||||
return err
|
||||
}
|
||||
|
||||
func (self *User) HasWriteAccess(name string) bool {
|
||||
for _, matcher := range self.u.WriteTo {
|
||||
if matcher.Matches(name) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (self *User) HasReadAccess(name string) bool {
|
||||
for _, matcher := range self.u.ReadFrom {
|
||||
if matcher.Matches(name) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// private funcs
|
||||
|
||||
func (self *User) addMatcher(u *User, m *protocol.Matcher, matchers []*protocol.Matcher) ([]*protocol.Matcher, error) {
|
||||
if err := self.getMatcherPermission(m); err != nil {
|
||||
return matchers, err
|
||||
}
|
||||
|
||||
idx := u.findMatcher(m, matchers)
|
||||
if idx == -1 {
|
||||
matchers = append(matchers, m)
|
||||
}
|
||||
return matchers, nil
|
||||
}
|
||||
|
||||
func (self *User) removeMatcher(u *User, m *protocol.Matcher, matchers []*protocol.Matcher) ([]*protocol.Matcher, error) {
|
||||
if err := self.getMatcherPermission(m); err != nil {
|
||||
return matchers, err
|
||||
}
|
||||
|
||||
idx := u.findMatcher(m, matchers)
|
||||
if idx != -1 {
|
||||
matchers = append(matchers[:idx], matchers[idx+1:]...)
|
||||
}
|
||||
return matchers, nil
|
||||
}
|
||||
|
||||
func (self *User) getMatcherPermission(m *protocol.Matcher) error {
|
||||
if !self.IsClusterAdmin() && m.GetIsRegex() {
|
||||
return fmt.Errorf("Only a cluster admin can add access to a regex")
|
||||
}
|
||||
|
||||
if !self.IsClusterAdmin() && !self.IsDbAdmin(m.GetName()) {
|
||||
return fmt.Errorf("Cannot add permission to a db your not an admin of")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *User) isValidPwd(password string) bool {
|
||||
return bcrypt.CompareHashAndPassword([]byte(self.u.GetHash()), []byte(password)) == nil
|
||||
}
|
||||
|
||||
func (self *User) findMatcher(matcher *protocol.Matcher, matchers []*protocol.Matcher) int {
|
||||
for idx, m := range matchers {
|
||||
if m.GetIsRegex() == matcher.GetIsRegex() && m.GetName() == matcher.GetName() {
|
||||
return idx
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
func hashPassword(password string) ([]byte, error) {
|
||||
// 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
|
||||
|
|
|
@ -54,6 +54,14 @@ func (self *UserSuite) TestClusterAdminUser(c *C) {
|
|||
c.Assert(u.IsDbAdmin("db2"), Equals, false)
|
||||
c.Assert(root.RemoveDbAdmin(u, "db1"), IsNil)
|
||||
c.Assert(u.IsDbAdmin("db1"), Equals, false)
|
||||
|
||||
// can add read and write keys that are regex
|
||||
c.Assert(root.AddReadMatcher(u, protocol.NewMatcher(false, "db1")), IsNil)
|
||||
c.Assert(root.AddReadMatcher(u, protocol.NewMatcher(true, "db2.*")), IsNil)
|
||||
c.Assert(u.HasReadAccess("db1"), Equals, true)
|
||||
c.Assert(u.HasReadAccess("db2.foobar"), Equals, true)
|
||||
c.Assert(root.RemoveReadMatcher(u, protocol.NewMatcher(false, "db1")), IsNil)
|
||||
c.Assert(u.HasReadAccess("db1"), Equals, false)
|
||||
}
|
||||
|
||||
func (self *UserSuite) TestDbAdminUser(c *C) {
|
||||
|
@ -89,6 +97,14 @@ func (self *UserSuite) TestDbAdminUser(c *C) {
|
|||
c.Assert(dbAdmin.RemoveDbAdmin(u, "db1"), IsNil)
|
||||
c.Assert(u.IsDbAdmin("db1"), Equals, false)
|
||||
c.Assert(u.IsDbAdmin("db2"), Equals, false)
|
||||
|
||||
// can add read access to the db that he's administering only
|
||||
c.Assert(dbAdmin.AddReadMatcher(u, protocol.NewMatcher(false, "db1")), IsNil)
|
||||
c.Assert(dbAdmin.AddReadMatcher(u, protocol.NewMatcher(false, "db2")), NotNil)
|
||||
c.Assert(dbAdmin.AddReadMatcher(u, protocol.NewMatcher(true, "db2.*")), NotNil)
|
||||
c.Assert(u.HasReadAccess("db1"), Equals, true)
|
||||
c.Assert(u.HasReadAccess("db2"), Equals, false)
|
||||
c.Assert(u.HasReadAccess("db2.foobar"), Equals, false)
|
||||
}
|
||||
|
||||
func (self *UserSuite) BenchmarkHashing(c *C) {
|
||||
|
|
|
@ -317,11 +317,37 @@ func (m *Response) GetServers() []string {
|
|||
return nil
|
||||
}
|
||||
|
||||
type Matcher struct {
|
||||
IsRegex *bool `protobuf:"varint,1,req,name=is_regex" json:"is_regex,omitempty"`
|
||||
Name *string `protobuf:"bytes,2,req,name=name" json:"name,omitempty"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
}
|
||||
|
||||
func (m *Matcher) Reset() { *m = Matcher{} }
|
||||
func (m *Matcher) String() string { return proto.CompactTextString(m) }
|
||||
func (*Matcher) ProtoMessage() {}
|
||||
|
||||
func (m *Matcher) GetIsRegex() bool {
|
||||
if m != nil && m.IsRegex != nil {
|
||||
return *m.IsRegex
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (m *Matcher) GetName() string {
|
||||
if m != nil && m.Name != nil {
|
||||
return *m.Name
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type User struct {
|
||||
Name *string `protobuf:"bytes,1,req,name=name" json:"name,omitempty"`
|
||||
Hash *string `protobuf:"bytes,2,req,name=hash" json:"hash,omitempty"`
|
||||
ClusterAdmin *bool `protobuf:"varint,3,req,name=clusterAdmin" json:"clusterAdmin,omitempty"`
|
||||
AdminFor []string `protobuf:"bytes,4,rep,name=admin_for" json:"admin_for,omitempty"`
|
||||
ReadFrom []*Matcher `protobuf:"bytes,5,rep,name=read_from" json:"read_from,omitempty"`
|
||||
WriteTo []*Matcher `protobuf:"bytes,6,rep,name=write_to" json:"write_to,omitempty"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
}
|
||||
|
||||
|
@ -357,6 +383,20 @@ func (m *User) GetAdminFor() []string {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (m *User) GetReadFrom() []*Matcher {
|
||||
if m != nil {
|
||||
return m.ReadFrom
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *User) GetWriteTo() []*Matcher {
|
||||
if m != nil {
|
||||
return m.WriteTo
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
proto.RegisterEnum("protocol.FieldDefinition_Type", FieldDefinition_Type_name, FieldDefinition_Type_value)
|
||||
proto.RegisterEnum("protocol.Request_Type", Request_Type_name, Request_Type_value)
|
||||
|
|
|
@ -51,11 +51,20 @@ message Response {
|
|||
repeated string servers = 3;
|
||||
}
|
||||
|
||||
message Matcher {
|
||||
required bool is_regex = 1;
|
||||
required string name = 2;
|
||||
}
|
||||
|
||||
message User {
|
||||
required string name = 1;
|
||||
required string hash = 2;
|
||||
required bool clusterAdmin = 3;
|
||||
// the list of dbs that the user is admin for
|
||||
repeated string admin_for = 4;
|
||||
// the list of dbs that the user can read from
|
||||
repeated Matcher read_from = 5;
|
||||
// the list of dbs that the user can write to
|
||||
repeated Matcher write_to = 6;
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@ package protocol
|
|||
|
||||
import (
|
||||
"code.google.com/p/goprotobuf/proto"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
func UnmarshalPoint(data []byte) (point *Point, err error) {
|
||||
|
@ -21,3 +22,19 @@ func (self *Point) GetTimestampInMicroseconds() *int64 {
|
|||
func (self *Point) SetTimestampInMicroseconds(t int64) {
|
||||
self.Timestamp = &t
|
||||
}
|
||||
|
||||
func NewMatcher(isRegex bool, name string) *Matcher {
|
||||
return &Matcher{
|
||||
Name: &name,
|
||||
IsRegex: &isRegex,
|
||||
}
|
||||
}
|
||||
|
||||
func (self *Matcher) Matches(name string) bool {
|
||||
if self.GetIsRegex() {
|
||||
matches, _ := regexp.MatchString(self.GetName(), name)
|
||||
return matches
|
||||
}
|
||||
|
||||
return self.GetName() == name
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue