Add change password.

pull/903/head
Ben Johnson 2014-10-25 13:30:41 -06:00
parent e47a19ada6
commit f683eabb7a
2 changed files with 105 additions and 21 deletions

View File

@ -283,6 +283,33 @@ type deleteDBUserCommand struct {
Username string `json:"username"` Username string `json:"username"`
} }
func (s *Server) applyChangePassword(m *messaging.Message) error {
var c changePasswordCommand
mustUnmarshal(m.Data, &c)
s.mu.Lock()
defer s.mu.Unlock()
// Validate user.
if c.Username == "" {
return ErrUsernameRequired
}
// Retrieve the database.
db := s.databases[c.Database]
if s.databases[c.Database] == nil {
return ErrDatabaseNotFound
}
return db.changePassword(c.Username, c.Password)
}
type changePasswordCommand struct {
Database string `json:"database"`
Username string `json:"username"`
Password string `json:"password"`
}
// WriteSeries writes series data to the broker. // WriteSeries writes series data to the broker.
func (s *Server) WriteSeries(u *ClusterAdmin, database string, series *protocol.Series) error { func (s *Server) WriteSeries(u *ClusterAdmin, database string, series *protocol.Series) error {
// TODO: // TODO:
@ -312,6 +339,8 @@ func (s *Server) processor(done chan struct{}) {
err = s.applyCreateDBUser(m) err = s.applyCreateDBUser(m)
case deleteDBUserMessageType: case deleteDBUserMessageType:
err = s.applyDeleteDBUser(m) err = s.applyDeleteDBUser(m)
case changePasswordMessageType:
err = s.applyChangePassword(m)
} }
// Sync high water mark and errors for broadcast topic. // Sync high water mark and errors for broadcast topic.
@ -381,6 +410,13 @@ func (db *Database) CreateUser(username, password string, permissions []string)
return err return err
} }
func (db *Database) saveUser(u *DBUser) error {
db.mu.Lock()
db.users[u.Name] = u
db.mu.Unlock()
return nil
}
// DeleteUser removes a user from the database. // DeleteUser removes a user from the database.
func (db *Database) DeleteUser(username string) error { func (db *Database) DeleteUser(username string) error {
c := &deleteDBUserCommand{ c := &deleteDBUserCommand{
@ -391,15 +427,6 @@ func (db *Database) DeleteUser(username string) error {
return err return err
} }
// saveUser persists a user to the database.
func (db *Database) saveUser(u *DBUser) error {
db.mu.Lock()
db.users[u.Name] = u
db.mu.Unlock()
return nil
}
// deleteUser removes a user from the database.
func (db *Database) deleteUser(username string) error { func (db *Database) deleteUser(username string) error {
db.mu.Lock() db.mu.Lock()
defer db.mu.Unlock() defer db.mu.Unlock()
@ -414,6 +441,39 @@ func (db *Database) deleteUser(username string) error {
return nil return nil
} }
// ChangePassword changes the password for a user in the database.
func (db *Database) ChangePassword(username, newPassword string) error {
c := &changePasswordCommand{
Database: db.Name(),
Username: username,
Password: newPassword,
}
_, err := db.server.broadcast(changePasswordMessageType, c)
return err
}
func (db *Database) changePassword(username, newPassword string) error {
db.mu.Lock()
defer db.mu.Unlock()
// Check that user exists.
u := db.users[username]
if u == nil {
return ErrUserNotFound
}
// Generate the hash of the password.
hash, err := HashPassword(newPassword)
if err != nil {
return err
}
// Update user password hash.
u.Hash = string(hash)
return nil
}
// ShardSpace represents a policy for creating new shards in a database. // ShardSpace represents a policy for creating new shards in a database.
type ShardSpace struct { type ShardSpace struct {
// Unique name within database. Required. // Unique name within database. Required.

View File

@ -4,9 +4,9 @@ import (
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"os" "os"
"reflect"
"testing" "testing"
"code.google.com/p/go.crypto/bcrypt"
"github.com/influxdb/influxdb" "github.com/influxdb/influxdb"
"github.com/influxdb/influxdb/messaging" "github.com/influxdb/influxdb/messaging"
) )
@ -94,7 +94,7 @@ func TestServer_DropDatabase_ErrDatabaseNotFound(t *testing.T) {
} }
// Ensure the server can create a new user. // Ensure the server can create a new user.
func TestServer_CreateUser(t *testing.T) { func TestDatabase_CreateUser(t *testing.T) {
s := OpenServer(NewMessagingClient()) s := OpenServer(NewMessagingClient())
defer s.Close() defer s.Close()
@ -112,13 +112,15 @@ func TestServer_CreateUser(t *testing.T) {
// Verify that the user exists. // Verify that the user exists.
if u := db.User("susy"); u == nil { if u := db.User("susy"); u == nil {
t.Fatalf("user not found") t.Fatalf("user not found")
} else if reflect.DeepEqual(u, nil) { } else if u.Name != "susy" {
t.Fatalf("user mismatch: %#v", u) t.Fatalf("username mismatch: %v", u.Name)
} else if bcrypt.CompareHashAndPassword([]byte(u.Hash), []byte("pass")) != nil {
t.Fatal("invalid password")
} }
} }
// Ensure the server returns an error when creating a user without a name. // Ensure the server returns an error when creating a user without a name.
func TestServer_CreateUser_ErrUsernameRequired(t *testing.T) { func TestDatabase_CreateUser_ErrUsernameRequired(t *testing.T) {
s := OpenServer(NewMessagingClient()) s := OpenServer(NewMessagingClient())
defer s.Close() defer s.Close()
if err := s.CreateDatabase("foo"); err != nil { if err := s.CreateDatabase("foo"); err != nil {
@ -130,7 +132,7 @@ func TestServer_CreateUser_ErrUsernameRequired(t *testing.T) {
} }
// Ensure the server returns an error when creating a user with an invalid name. // Ensure the server returns an error when creating a user with an invalid name.
func TestServer_CreateUser_ErrInvalidUsername(t *testing.T) { func TestDatabase_CreateUser_ErrInvalidUsername(t *testing.T) {
s := OpenServer(NewMessagingClient()) s := OpenServer(NewMessagingClient())
defer s.Close() defer s.Close()
if err := s.CreateDatabase("foo"); err != nil { if err := s.CreateDatabase("foo"); err != nil {
@ -142,7 +144,7 @@ func TestServer_CreateUser_ErrInvalidUsername(t *testing.T) {
} }
// Ensure the server returns an error when creating a user after the db is dropped. // Ensure the server returns an error when creating a user after the db is dropped.
func TestServer_CreateUser_ErrDatabaseNotFound(t *testing.T) { func TestDatabase_CreateUser_ErrDatabaseNotFound(t *testing.T) {
s := OpenServer(NewMessagingClient()) s := OpenServer(NewMessagingClient())
defer s.Close() defer s.Close()
@ -164,7 +166,7 @@ func TestServer_CreateUser_ErrDatabaseNotFound(t *testing.T) {
} }
// Ensure the server returns an error when creating a duplicate user. // Ensure the server returns an error when creating a duplicate user.
func TestServer_CreateUser_ErrUserExists(t *testing.T) { func TestDatabase_CreateUser_ErrUserExists(t *testing.T) {
s := OpenServer(NewMessagingClient()) s := OpenServer(NewMessagingClient())
defer s.Close() defer s.Close()
@ -184,7 +186,7 @@ func TestServer_CreateUser_ErrUserExists(t *testing.T) {
} }
// Ensure the server can delete an existing user. // Ensure the server can delete an existing user.
func TestServer_DeleteUser(t *testing.T) { func TestDatabase_DeleteUser(t *testing.T) {
s := OpenServer(NewMessagingClient()) s := OpenServer(NewMessagingClient())
defer s.Close() defer s.Close()
@ -206,7 +208,7 @@ func TestServer_DeleteUser(t *testing.T) {
} }
// Ensure the server returns an error when delete a user without a name. // Ensure the server returns an error when delete a user without a name.
func TestServer_DeleteUser_ErrUsernameRequired(t *testing.T) { func TestDatabase_DeleteUser_ErrUsernameRequired(t *testing.T) {
s := OpenServer(NewMessagingClient()) s := OpenServer(NewMessagingClient())
defer s.Close() defer s.Close()
s.CreateDatabase("foo") s.CreateDatabase("foo")
@ -216,7 +218,7 @@ func TestServer_DeleteUser_ErrUsernameRequired(t *testing.T) {
} }
// Ensure the server returns an error when deleting a user after the db is dropped. // Ensure the server returns an error when deleting a user after the db is dropped.
func TestServer_DeleteUser_ErrDatabaseNotFound(t *testing.T) { func TestDatabase_DeleteUser_ErrDatabaseNotFound(t *testing.T) {
s := OpenServer(NewMessagingClient()) s := OpenServer(NewMessagingClient())
defer s.Close() defer s.Close()
@ -232,7 +234,7 @@ func TestServer_DeleteUser_ErrDatabaseNotFound(t *testing.T) {
} }
// Ensure the server returns an error when deleting a non-existent user. // Ensure the server returns an error when deleting a non-existent user.
func TestServer_DeleteUser_ErrUserNotFound(t *testing.T) { func TestDatabase_DeleteUser_ErrUserNotFound(t *testing.T) {
s := OpenServer(NewMessagingClient()) s := OpenServer(NewMessagingClient())
defer s.Close() defer s.Close()
s.CreateDatabase("foo") s.CreateDatabase("foo")
@ -241,6 +243,28 @@ func TestServer_DeleteUser_ErrUserNotFound(t *testing.T) {
} }
} }
// Ensure the server can change the password of a user.
func TestDatabase_ChangePassword(t *testing.T) {
s := OpenServer(NewMessagingClient())
defer s.Close()
// Create a database and user.
s.CreateDatabase("foo")
db := s.Database("foo")
if err := db.CreateUser("susy", "pass", nil); err != nil {
t.Fatal(err)
} else if bcrypt.CompareHashAndPassword([]byte(db.User("susy").Hash), []byte("pass")) != nil {
t.Fatal("invalid initial password")
}
// Update user password.
if err := db.ChangePassword("susy", "newpass"); err != nil {
t.Fatal(err)
} else if bcrypt.CompareHashAndPassword([]byte(db.User("susy").Hash), []byte("newpass")) != nil {
t.Fatal("invalid new password")
}
}
// Server is a wrapping test struct for influxdb.Server. // Server is a wrapping test struct for influxdb.Server.
type Server struct { type Server struct {
*influxdb.Server *influxdb.Server