diff --git a/src/coordinator/cluster_configuration.go b/src/coordinator/cluster_configuration.go index 55144290d7..c1f1179475 100644 --- a/src/coordinator/cluster_configuration.go +++ b/src/coordinator/cluster_configuration.go @@ -79,6 +79,28 @@ func (self *ClusterConfiguration) DropDatabase(name string) error { return nil } +func (self *ClusterConfiguration) GetDbUsers(db string) (names []string) { + self.usersLock.RLock() + defer self.usersLock.RUnlock() + + dbUsers := self.dbUsers[db] + for name, _ := range dbUsers { + names = append(names, name) + } + return +} + +func (self *ClusterConfiguration) GetDbUser(db, username string) *dbUser { + self.usersLock.RLock() + defer self.usersLock.RUnlock() + + dbUsers := self.dbUsers[db] + if dbUsers == nil { + return nil + } + return dbUsers[username] +} + func (self *ClusterConfiguration) SaveDbUser(u *dbUser) { self.usersLock.Lock() defer self.usersLock.Unlock() @@ -98,6 +120,24 @@ func (self *ClusterConfiguration) SaveDbUser(u *dbUser) { dbUsers[u.GetName()] = u } +func (self *ClusterConfiguration) GetClusterAdmins() (names []string) { + self.usersLock.RLock() + defer self.usersLock.RUnlock() + + clusterAdmins := self.clusterAdmins + for name, _ := range clusterAdmins { + names = append(names, name) + } + return +} + +func (self *ClusterConfiguration) GetClusterAdmin(username string) *clusterAdmin { + self.usersLock.RLock() + defer self.usersLock.RUnlock() + + return self.clusterAdmins[username] +} + func (self *ClusterConfiguration) SaveClusterAdmin(u *clusterAdmin) { self.usersLock.Lock() defer self.usersLock.Unlock() diff --git a/src/coordinator/coordinator.go b/src/coordinator/coordinator.go index e8f2825360..5500f45596 100644 --- a/src/coordinator/coordinator.go +++ b/src/coordinator/coordinator.go @@ -85,6 +85,14 @@ func (self *CoordinatorImpl) AuthenticateClusterAdmin(username, password string) return nil, fmt.Errorf("Invalid username/password") } +func (self *CoordinatorImpl) ListClusterAdmins(requester User) ([]string, error) { + if !requester.IsClusterAdmin() { + return nil, fmt.Errorf("Insufficient permissions") + } + + return self.clusterConfiguration.GetClusterAdmins(), nil +} + func (self *CoordinatorImpl) CreateClusterAdminUser(requester User, username string) error { if !requester.IsClusterAdmin() { return fmt.Errorf("Insufficient permissions") @@ -158,6 +166,14 @@ func (self *CoordinatorImpl) DeleteDbUser(requester User, db, username string) e return self.raftServer.SaveDbUser(user) } +func (self *CoordinatorImpl) ListDbUsers(requester User, db string) ([]string, error) { + if !requester.IsClusterAdmin() && !requester.IsDbAdmin(db) { + return nil, fmt.Errorf("Insufficient permissions") + } + + return self.clusterConfiguration.GetDbUsers(db), nil +} + func (self *CoordinatorImpl) ChangeDbUserPassword(requester User, db, username, password string) error { if !requester.IsClusterAdmin() && !requester.IsDbAdmin(db) && !(requester.GetDb() == db && requester.GetName() == username) { return fmt.Errorf("Insufficient permissions") diff --git a/src/coordinator/coordinator_test.go b/src/coordinator/coordinator_test.go index 6e9fc2c4b0..b4f8890f91 100644 --- a/src/coordinator/coordinator_test.go +++ b/src/coordinator/coordinator_test.go @@ -422,6 +422,11 @@ func (self *CoordinatorSuite) TestAdminOperations(c *C) { c.Assert(err, IsNil) c.Assert(u.IsClusterAdmin(), Equals, true) + // can get other cluster admin + admins, err := coordinator.ListClusterAdmins(root) + c.Assert(err, IsNil) + c.Assert(admins, DeepEquals, []string{"root", "another_cluster_admin"}) + // can create db users c.Assert(coordinator.CreateDbUser(root, "db1", "db_user"), IsNil) c.Assert(coordinator.ChangeDbUserPassword(root, "db1", "db_user", "db_pass"), IsNil) @@ -436,6 +441,11 @@ func (self *CoordinatorSuite) TestAdminOperations(c *C) { c.Assert(err, IsNil) c.Assert(u.IsDbAdmin("db1"), Equals, true) + // can list db users + dbUsers, err := coordinator.ListDbUsers(root, "db1") + c.Assert(err, IsNil) + c.Assert(dbUsers, DeepEquals, []string{"db_user"}) + // can delete cluster admins and db users c.Assert(coordinator.DeleteDbUser(root, "db1", "db_user"), IsNil) c.Assert(coordinator.DeleteClusterAdminUser(root, "another_cluster_admin"), IsNil) @@ -463,6 +473,10 @@ func (self *CoordinatorSuite) TestDbAdminOperations(c *C) { c.Assert(coordinator.CreateClusterAdminUser(dbUser, "another_cluster_admin"), NotNil) c.Assert(coordinator.DeleteClusterAdminUser(dbUser, "root"), NotNil) + // cannot get cluster admin + _, err = coordinator.ListClusterAdmins(dbUser) + c.Assert(err, NotNil) + // can create db users c.Assert(coordinator.CreateDbUser(dbUser, "db1", "db_user2"), IsNil) c.Assert(coordinator.ChangeDbUserPassword(dbUser, "db1", "db_user2", "db_pass"), IsNil) @@ -471,9 +485,18 @@ func (self *CoordinatorSuite) TestDbAdminOperations(c *C) { c.Assert(u.IsClusterAdmin(), Equals, false) c.Assert(u.IsDbAdmin("db1"), Equals, false) + // can get db users + admins, err := coordinator.ListDbUsers(dbUser, "db1") + c.Assert(err, IsNil) + c.Assert(admins, DeepEquals, []string{"db_user", "db_user2"}) + // cannot create db users for a different db c.Assert(coordinator.CreateDbUser(dbUser, "db2", "db_user"), NotNil) + // cannot get db users for a different db + _, err = coordinator.ListDbUsers(dbUser, "db2") + c.Assert(err, NotNil) + // can make db users db admins c.Assert(coordinator.SetDbAdmin(dbUser, "db1", "db_user2", true), IsNil) u, err = coordinator.AuthenticateDbUser("db1", "db_user2", "db_pass") diff --git a/src/coordinator/interface.go b/src/coordinator/interface.go index 84ff7a126d..cd75235dec 100644 --- a/src/coordinator/interface.go +++ b/src/coordinator/interface.go @@ -32,12 +32,16 @@ type UserManager interface { DeleteClusterAdminUser(requester User, username string) error // Change cluster admin's password. It's an error if requester isn't a cluster admin ChangeClusterAdminPassword(requester User, username, password string) error + // list cluster admins. only a cluster admin can list the other cluster admins + ListClusterAdmins(requester User) ([]string, error) // Create a db user, it's an error if requester isn't a db admin or cluster admin CreateDbUser(request User, db, username string) error // Delete a db user. Same restrictions apply as in CreateDbUser DeleteDbUser(requester User, db, username string) error // Change db user's password. It's an error if requester isn't a cluster admin or db admin ChangeDbUserPassword(requester User, db, username, password string) error + // list cluster admins. only a cluster admin or the db admin can list the db users + ListDbUsers(requester User, db string) ([]string, error) // make user a db admin for 'db'. It's an error if the requester // isn't a db admin or cluster admin or if user isn't a db user // for the given db