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

Wire up admin privilege grant and revoke (#2). Fixes #2872 #3244

Merged
merged 1 commit into from
Jul 17, 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
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