From 1469cc1d72fa00cb5aea228374650dc3649f0c45 Mon Sep 17 00:00:00 2001 From: Dejan Golja Date: Sun, 24 May 2015 17:27:02 +1000 Subject: [PATCH] Added support for SHOW GRANTS FOR USER syntax --- influxql/ast.go | 22 ++++++++++++++++++++++ influxql/parser.go | 24 +++++++++++++++++++++++- influxql/token.go | 2 ++ server.go | 27 +++++++++++++++++++++++++++ 4 files changed, 74 insertions(+), 1 deletion(-) diff --git a/influxql/ast.go b/influxql/ast.go index cb7ffcdd9cd..741ebe75e9d 100644 --- a/influxql/ast.go +++ b/influxql/ast.go @@ -75,6 +75,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() {} @@ -175,6 +176,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() {} @@ -1500,6 +1502,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{} diff --git a/influxql/parser.go b/influxql/parser.go index 7f2954255ce..c45935e3a08 100644 --- a/influxql/parser.go +++ b/influxql/parser.go @@ -93,6 +93,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: @@ -129,7 +131,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. @@ -1067,6 +1069,26 @@ func (p *Parser) parseShowServersStatement() (*ShowServersStatement, error) { return stmt, nil } +// parseShowDatabasesStatement parses a string and returns a ShowDatabasesStatement. +// This function assumes the "SHOW GRANTS" tokens have already been consumed. +func (p *Parser) parseGrantsForUserStatement() (*ShowGrantsForUserStatement, error) { + 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) { diff --git a/influxql/token.go b/influxql/token.go index 4eae37c7221..0eb5b7a9a6d 100644 --- a/influxql/token.go +++ b/influxql/token.go @@ -78,6 +78,7 @@ const ( FOR FROM GRANT + GRANTS GROUP IF IN @@ -184,6 +185,7 @@ var tokens = [...]string{ FOR: "FOR", FROM: "FROM", GRANT: "GRANT", + GRANTS: "GRANTS", GROUP: "GROUP", IF: "IF", IN: "IN", diff --git a/server.go b/server.go index 2d5d0ab090a..1ba9ed63c87 100644 --- a/server.go +++ b/server.go @@ -883,6 +883,16 @@ func (s *Server) DataNodeByURL(u *url.URL) *DataNode { return nil } +// UserPrivileges +func (s *Server) UserPrivileges(user string) (p map[string]influxql.Privilege, err error) { + u := s.User(user) + + if u == nil { + return nil, ErrUserNotFound + } + return u.Privileges, nil +} + // DataNodes returns a list of data nodes. func (s *Server) DataNodes() (a []*DataNode) { s.mu.RLock() @@ -2232,6 +2242,8 @@ func (s *Server) ExecuteQuery(q *influxql.Query, database string, user *User, ch res = s.executeDropDatabaseStatement(stmt, user) case *influxql.ShowDatabasesStatement: res = s.executeShowDatabasesStatement(stmt, user) + case *influxql.ShowGrantsForUserStatement: + res = s.executeShowGrantsForUserStatement(stmt, user) case *influxql.ShowServersStatement: res = s.executeShowServersStatement(stmt, user) case *influxql.CreateUserStatement: @@ -2512,6 +2524,21 @@ func (s *Server) executeShowDatabasesStatement(q *influxql.ShowDatabasesStatemen return &Result{Series: []*influxql.Row{row}} } +func (s *Server) executeShowGrantsForUserStatement(q *influxql.ShowGrantsForUserStatement, user *User) *Result { + row := &influxql.Row{Columns: []string{"database", "privilege"}} + + priv, err := s.UserPrivileges(q.Name) + + if err != nil { + return &Result{Err: err} + } + + for d, p := range priv { + row.Values = append(row.Values, []interface{}{d, p.String()}) + } + return &Result{Series: []*influxql.Row{row}} +} + func (s *Server) executeShowServersStatement(q *influxql.ShowServersStatement, user *User) *Result { row := &influxql.Row{Columns: []string{"id", "url"}} for _, node := range s.DataNodes() {