Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Show grants for user statement #2650

Merged
merged 2 commits into from
Jun 16, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
## v0.9.1 [unreleased]

### Features

- [2650](https://github.com/influxdb/influxdb/pull/2650): Add SHOW GRANTS FOR USER statement. Thanks @n1tr0g.

### Bugfixes

- [#2908](https://github.com/influxdb/influxdb/issues/2908): Field mismatch error messages need to be updated
Expand Down
22 changes: 22 additions & 0 deletions influxql/ast.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ func (*DropSeriesStatement) node() {}
func (*DropUserStatement) node() {}
func (*GrantStatement) node() {}
func (*ShowContinuousQueriesStatement) node() {}
func (*ShowGrantsForUserStatement) node() {}
func (*ShowServersStatement) node() {}
func (*ShowDatabasesStatement) node() {}
func (*ShowFieldKeysStatement) node() {}
Expand Down Expand Up @@ -193,6 +194,7 @@ func (*DropSeriesStatement) stmt() {}
func (*DropUserStatement) stmt() {}
func (*GrantStatement) stmt() {}
func (*ShowContinuousQueriesStatement) stmt() {}
func (*ShowGrantsForUserStatement) stmt() {}
func (*ShowServersStatement) stmt() {}
func (*ShowDatabasesStatement) stmt() {}
func (*ShowFieldKeysStatement) stmt() {}
Expand Down Expand Up @@ -1518,6 +1520,26 @@ func (s *ShowContinuousQueriesStatement) RequiredPrivileges() ExecutionPrivilege
return ExecutionPrivileges{{Name: "", Privilege: ReadPrivilege}}
}

// ShowGrantsForUserStatement represents a command for listing user privileges.
type ShowGrantsForUserStatement struct {
// Name of the user to display privileges.
Name string
}

// String returns a string representation of the show grants for user.
func (s *ShowGrantsForUserStatement) String() string {
var buf bytes.Buffer
_, _ = buf.WriteString("SHOW GRANTS FOR ")
_, _ = buf.WriteString(s.Name)

return buf.String()
}

// RequiredPrivileges returns the privilege required to execute a ShowGrantsForUserStatement
func (s *ShowGrantsForUserStatement) RequiredPrivileges() ExecutionPrivileges {
return ExecutionPrivileges{{Name: "", Privilege: AllPrivileges}}
}

// ShowServersStatement represents a command for listing all servers.
type ShowServersStatement struct{}

Expand Down
24 changes: 23 additions & 1 deletion influxql/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,8 @@ func (p *Parser) parseShowStatement() (Statement, error) {
switch tok {
case CONTINUOUS:
return p.parseShowContinuousQueriesStatement()
case GRANTS:
return p.parseGrantsForUserStatement()
case DATABASES:
return p.parseShowDatabasesStatement()
case SERVERS:
Expand Down Expand Up @@ -143,7 +145,7 @@ func (p *Parser) parseShowStatement() (Statement, error) {
return p.parseShowUsersStatement()
}

return nil, newParseError(tokstr(tok, lit), []string{"CONTINUOUS", "DATABASES", "FIELD", "MEASUREMENTS", "RETENTION", "SERIES", "SERVERS", "TAG", "USERS"}, pos)
return nil, newParseError(tokstr(tok, lit), []string{"CONTINUOUS", "DATABASES", "FIELD", "GRANTS", "MEASUREMENTS", "RETENTION", "SERIES", "SERVERS", "TAG", "USERS"}, pos)
}

// parseCreateStatement parses a string and returns a create statement.
Expand Down Expand Up @@ -1081,6 +1083,26 @@ func (p *Parser) parseShowServersStatement() (*ShowServersStatement, error) {
return stmt, nil
}

// parseGrantsForUserStatement parses a string and returns a ShowGrantsForUserStatement.
// This function assumes the "SHOW GRANTS" tokens have already been consumed.
func (p *Parser) parseGrantsForUserStatement() (*ShowGrantsForUserStatement, error) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need to fix the comment for this method.

stmt := &ShowGrantsForUserStatement{}

// Expect a "FOR" token.
if tok, pos, lit := p.scanIgnoreWhitespace(); tok != FOR {
return nil, newParseError(tokstr(tok, lit), []string{"FOR"}, pos)
}

// Parse the name of the user to be displayed.
lit, err := p.parseIdent()
if err != nil {
return nil, err
}
stmt.Name = lit

return stmt, nil
}

// parseShowDatabasesStatement parses a string and returns a ShowDatabasesStatement.
// This function assumes the "SHOW DATABASE" tokens have already been consumed.
func (p *Parser) parseShowDatabasesStatement() (*ShowDatabasesStatement, error) {
Expand Down
10 changes: 9 additions & 1 deletion influxql/parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -534,6 +534,12 @@ func TestParser_ParseStatement(t *testing.T) {
stmt: &influxql.ShowServersStatement{},
},

// SHOW GRANTS
{
s: `SHOW GRANTS FOR jdoe`,
stmt: &influxql.ShowGrantsForUserStatement{Name: "jdoe"},
},

// SHOW DATABASES
{
s: `SHOW DATABASES`,
Expand Down Expand Up @@ -1228,8 +1234,10 @@ func TestParser_ParseStatement(t *testing.T) {
{s: `SHOW CONTINUOUS`, err: `found EOF, expected QUERIES at line 1, char 17`},
{s: `SHOW RETENTION`, err: `found EOF, expected POLICIES at line 1, char 16`},
{s: `SHOW RETENTION POLICIES`, err: `found EOF, expected identifier at line 1, char 25`},
{s: `SHOW FOO`, err: `found FOO, expected CONTINUOUS, DATABASES, FIELD, MEASUREMENTS, RETENTION, SERIES, SERVERS, TAG, USERS at line 1, char 6`},
{s: `SHOW FOO`, err: `found FOO, expected CONTINUOUS, DATABASES, FIELD, GRANTS, MEASUREMENTS, RETENTION, SERIES, SERVERS, TAG, USERS at line 1, char 6`},
{s: `SHOW STATS ON`, err: `found EOF, expected string at line 1, char 15`},
{s: `SHOW GRANTS`, err: `found EOF, expected FOR at line 1, char 13`},
{s: `SHOW GRANTS FOR`, err: `found EOF, expected identifier at line 1, char 17`},
{s: `DROP CONTINUOUS`, err: `found EOF, expected QUERY at line 1, char 17`},
{s: `DROP CONTINUOUS QUERY`, err: `found EOF, expected identifier at line 1, char 23`},
{s: `DROP CONTINUOUS QUERY myquery`, err: `found EOF, expected ON at line 1, char 31`},
Expand Down
2 changes: 2 additions & 0 deletions influxql/token.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ const (
FOR
FROM
GRANT
GRANTS
GROUP
IF
IN
Expand Down Expand Up @@ -184,6 +185,7 @@ var tokens = [...]string{
FOR: "FOR",
FROM: "FROM",
GRANT: "GRANT",
GRANTS: "GRANTS",
GROUP: "GROUP",
IF: "IF",
IN: "IN",
Expand Down
10 changes: 10 additions & 0 deletions meta/data.go
Original file line number Diff line number Diff line change
Expand Up @@ -458,6 +458,16 @@ func (data *Data) SetPrivilege(name, database string, p influxql.Privilege) erro
return nil
}

// UserPrivileges get privileges for a user.
func (data *Data) UserPrivileges(name string) (map[string]influxql.Privilege, error) {
ui := data.User(name)
if ui == nil {
return nil, ErrUserNotFound
}

return ui.Privileges, nil
}

// Clone returns a copy of data with a new version.
func (data *Data) Clone() *Data {
other := *data
Expand Down
16 changes: 16 additions & 0 deletions meta/statement_executor.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ type StatementExecutor struct {
UpdateUser(name, password string) error
DropUser(name string) error
SetPrivilege(username, database string, p influxql.Privilege) error
UserPrivileges(username string) (map[string]influxql.Privilege, error)

CreateContinuousQuery(database, name, query string) error
DropContinuousQuery(database, name string) error
Expand All @@ -42,6 +43,8 @@ func (e *StatementExecutor) ExecuteStatement(stmt influxql.Statement) *influxql.
return e.executeDropDatabaseStatement(stmt)
case *influxql.ShowDatabasesStatement:
return e.executeShowDatabasesStatement(stmt)
case *influxql.ShowGrantsForUserStatement:
return e.executeShowGrantsForUserStatement(stmt)
case *influxql.ShowServersStatement:
return e.executeShowServersStatement(stmt)
case *influxql.CreateUserStatement:
Expand Down Expand Up @@ -97,6 +100,19 @@ func (e *StatementExecutor) executeShowDatabasesStatement(q *influxql.ShowDataba
return &influxql.Result{Series: []*influxql.Row{row}}
}

func (e *StatementExecutor) executeShowGrantsForUserStatement(q *influxql.ShowGrantsForUserStatement) *influxql.Result {
priv, err := e.Store.UserPrivileges(q.Name)
if err != nil {
return &influxql.Result{Err: err}
}

row := &influxql.Row{Columns: []string{"database", "privilege"}}
for d, p := range priv {
row.Values = append(row.Values, []interface{}{d, p.String()})
}
return &influxql.Result{Series: []*influxql.Row{row}}
}

func (e *StatementExecutor) executeShowServersStatement(q *influxql.ShowServersStatement) *influxql.Result {
nis, err := e.Store.Nodes()
if err != nil {
Expand Down
33 changes: 33 additions & 0 deletions meta/statement_executor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,34 @@ func TestStatementExecutor_ExecuteStatement_ShowDatabases_Err(t *testing.T) {
}
}

// Ensure a SHOW GRANTS FOR statement can be executed.
func TestStatementExecutor_ExecuteStatement_ShowGrantsFor(t *testing.T) {
e := NewStatementExecutor()
e.Store.UserPrivilegesFn = func(username string) (map[string]influxql.Privilege, error) {
if username != "dejan" {
t.Fatalf("unexpected username: %s", username)
}
return map[string]influxql.Privilege{
"dejan": influxql.ReadPrivilege,
"golja": influxql.WritePrivilege,
}, nil
}

if res := e.ExecuteStatement(influxql.MustParseStatement(`SHOW GRANTS FOR dejan`)); res.Err != nil {
t.Fatal(res.Err)
} else if !reflect.DeepEqual(res.Series, influxql.Rows{
{
Columns: []string{"database", "privilege"},
Values: [][]interface{}{
{"dejan", "READ"},
{"golja", "WRITE"},
},
},
}) {
t.Fatalf("unexpected rows: %s", spew.Sdump(res.Series))
}
}

// Ensure a SHOW SERVERS statement can be executed.
func TestStatementExecutor_ExecuteStatement_ShowServers(t *testing.T) {
e := NewStatementExecutor()
Expand Down Expand Up @@ -701,6 +729,7 @@ type StatementExecutorStore struct {
UpdateUserFn func(name, password string) error
DropUserFn func(name string) error
SetPrivilegeFn func(username, database string, p influxql.Privilege) error
UserPrivilegesFn func(username string) (map[string]influxql.Privilege, error)
ContinuousQueriesFn func() ([]meta.ContinuousQueryInfo, error)
CreateContinuousQueryFn func(database, name, query string) error
DropContinuousQueryFn func(database, name string) error
Expand Down Expand Up @@ -766,6 +795,10 @@ func (s *StatementExecutorStore) SetPrivilege(username, database string, p influ
return s.SetPrivilegeFn(username, database, p)
}

func (s *StatementExecutorStore) UserPrivileges(username string) (map[string]influxql.Privilege, error) {
return s.UserPrivilegesFn(username)
}

func (s *StatementExecutorStore) ContinuousQueries() ([]meta.ContinuousQueryInfo, error) {
return s.ContinuousQueriesFn()
}
Expand Down
9 changes: 9 additions & 0 deletions meta/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -1039,6 +1039,15 @@ func (s *Store) SetPrivilege(username, database string, p influxql.Privilege) er
)
}

// UserPrivileges returns a list of all databases.
func (s *Store) UserPrivileges(username string) (p map[string]influxql.Privilege, err error) {
err = s.read(func(data *Data) error {
p, err = data.UserPrivileges(username)
return err
})
return
}

// UserCount returns the number of users defined in the cluster.
func (s *Store) UserCount() (count int, err error) {
err = s.read(func(data *Data) error {
Expand Down