From 846a259c1d24d9082d8296d5fb253c0af8d2dba9 Mon Sep 17 00:00:00 2001 From: Gabriel Taylor-Russ Date: Tue, 12 May 2015 09:14:35 -0700 Subject: [PATCH 1/3] Add tests for setting and revoking privileges on databases Add tests for elevating user to admin and demoting users from admin --- server_test.go | 250 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 250 insertions(+) diff --git a/server_test.go b/server_test.go index 93c53a9e84..408e16fb8a 100644 --- a/server_test.go +++ b/server_test.go @@ -2347,6 +2347,256 @@ func TestServer_CreateDatabaseIfNotExists(t *testing.T) { } } +// Ensure session is always authenticated when authentication is disabled +func TestServer_Authenticate_AuthenticationDisabled(t *testing.T) { + c := test.NewDefaultMessagingClient() + defer c.Close() + s := OpenServer(c) + defer s.Close() + + // Create a user. + if err := s.CreateUser("susy", "pass", true); err != nil { + t.Fatal(err) + } + s.Restart() + s.SetAuthenticationEnabled(false) + + u, err := s.Authenticate("sammy", "pass") + if u != nil || err != nil { + t.Fatalf("Authenticate should return nil when authentication is disabled and user does not exist") + } +} + +// Ensure an error is raised for a non-existent user +func TestServer_Authenticate_InvalidUsername(t *testing.T) { + c := test.NewDefaultMessagingClient() + defer c.Close() + s := OpenServer(c) + defer s.Close() + + // Create a user. + if err := s.CreateUser("susy", "pass", true); err != nil { + t.Fatal(err) + } + s.Restart() + s.SetAuthenticationEnabled(true) + + _, err := s.Authenticate("sammy", "pass") + if err == nil { + t.Fatalf("Authenticate should return an error when the user does not exist") + } +} + +// Server should be able to update user's password +func TestServer_UpdateUser_ChangePassword(t *testing.T) { + c := test.NewDefaultMessagingClient() + defer c.Close() + s := OpenServer(c) + defer s.Close() + + // Create a user. + if err := s.CreateUser("susy", "pass", true); err != nil { + t.Fatal(err) + } + s.Restart() + s.SetAuthenticationEnabled(true) + + // Can authenticate with existing password + if _, err := s.Authenticate("susy", "pass"); err != nil { + t.Errorf("unexpected error: %s", err) + } + + // Can update password + if err := s.UpdateUser("susy", "updatedPass"); err != nil { + t.Errorf("unexpected error: %s", err) + } + + // Can authenticate with new password + if _, err := s.Authenticate("susy", "updatedPass"); err != nil { + t.Errorf("unexpected error: %s", err) + } + + // Can't authenticate with old password + if _, err := s.Authenticate("susy", "pass"); err == nil { + t.Errorf("The server should not allow users to authenticate with password that has been replaced.") + } +} + +// Ensure error is returned when attempting to update a non-existent user +func TestServer_UpdateUser_NonexistentUser(t *testing.T) { + c := test.NewDefaultMessagingClient() + defer c.Close() + s := OpenServer(c) + defer s.Close() + + // Can't update non-existent user + if err := s.UpdateUser("susy", "updatedPass"); err != influxdb.ErrUserNotFound { + t.Fatal(err) + } +} + +// Ensure error is returned when attempting to delete a non-existent user +func TestServer_DeleteUser_NonexistentUser(t *testing.T) { + c := test.NewDefaultMessagingClient() + defer c.Close() + s := OpenServer(c) + defer s.Close() + + // Can't update non-existent user + if err := s.DeleteUser("susy"); err != influxdb.ErrUserNotFound { + t.Fatal(err) + } +} + +// Ensure error is returned when attempting to delete a blank username +func TestServer_DeleteUser_BlankUser(t *testing.T) { + c := test.NewDefaultMessagingClient() + defer c.Close() + s := OpenServer(c) + defer s.Close() + + // Can't update non-existent user + if err := s.DeleteUser(""); err != influxdb.ErrUsernameRequired { + t.Fatal(err) + } +} + +// Ensure error is returned when attempting to set privileges for a blank username +func TestServer_SetPrivilege_BlankUser(t *testing.T) { + c := test.NewDefaultMessagingClient() + defer c.Close() + s := OpenServer(c) + defer s.Close() + + // Can't set privilege on blank username + if err := s.SetPrivilege(influxql.WritePrivilege, "", ""); err != influxdb.ErrUsernameRequired { + t.Fatal(err) + } +} + +// Ensure error is returned when attempting to set privileges for a non-existent user +func TestServer_SetPrivilege_NonexistentUser(t *testing.T) { + c := test.NewDefaultMessagingClient() + defer c.Close() + s := OpenServer(c) + defer s.Close() + + // Can't set privilege on non existent user + if err := s.SetPrivilege(influxql.WritePrivilege, "susy", ""); err != influxdb.ErrUserNotFound { + t.Fatal(err) + } +} + +// Ensure user admin flag updated when database name is blank +func TestServer_SetPrivilege_BlankDatabaseName_Grant(t *testing.T) { + c := test.NewDefaultMessagingClient() + defer c.Close() + s := OpenServer(c) + defer s.Close() + + // Create a user. + if err := s.CreateUser("susy", "pass", false); err != nil { + t.Fatal(err) + } + s.Restart() + + if u := s.User("susy"); u.Admin != false { + t.Errorf("The user should not be an admin by default.") + } + + // Set privileges with blank database name to update user admin flag + err := s.SetPrivilege(influxql.AllPrivileges, "susy", "") + if err != nil { + t.Errorf("unexpected error: %s", err) + } + + if u := s.User("susy"); u.Admin != true { + t.Errorf("The user should be an admin as their privileges have been updated.") + } +} + +// Ensure user admin flag updated when database name is blank +func TestServer_SetPrivilege_BlankDatabaseName_Revoke(t *testing.T) { + c := test.NewDefaultMessagingClient() + defer c.Close() + s := OpenServer(c) + defer s.Close() + + // Create a user. + if err := s.CreateUser("susy", "pass", true); err != nil { + t.Fatal(err) + } + s.Restart() + + if u := s.User("susy"); u.Admin != true { + t.Errorf("The user should be an admin.") + } + + // Set no privileges with blank database name to update user admin flag + err := s.SetPrivilege(influxql.NoPrivileges, "susy", "") + if err != nil { + t.Errorf("unexpected error: %s", err) + } + + if u := s.User("susy"); u.Admin != false { + t.Errorf("The user should not be an admin as their privileges have been revoked.") + } +} + +// Ensure user admin flag updated when database name is blank +func TestServer_SetPrivilege_ExistingDatabase(t *testing.T) { + c := test.NewDefaultMessagingClient() + defer c.Close() + s := OpenServer(c) + defer s.Close() + + // Create the "foo" database. + if err := s.CreateDatabase("foo"); err != nil { + t.Fatal(err) + } + + // Create a user. + if err := s.CreateUser("susy", "pass", false); err != nil { + t.Fatal(err) + } + s.Restart() + + u := s.User("susy") + if u.Privileges["foo"] != influxql.NoPrivileges { + t.Errorf("The user should have no privileges by default.") + } + + // Set privileges with blank database name to update user admin flag + err := s.SetPrivilege(influxql.WritePrivilege, "susy", "foo") + if err != nil { + t.Errorf("unexpected error: %s", err) + } + + if u := s.User("susy"); u.Privileges["foo"] != influxql.WritePrivilege { + t.Errorf("The user should have 'WRITE' privileges.") + } +} + +// Ensure server returns error when attempting to grant granular privileges on blank database name +func TestServer_SetPrivilege_WritePrivilegeBlankDatabase(t *testing.T) { + c := test.NewDefaultMessagingClient() + defer c.Close() + s := OpenServer(c) + defer s.Close() + + // Create a user. + if err := s.CreateUser("susy", "pass", false); err != nil { + t.Fatal(err) + } + s.Restart() + + // Can't set write privileges with blank database name + err := s.SetPrivilege(influxql.WritePrivilege, "susy", "") + if err != influxdb.ErrInvalidGrantRevoke { + t.Fatal(err) + } +} + func TestServer_SeriesByTagNames(t *testing.T) { t.Skip("pending") } func TestServer_SeriesByTagValues(t *testing.T) { t.Skip("pending") } func TestServer_TagNamesBySeries(t *testing.T) { t.Skip("pending") } From 0763caaa0c5efe815063b63b720d95b4fc7d0699 Mon Sep 17 00:00:00 2001 From: Gabriel Taylor-Russ Date: Tue, 12 May 2015 16:35:21 -0700 Subject: [PATCH 2/3] Add tests for setting AllPrivileges, WritePrivilege, ReadPrivilege. --- server.go | 2 +- server_test.go | 103 +++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 101 insertions(+), 4 deletions(-) diff --git a/server.go b/server.go index e7f8320456..1c0793c8d0 100644 --- a/server.go +++ b/server.go @@ -1484,7 +1484,7 @@ func (s *Server) DefaultRetentionPolicy(database string) (*RetentionPolicy, erro return db.policies[db.defaultRetentionPolicy], nil } -// RetentionPolicies returns a list of retention polocies for a database. +// RetentionPolicies returns a list of retention policies for a database. // Returns an error if the database doesn't exist. func (s *Server) RetentionPolicies(database string) ([]*RetentionPolicy, error) { s.mu.RLock() diff --git a/server_test.go b/server_test.go index 408e16fb8a..34ecf44ab6 100644 --- a/server_test.go +++ b/server_test.go @@ -604,6 +604,47 @@ func TestServer_CreateRetentionPolicy(t *testing.T) { } } +// Ensure the database only creates retention policy if it doesn't already exist. +func TestServer_CreateRetentionPolicyIfNotExists(t *testing.T) { + c := test.NewDefaultMessagingClient() + defer c.Close() + s := OpenServer(c) + defer s.Close() + + // Create a database. + if err := s.CreateDatabase("foo"); err != nil { + t.Fatal(err) + } + + // Create a retention policy on the database. + rp := &influxdb.RetentionPolicy{ + Name: "bar", + Duration: time.Hour, + ShardGroupDuration: time.Hour, + ReplicaN: 2, + } + + // Verify nil returned if policy doesn't exist and succesfully created + if err := s.CreateRetentionPolicyIfNotExists("foo", rp); err != nil { + t.Fatal(err) + } + s.Restart() + + // Verify that the policy exists. + if o, err := s.RetentionPolicy("foo", "bar"); err != nil { + t.Fatalf("unexpected error: %s", err) + } else if o == nil { + t.Fatalf("retention policy not found") + } else if !reflect.DeepEqual(rp, o) { + t.Fatalf("retention policy mismatch: %#v", o) + } + + // Verify nil returned if policy already exists + if err := s.CreateRetentionPolicyIfNotExists("foo", rp); err != nil { + t.Fatal(err) + } +} + // Ensure the database can create a new retention policy with infinite duration. func TestServer_CreateRetentionPolicyInfinite(t *testing.T) { c := test.NewDefaultMessagingClient() @@ -997,6 +1038,30 @@ func TestServer_StartRetentionPolicyEnforcement_ErrZeroInterval(t *testing.T) { } } +// Ensure the server returns an error when attempting to look up +// the retention policy on a non existent database +func TestServer_RetentionPolicy_NonexistentDatabase(t *testing.T) { + c := test.NewDefaultMessagingClient() + defer c.Close() + s := OpenServer(c) + defer s.Close() + + nonExistentDBName := "nonexistent_database" + + expectedErr := influxdb.ErrDatabaseNotFound(nonExistentDBName) + + extractMessage := func(e error) string { + r, _ := regexp.Compile("(.+)\\(.+\\)") + match := r.FindStringSubmatch(e.Error())[1] + return match + } + + _, err := s.RetentionPolicy(nonExistentDBName, "rp") + if extractMessage(err) != extractMessage(expectedErr) { + t.Fatal(err) + } +} + // Ensure the server can support writes of all data types. func TestServer_WriteAllDataTypes(t *testing.T) { c := test.NewDefaultMessagingClient() @@ -2543,8 +2608,8 @@ func TestServer_SetPrivilege_BlankDatabaseName_Revoke(t *testing.T) { } } -// Ensure user admin flag updated when database name is blank -func TestServer_SetPrivilege_ExistingDatabase(t *testing.T) { +// Ensure read privilege can be set for user +func TestServer_SetPrivilege_Read(t *testing.T) { c := test.NewDefaultMessagingClient() defer c.Close() s := OpenServer(c) @@ -2566,7 +2631,6 @@ func TestServer_SetPrivilege_ExistingDatabase(t *testing.T) { t.Errorf("The user should have no privileges by default.") } - // Set privileges with blank database name to update user admin flag err := s.SetPrivilege(influxql.WritePrivilege, "susy", "foo") if err != nil { t.Errorf("unexpected error: %s", err) @@ -2577,6 +2641,39 @@ func TestServer_SetPrivilege_ExistingDatabase(t *testing.T) { } } +// Ensure all privileges can be set for user +func TestServer_SetPrivilege_All(t *testing.T) { + c := test.NewDefaultMessagingClient() + defer c.Close() + s := OpenServer(c) + defer s.Close() + + // Create the "foo" database. + if err := s.CreateDatabase("foo"); err != nil { + t.Fatal(err) + } + + // Create a user. + if err := s.CreateUser("susy", "pass", false); err != nil { + t.Fatal(err) + } + s.Restart() + + u := s.User("susy") + if u.Privileges["foo"] != influxql.NoPrivileges { + t.Errorf("The user should have no privileges by default.") + } + + err := s.SetPrivilege(influxql.AllPrivileges, "susy", "foo") + if err != nil { + t.Errorf("unexpected error: %s", err) + } + + if u := s.User("susy"); u.Privileges["foo"] != influxql.AllPrivileges { + t.Errorf("The user should have 'ALL' privileges.") + } +} + // Ensure server returns error when attempting to grant granular privileges on blank database name func TestServer_SetPrivilege_WritePrivilegeBlankDatabase(t *testing.T) { c := test.NewDefaultMessagingClient() From d11b943f62adbf3a9fb0a5732e77777f6d43b320 Mon Sep 17 00:00:00 2001 From: Gabriel Taylor-Russ Date: Fri, 22 May 2015 18:33:17 -0700 Subject: [PATCH 3/3] Corrected comments on server tests to better reflect test actions --- server_test.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/server_test.go b/server_test.go index 3726ff0544..607dc0f10f 100644 --- a/server_test.go +++ b/server_test.go @@ -2507,7 +2507,7 @@ func TestServer_DeleteUser_NonexistentUser(t *testing.T) { s := OpenServer(c) defer s.Close() - // Can't update non-existent user + // Can't delete non-existent user if err := s.DeleteUser("susy"); err != influxdb.ErrUserNotFound { t.Fatal(err) } @@ -2520,7 +2520,7 @@ func TestServer_DeleteUser_BlankUser(t *testing.T) { s := OpenServer(c) defer s.Close() - // Can't update non-existent user + // Can't delete blank user if err := s.DeleteUser(""); err != influxdb.ErrUsernameRequired { t.Fatal(err) } @@ -2546,7 +2546,7 @@ func TestServer_SetPrivilege_NonexistentUser(t *testing.T) { s := OpenServer(c) defer s.Close() - // Can't set privilege on non existent user + // Can't set privilege on non-existent user if err := s.SetPrivilege(influxql.WritePrivilege, "susy", ""); err != influxdb.ErrUserNotFound { t.Fatal(err) } @@ -2580,14 +2580,14 @@ func TestServer_SetPrivilege_BlankDatabaseName_Grant(t *testing.T) { } } -// Ensure user admin flag updated when database name is blank +// Ensure user admin flag can be revoked when user created as admin func TestServer_SetPrivilege_BlankDatabaseName_Revoke(t *testing.T) { c := test.NewDefaultMessagingClient() defer c.Close() s := OpenServer(c) defer s.Close() - // Create a user. + // Create an admin user. if err := s.CreateUser("susy", "pass", true); err != nil { t.Fatal(err) }