Skip to content

Commit

Permalink
Merge pull request #3244 from influxdb/ga-admin-privilege-2
Browse files Browse the repository at this point in the history
Wire up admin privilege grant and revoke (#2). Fixes #2872
  • Loading branch information
gunnaraasen committed Jul 17, 2015
2 parents f404a8a + 9ba3732 commit d1da730
Show file tree
Hide file tree
Showing 14 changed files with 558 additions and 205 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
- [#2761](https://github.com/influxdb/influxdb/issues/2761): Make SHOW RETENTION POLICIES consistent with other queries.
- [#3356](https://github.com/influxdb/influxdb/pull/3356): Disregard semicolons after database name in use command. Thanks @timraymond.
- [#3351](https://github.com/influxdb/influxdb/pull/3351): Handle malformed regex comparisons during parsing. Thanks @rnubel
- [#3244](https://github.com/influxdb/influxdb/pull/3244): Wire up admin privilege grant and revoke.
- [#3259](https://github.com/influxdb/influxdb/issues/3259): Respect privileges for queries.

## v0.9.1 [2015-07-02]

Expand Down
144 changes: 91 additions & 53 deletions influxql/ast.go

Large diffs are not rendered by default.

132 changes: 101 additions & 31 deletions influxql/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -521,39 +521,58 @@ func (p *Parser) parseString() (string, error) {

// parseRevokeStatement parses a string and returns a revoke statement.
// This function assumes the REVOKE token has already been consumed.
func (p *Parser) parseRevokeStatement() (*RevokeStatement, error) {
stmt := &RevokeStatement{}

func (p *Parser) parseRevokeStatement() (Statement, error) {
// Parse the privilege to be revoked.
priv, err := p.parsePrivilege()
if err != nil {
return nil, err
}
stmt.Privilege = priv

// Parse ON clause.
// Check for ON or FROM clauses.
tok, pos, lit := p.scanIgnoreWhitespace()
if tok == ON {
// Parse the name of the thing we're revoking a privilege to use.
lit, err := p.parseIdent()
stmt, err := p.parseRevokeOnStatement()
if err != nil {
return nil, err
}
stmt.On = lit
stmt.Privilege = priv
return stmt, nil
} else if tok == FROM {
// Admin privilege is only revoked on ALL PRIVILEGES.
if priv != AllPrivileges {
return nil, newParseError(tokstr(tok, lit), []string{"ON"}, pos)
}
return p.parseRevokeAdminStatement()
}

tok, pos, lit = p.scanIgnoreWhitespace()
} else if priv != AllPrivileges {
// ALL PRIVILEGES is the only privilege allowed cluster-wide.
// No ON clause means query is requesting cluster-wide.
return nil, newParseError(tokstr(tok, lit), []string{"ON"}, pos)
// Only ON or FROM clauses are allowed after privilege.
if priv == AllPrivileges {
return nil, newParseError(tokstr(tok, lit), []string{"ON", "FROM"}, pos)
}
return nil, newParseError(tokstr(tok, lit), []string{"ON"}, pos)
}

// parseRevokeOnStatement parses a string and returns a revoke statement.
// This function assumes the [PRIVILEGE] ON tokens have already been consumed.
func (p *Parser) parseRevokeOnStatement() (*RevokeStatement, error) {
stmt := &RevokeStatement{}

// Parse the name of the database.
lit, err := p.parseIdent()
if err != nil {
return nil, err
}
stmt.On = lit

// Parse FROM clause.
tok, pos, lit := p.scanIgnoreWhitespace()

// Check for required FROM token.
if tok != FROM {
return nil, newParseError(tokstr(tok, lit), []string{"FROM"}, pos)
}

// Parse the name of the user we're revoking the privilege from.
// Parse the name of the user.
lit, err = p.parseIdent()
if err != nil {
return nil, err
Expand All @@ -563,41 +582,76 @@ func (p *Parser) parseRevokeStatement() (*RevokeStatement, error) {
return stmt, nil
}

// parseRevokeAdminStatement parses a string and returns a revoke admin statement.
// This function assumes the ALL [PRVILEGES] FROM token has already been consumed.
func (p *Parser) parseRevokeAdminStatement() (*RevokeAdminStatement, error) {
// Admin privilege is always false when revoke admin clause is called.
stmt := &RevokeAdminStatement{}

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

return stmt, nil
}

// parseGrantStatement parses a string and returns a grant statement.
// This function assumes the GRANT token has already been consumed.
func (p *Parser) parseGrantStatement() (*GrantStatement, error) {
stmt := &GrantStatement{}

func (p *Parser) parseGrantStatement() (Statement, error) {
// Parse the privilege to be granted.
priv, err := p.parsePrivilege()
if err != nil {
return nil, err
}
stmt.Privilege = priv

// Parse ON clause.
// Check for ON or TO clauses.
tok, pos, lit := p.scanIgnoreWhitespace()
if tok == ON {
// Parse the name of the thing we're granting a privilege to use.
lit, err := p.parseIdent()
stmt, err := p.parseGrantOnStatement()
if err != nil {
return nil, err
}
stmt.On = lit
stmt.Privilege = priv
return stmt, nil
} else if tok == TO {
// Admin privilege is only granted on ALL PRIVILEGES.
if priv != AllPrivileges {
return nil, newParseError(tokstr(tok, lit), []string{"ON"}, pos)
}
return p.parseGrantAdminStatement()
}

tok, pos, lit = p.scanIgnoreWhitespace()
} else if priv != AllPrivileges {
// ALL PRIVILEGES is the only privilege allowed cluster-wide.
// No ON clause means query is requesting cluster-wide.
return nil, newParseError(tokstr(tok, lit), []string{"ON"}, pos)
// Only ON or TO clauses are allowed after privilege.
if priv == AllPrivileges {
return nil, newParseError(tokstr(tok, lit), []string{"ON", "TO"}, pos)
}
return nil, newParseError(tokstr(tok, lit), []string{"ON"}, pos)
}

// parseGrantOnStatement parses a string and returns a grant statement.
// This function assumes the [PRIVILEGE] ON tokens have already been consumed.
func (p *Parser) parseGrantOnStatement() (*GrantStatement, error) {
stmt := &GrantStatement{}

// Parse the name of the database.
lit, err := p.parseIdent()
if err != nil {
return nil, err
}
stmt.On = lit

// Parse TO clause.
tok, pos, lit := p.scanIgnoreWhitespace()

// Check for required TO token.
if tok != TO {
return nil, newParseError(tokstr(tok, lit), []string{"TO"}, pos)
}

// Parse the name of the user we're granting the privilege to.
// Parse the name of the user.
lit, err = p.parseIdent()
if err != nil {
return nil, err
Expand All @@ -607,6 +661,22 @@ func (p *Parser) parseGrantStatement() (*GrantStatement, error) {
return stmt, nil
}

// parseGrantAdminStatement parses a string and returns a grant admin statement.
// This function assumes the ALL [PRVILEGES] TO tokens have already been consumed.
func (p *Parser) parseGrantAdminStatement() (*GrantAdminStatement, error) {
// Admin privilege is always true when grant admin clause is called.
stmt := &GrantAdminStatement{}

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

return stmt, nil
}

// parsePrivilege parses a string and returns a Privilege
func (p *Parser) parsePrivilege() (Privilege, error) {
tok, pos, lit := p.scanIgnoreWhitespace()
Expand Down Expand Up @@ -1259,12 +1329,12 @@ func (p *Parser) parseCreateUserStatement() (*CreateUserStatement, error) {
return stmt, nil
}

// We only allow granting of "ALL PRIVILEGES" during CREATE USER.
// All other privileges must be granted using a GRANT statement.
// "WITH ALL PRIVILEGES" grants the new user admin privilege.
// Only admin privilege can be set on user creation.
if err := p.parseTokens([]Token{ALL, PRIVILEGES}); err != nil {
return nil, err
}
stmt.Privilege = NewPrivilege(AllPrivileges)
stmt.Admin = true

return stmt, nil
}
Expand Down
93 changes: 79 additions & 14 deletions influxql/parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -942,9 +942,9 @@ func TestParser_ParseStatement(t *testing.T) {
{
s: `CREATE USER testuser WITH PASSWORD 'pwd1337' WITH ALL PRIVILEGES`,
stmt: &influxql.CreateUserStatement{
Name: "testuser",
Password: "pwd1337",
Privilege: influxql.NewPrivilege(influxql.AllPrivileges),
Name: "testuser",
Password: "pwd1337",
Admin: true,
},
},

Expand Down Expand Up @@ -1030,12 +1030,19 @@ func TestParser_ParseStatement(t *testing.T) {
},
},

// GRANT cluster admin
// GRANT ALL admin privilege
{
s: `GRANT ALL TO jdoe`,
stmt: &influxql.GrantAdminStatement{
User: "jdoe",
},
},

// GRANT ALL PRVILEGES admin privilege
{
s: `GRANT ALL PRIVILEGES TO jdoe`,
stmt: &influxql.GrantStatement{
Privilege: influxql.AllPrivileges,
User: "jdoe",
stmt: &influxql.GrantAdminStatement{
User: "jdoe",
},
},

Expand Down Expand Up @@ -1079,12 +1086,19 @@ func TestParser_ParseStatement(t *testing.T) {
},
},

// REVOKE cluster admin
// REVOKE ALL admin privilege
{
s: `REVOKE ALL FROM jdoe`,
stmt: &influxql.RevokeStatement{
Privilege: influxql.AllPrivileges,
User: "jdoe",
stmt: &influxql.RevokeAdminStatement{
User: "jdoe",
},
},

// REVOKE ALL PRIVILEGES admin privilege
{
s: `REVOKE ALL PRIVILEGES FROM jdoe`,
stmt: &influxql.RevokeAdminStatement{
User: "jdoe",
},
},

Expand Down Expand Up @@ -1263,16 +1277,67 @@ func TestParser_ParseStatement(t *testing.T) {
{s: `GRANT`, err: `found EOF, expected READ, WRITE, ALL [PRIVILEGES] at line 1, char 7`},
{s: `GRANT BOGUS`, err: `found BOGUS, expected READ, WRITE, ALL [PRIVILEGES] at line 1, char 7`},
{s: `GRANT READ`, err: `found EOF, expected ON at line 1, char 12`},
{s: `GRANT READ TO jdoe`, err: `found TO, expected ON at line 1, char 12`},
{s: `GRANT READ FROM`, err: `found FROM, expected ON at line 1, char 12`},
{s: `GRANT READ ON`, err: `found EOF, expected identifier at line 1, char 15`},
{s: `GRANT READ ON TO`, err: `found TO, expected identifier at line 1, char 15`},
{s: `GRANT READ ON testdb`, err: `found EOF, expected TO at line 1, char 22`},
{s: `GRANT READ ON testdb TO`, err: `found EOF, expected identifier at line 1, char 25`}, {s: `GRANT`, err: `found EOF, expected READ, WRITE, ALL [PRIVILEGES] at line 1, char 7`},
{s: `GRANT READ ON testdb TO`, err: `found EOF, expected identifier at line 1, char 25`},
{s: `GRANT READ TO`, err: `found TO, expected ON at line 1, char 12`},
{s: `GRANT WRITE`, err: `found EOF, expected ON at line 1, char 13`},
{s: `GRANT WRITE FROM`, err: `found FROM, expected ON at line 1, char 13`},
{s: `GRANT WRITE ON`, err: `found EOF, expected identifier at line 1, char 16`},
{s: `GRANT WRITE ON TO`, err: `found TO, expected identifier at line 1, char 16`},
{s: `GRANT WRITE ON testdb`, err: `found EOF, expected TO at line 1, char 23`},
{s: `GRANT WRITE ON testdb TO`, err: `found EOF, expected identifier at line 1, char 26`},
{s: `GRANT WRITE TO`, err: `found TO, expected ON at line 1, char 13`},
{s: `GRANT ALL`, err: `found EOF, expected ON, TO at line 1, char 11`},
{s: `GRANT ALL PRIVILEGES`, err: `found EOF, expected ON, TO at line 1, char 22`},
{s: `GRANT ALL FROM`, err: `found FROM, expected ON, TO at line 1, char 11`},
{s: `GRANT ALL PRIVILEGES FROM`, err: `found FROM, expected ON, TO at line 1, char 22`},
{s: `GRANT ALL ON`, err: `found EOF, expected identifier at line 1, char 14`},
{s: `GRANT ALL PRIVILEGES ON`, err: `found EOF, expected identifier at line 1, char 25`},
{s: `GRANT ALL ON TO`, err: `found TO, expected identifier at line 1, char 14`},
{s: `GRANT ALL PRIVILEGES ON TO`, err: `found TO, expected identifier at line 1, char 25`},
{s: `GRANT ALL ON testdb`, err: `found EOF, expected TO at line 1, char 21`},
{s: `GRANT ALL PRIVILEGES ON testdb`, err: `found EOF, expected TO at line 1, char 32`},
{s: `GRANT ALL ON testdb FROM`, err: `found FROM, expected TO at line 1, char 21`},
{s: `GRANT ALL PRIVILEGES ON testdb FROM`, err: `found FROM, expected TO at line 1, char 32`},
{s: `GRANT ALL ON testdb TO`, err: `found EOF, expected identifier at line 1, char 24`},
{s: `GRANT ALL PRIVILEGES ON testdb TO`, err: `found EOF, expected identifier at line 1, char 35`},
{s: `GRANT ALL TO`, err: `found EOF, expected identifier at line 1, char 14`},
{s: `GRANT ALL PRIVILEGES TO`, err: `found EOF, expected identifier at line 1, char 25`},
{s: `REVOKE`, err: `found EOF, expected READ, WRITE, ALL [PRIVILEGES] at line 1, char 8`},
{s: `REVOKE BOGUS`, err: `found BOGUS, expected READ, WRITE, ALL [PRIVILEGES] at line 1, char 8`},
{s: `REVOKE READ`, err: `found EOF, expected ON at line 1, char 13`},
{s: `REVOKE READ TO jdoe`, err: `found TO, expected ON at line 1, char 13`},
{s: `REVOKE READ TO`, err: `found TO, expected ON at line 1, char 13`},
{s: `REVOKE READ ON`, err: `found EOF, expected identifier at line 1, char 16`},
{s: `REVOKE READ ON FROM`, err: `found FROM, expected identifier at line 1, char 16`},
{s: `REVOKE READ ON testdb`, err: `found EOF, expected FROM at line 1, char 23`},
{s: `REVOKE READ ON testdb FROM`, err: `found EOF, expected identifier at line 1, char 28`},
{s: `REVOKE READ FROM`, err: `found FROM, expected ON at line 1, char 13`},
{s: `REVOKE WRITE`, err: `found EOF, expected ON at line 1, char 14`},
{s: `REVOKE WRITE TO`, err: `found TO, expected ON at line 1, char 14`},
{s: `REVOKE WRITE ON`, err: `found EOF, expected identifier at line 1, char 17`},
{s: `REVOKE WRITE ON FROM`, err: `found FROM, expected identifier at line 1, char 17`},
{s: `REVOKE WRITE ON testdb`, err: `found EOF, expected FROM at line 1, char 24`},
{s: `REVOKE WRITE ON testdb FROM`, err: `found EOF, expected identifier at line 1, char 29`},
{s: `REVOKE WRITE FROM`, err: `found FROM, expected ON at line 1, char 14`},
{s: `REVOKE ALL`, err: `found EOF, expected ON, FROM at line 1, char 12`},
{s: `REVOKE ALL PRIVILEGES`, err: `found EOF, expected ON, FROM at line 1, char 23`},
{s: `REVOKE ALL TO`, err: `found TO, expected ON, FROM at line 1, char 12`},
{s: `REVOKE ALL PRIVILEGES TO`, err: `found TO, expected ON, FROM at line 1, char 23`},
{s: `REVOKE ALL ON`, err: `found EOF, expected identifier at line 1, char 15`},
{s: `REVOKE ALL PRIVILEGES ON`, err: `found EOF, expected identifier at line 1, char 26`},
{s: `REVOKE ALL ON FROM`, err: `found FROM, expected identifier at line 1, char 15`},
{s: `REVOKE ALL PRIVILEGES ON FROM`, err: `found FROM, expected identifier at line 1, char 26`},
{s: `REVOKE ALL ON testdb`, err: `found EOF, expected FROM at line 1, char 22`},
{s: `REVOKE ALL PRIVILEGES ON testdb`, err: `found EOF, expected FROM at line 1, char 33`},
{s: `REVOKE ALL ON testdb TO`, err: `found TO, expected FROM at line 1, char 22`},
{s: `REVOKE ALL PRIVILEGES ON testdb TO`, err: `found TO, expected FROM at line 1, char 33`},
{s: `REVOKE ALL ON testdb FROM`, err: `found EOF, expected identifier at line 1, char 27`},
{s: `REVOKE ALL PRIVILEGES ON testdb FROM`, err: `found EOF, expected identifier at line 1, char 38`},
{s: `REVOKE ALL FROM`, err: `found EOF, expected identifier at line 1, char 17`},
{s: `REVOKE ALL PRIVILEGES FROM`, err: `found EOF, expected identifier at line 1, char 28`},
{s: `CREATE RETENTION`, err: `found EOF, expected POLICY at line 1, char 18`},
{s: `CREATE RETENTION POLICY`, err: `found EOF, expected identifier at line 1, char 25`},
{s: `CREATE RETENTION POLICY policy1`, err: `found EOF, expected ON at line 1, char 33`},
Expand Down
Loading

0 comments on commit d1da730

Please sign in to comment.