From 87a139c8e5d1c3a341613450128d66437091cb5b Mon Sep 17 00:00:00 2001 From: Chris Goller Date: Wed, 22 Feb 2017 00:36:28 -0600 Subject: [PATCH] Add password changing for OSS users --- influx/users.go | 34 +++++++++++++++++++ influx/users_test.go | 78 +++++++++++++++++++++++++++++++++++++------- 2 files changed, 100 insertions(+), 12 deletions(-) diff --git a/influx/users.go b/influx/users.go index b0294ad83..bca83fec3 100644 --- a/influx/users.go +++ b/influx/users.go @@ -72,6 +72,12 @@ func (c *Client) Get(ctx context.Context, name string) (*chronograf.User, error) // Update the user's permissions or roles func (c *Client) Update(ctx context.Context, u *chronograf.User) error { + // Only allow one type of change at a time. If it is a password + // change then do it and return without any changes to permissions + if u.Passwd != "" { + return c.updatePassword(ctx, u.Name, u.Passwd) + } + user, err := c.Get(ctx, u.Name) if err != nil { return err @@ -176,3 +182,31 @@ func (c *Client) userPermissions(ctx context.Context, name string) (chronograf.P } return results.Permissions(), nil } + +func (c *Client) updatePassword(ctx context.Context, name, passwd string) error { + res, err := c.Query(ctx, chronograf.Query{ + Command: fmt.Sprintf(`SET PASSWORD for "%s" = '%s'`, name, passwd), + }) + if err != nil { + return err + } + // The SET PASSWORD statements puts the error within the results itself + // So, we have to crack open the results to see what happens + octets, err := res.MarshalJSON() + if err != nil { + return err + } + + results := make([]struct{ Error string }, 0) + if err := json.Unmarshal(octets, &results); err != nil { + return err + } + + // At last, we can check if there are any error strings + for _, r := range results { + if r.Error != "" { + return fmt.Errorf(r.Error) + } + } + return nil +} diff --git a/influx/users_test.go b/influx/users_test.go index 111a42680..f486e13a9 100644 --- a/influx/users_test.go +++ b/influx/users_test.go @@ -641,19 +641,70 @@ func TestClient_Update(t *testing.T) { u *chronograf.User } tests := []struct { - name string - statusUsers int - showUsers []byte - statusGrants int - showGrants []byte - statusRevoke int - revoke []byte - statusGrant int - grant []byte - args args - want []string - wantErr bool + name string + statusUsers int + showUsers []byte + statusGrants int + showGrants []byte + statusRevoke int + revoke []byte + statusGrant int + grant []byte + statusPassword int + password []byte + args args + want []string + wantErr bool }{ + { + name: "Change Password", + statusPassword: http.StatusOK, + password: []byte(`{"results":[]}`), + args: args{ + ctx: context.Background(), + u: &chronograf.User{ + Name: "docbrown", + Passwd: "hunter2", + }, + }, + want: []string{ + `SET PASSWORD for "docbrown" = 'hunter2'`, + }, + }, + { + name: "Grant all permissions", + statusUsers: http.StatusOK, + showUsers: []byte(`{"results":[{"series":[{"columns":["user","admin"],"values":[["admin",true],["docbrown",true],["reader",false]]}]}]}`), + statusGrants: http.StatusOK, + showGrants: []byte(`{"results":[{"series":[{"columns":["database","privilege"],"values":[["mydb","ALL PRIVILEGES"]]}]}]}`), + statusRevoke: http.StatusOK, + revoke: []byte(`{"results":[]}`), + statusGrant: http.StatusOK, + grant: []byte(`{"results":[]}`), + args: args{ + ctx: context.Background(), + u: &chronograf.User{ + Name: "docbrown", + Permissions: chronograf.Permissions{ + { + Scope: "all", + Allowed: []string{"WRITE", "READ"}, + }, + { + Scope: "database", + Name: "mydb", + Allowed: []string{"WRITE", "READ"}, + }, + }, + }, + }, + want: []string{ + `SHOW USERS`, + `SHOW GRANTS FOR "docbrown"`, + `GRANT ALL PRIVILEGES TO "docbrown"`, + `GRANT ALL ON "mydb" TO "docbrown"`, + }, + }, { name: "Revoke all permissions", statusUsers: http.StatusOK, @@ -870,6 +921,9 @@ func TestClient_Update(t *testing.T) { } else if strings.Contains(query, "GRANT") { rw.WriteHeader(tt.statusGrant) rw.Write(tt.grant) + } else if strings.Contains(query, "PASSWORD") { + rw.WriteHeader(tt.statusPassword) + rw.Write(tt.password) } queries = append(queries, query) }))