-
Notifications
You must be signed in to change notification settings - Fork 3.8k
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
Create system.users table. #2235
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -42,6 +42,13 @@ const ( | |
UPDATE | ||
) | ||
|
||
// Predefined sets of privileges. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should this be moved after the definition of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it's pretty clear what List does from the name. I mostly wanted the sets of privileges to be right next to the actual privileges themselves. |
||
var ( | ||
ReadData = List{GRANT, SELECT} | ||
WriteData = List{INSERT, DELETE, UPDATE} | ||
ReadWriteData = List{GRANT, SELECT, INSERT, DELETE, UPDATE} | ||
) | ||
|
||
// Mask returns the bitmask for a given privilege. | ||
func (k Kind) Mask() uint32 { | ||
return 1 << k | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -20,46 +20,47 @@ package sql_test | |
import ( | ||
"testing" | ||
|
||
"github.com/cockroachdb/cockroach/security" | ||
"github.com/cockroachdb/cockroach/sql" | ||
"github.com/cockroachdb/cockroach/sql/privilege" | ||
"github.com/cockroachdb/cockroach/util/leaktest" | ||
) | ||
|
||
func TestPrivilege(t *testing.T) { | ||
defer leaktest.AfterTest(t) | ||
descriptor := sql.NewDefaultDatabasePrivilegeDescriptor() | ||
descriptor := sql.NewDefaultPrivilegeDescriptor() | ||
|
||
testCases := []struct { | ||
grantee string // User to grant/revoke privileges on. | ||
grant, revoke privilege.List | ||
show []sql.UserPrivilegeString | ||
}{ | ||
{"", nil, nil, | ||
[]sql.UserPrivilegeString{{"root", "ALL"}}, | ||
[]sql.UserPrivilegeString{{security.RootUser, "ALL"}}, | ||
}, | ||
{"root", privilege.List{privilege.ALL}, nil, | ||
[]sql.UserPrivilegeString{{"root", "ALL"}}, | ||
{security.RootUser, privilege.List{privilege.ALL}, nil, | ||
[]sql.UserPrivilegeString{{security.RootUser, "ALL"}}, | ||
}, | ||
{"root", privilege.List{privilege.INSERT, privilege.DROP}, nil, | ||
[]sql.UserPrivilegeString{{"root", "ALL"}}, | ||
{security.RootUser, privilege.List{privilege.INSERT, privilege.DROP}, nil, | ||
[]sql.UserPrivilegeString{{security.RootUser, "ALL"}}, | ||
}, | ||
{"foo", privilege.List{privilege.INSERT, privilege.DROP}, nil, | ||
[]sql.UserPrivilegeString{{"foo", "DROP,INSERT"}, {"root", "ALL"}}, | ||
[]sql.UserPrivilegeString{{"foo", "DROP,INSERT"}, {security.RootUser, "ALL"}}, | ||
}, | ||
{"bar", nil, privilege.List{privilege.INSERT, privilege.ALL}, | ||
[]sql.UserPrivilegeString{{"foo", "DROP,INSERT"}, {"root", "ALL"}}, | ||
[]sql.UserPrivilegeString{{"foo", "DROP,INSERT"}, {security.RootUser, "ALL"}}, | ||
}, | ||
{"foo", privilege.List{privilege.ALL}, nil, | ||
[]sql.UserPrivilegeString{{"foo", "ALL"}, {"root", "ALL"}}, | ||
[]sql.UserPrivilegeString{{"foo", "ALL"}, {security.RootUser, "ALL"}}, | ||
}, | ||
{"foo", nil, privilege.List{privilege.SELECT, privilege.INSERT}, | ||
[]sql.UserPrivilegeString{{"foo", "CREATE,DELETE,DROP,GRANT,UPDATE"}, {"root", "ALL"}}, | ||
[]sql.UserPrivilegeString{{"foo", "CREATE,DELETE,DROP,GRANT,UPDATE"}, {security.RootUser, "ALL"}}, | ||
}, | ||
{"foo", nil, privilege.List{privilege.ALL}, | ||
[]sql.UserPrivilegeString{{"root", "ALL"}}, | ||
[]sql.UserPrivilegeString{{security.RootUser, "ALL"}}, | ||
}, | ||
// Validate checks that root still has ALL privileges, but we do not call it here. | ||
{"root", nil, privilege.List{privilege.ALL}, | ||
{security.RootUser, nil, privilege.List{privilege.ALL}, | ||
[]sql.UserPrivilegeString{}, | ||
}, | ||
} | ||
|
@@ -90,60 +91,119 @@ func TestPrivilege(t *testing.T) { | |
} | ||
} | ||
|
||
// TestPrivilegeValidate exercises validation for non-system descriptors. | ||
func TestPrivilegeValidate(t *testing.T) { | ||
defer leaktest.AfterTest(t) | ||
descriptor := sql.NewDefaultDatabasePrivilegeDescriptor() | ||
if err := descriptor.Validate(false); err != nil { | ||
id := sql.MaxReservedDescID + 1 | ||
descriptor := sql.NewDefaultPrivilegeDescriptor() | ||
if err := descriptor.Validate(id); err != nil { | ||
t.Fatal(err) | ||
} | ||
descriptor.Grant("foo", privilege.List{privilege.ALL}) | ||
if err := descriptor.Validate(false); err != nil { | ||
if err := descriptor.Validate(id); err != nil { | ||
t.Fatal(err) | ||
} | ||
descriptor.Grant("root", privilege.List{privilege.SELECT}) | ||
if err := descriptor.Validate(false); err != nil { | ||
descriptor.Grant(security.RootUser, privilege.List{privilege.SELECT}) | ||
if err := descriptor.Validate(id); err != nil { | ||
t.Fatal(err) | ||
} | ||
descriptor.Revoke("root", privilege.List{privilege.SELECT}) | ||
if err := descriptor.Validate(false); err == nil { | ||
descriptor.Revoke(security.RootUser, privilege.List{privilege.SELECT}) | ||
if err := descriptor.Validate(id); err == nil { | ||
t.Fatal("unexpected success") | ||
} | ||
// TODO(marc): validate fails here because we do not aggregate | ||
// privileges into ALL when all are set. | ||
descriptor.Grant("root", privilege.List{privilege.SELECT}) | ||
if err := descriptor.Validate(false); err == nil { | ||
descriptor.Grant(security.RootUser, privilege.List{privilege.SELECT}) | ||
if err := descriptor.Validate(id); err == nil { | ||
t.Fatal("unexpected success") | ||
} | ||
descriptor.Revoke("root", privilege.List{privilege.ALL}) | ||
if err := descriptor.Validate(false); err == nil { | ||
descriptor.Revoke(security.RootUser, privilege.List{privilege.ALL}) | ||
if err := descriptor.Validate(id); err == nil { | ||
t.Fatal("unexpected success") | ||
} | ||
} | ||
|
||
// TestSystemPrivilegeValidate exercises validation for system descriptors. | ||
// We use 1 (the system database ID). | ||
func TestSystemPrivilegeValidate(t *testing.T) { | ||
defer leaktest.AfterTest(t) | ||
descriptor := sql.NewSystemObjectPrivilegeDescriptor() | ||
if err := descriptor.Validate(true); err != nil { | ||
t.Fatal(err) | ||
} | ||
descriptor.Grant("foo", privilege.List{privilege.SELECT, privilege.GRANT}) | ||
if err := descriptor.Validate(true); err != nil { | ||
t.Fatal(err) | ||
id := sql.ID(1) | ||
allowedPrivileges := sql.SystemAllowedPrivileges[id] | ||
|
||
hasPrivilege := func(pl privilege.List, p privilege.Kind) bool { | ||
for _, i := range pl { | ||
if i == p { | ||
return true | ||
} | ||
} | ||
return false | ||
} | ||
descriptor.Grant("root", privilege.List{privilege.SELECT}) | ||
if err := descriptor.Validate(true); err != nil { | ||
|
||
// Exhaustively grant/revoke all privileges. | ||
// Due to the way validation is done after Grant/Revoke, | ||
// we need to revert the just-performed change after errors. | ||
descriptor := sql.NewPrivilegeDescriptor(security.RootUser, allowedPrivileges) | ||
if err := descriptor.Validate(id); err != nil { | ||
t.Fatal(err) | ||
} | ||
descriptor.Revoke("root", privilege.List{privilege.SELECT}) | ||
if err := descriptor.Validate(true); err == nil { | ||
t.Fatal("unexpected success") | ||
} | ||
descriptor.Grant("root", privilege.List{privilege.INSERT}) | ||
if err := descriptor.Validate(true); err == nil { | ||
t.Fatal("unexpected success") | ||
} | ||
descriptor.Revoke("root", privilege.List{privilege.ALL}) | ||
if err := descriptor.Validate(true); err == nil { | ||
t.Fatal("unexpected success") | ||
for _, p := range privilege.ByValue { | ||
if hasPrivilege(allowedPrivileges, p) { | ||
// Grant allowed privileges. Either they are already | ||
// on (noop), or they're accepted. | ||
descriptor.Grant(security.RootUser, privilege.List{p}) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i don't understand the relationship between grant, revoke, and validate in this test. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. even with the comment at L144? |
||
if err := descriptor.Validate(id); err != nil { | ||
t.Fatal(err) | ||
} | ||
descriptor.Grant("foo", privilege.List{p}) | ||
if err := descriptor.Validate(id); err != nil { | ||
t.Fatal(err) | ||
} | ||
|
||
// Remove allowed privileges. This fails for root, | ||
// but passes for other users. | ||
descriptor.Revoke(security.RootUser, privilege.List{p}) | ||
if err := descriptor.Validate(id); err == nil { | ||
t.Fatal("unexpected success") | ||
} | ||
descriptor.Grant(security.RootUser, privilege.List{p}) | ||
} else { | ||
// Granting non-allowed privileges always. | ||
descriptor.Grant(security.RootUser, privilege.List{p}) | ||
if err := descriptor.Validate(id); err == nil { | ||
t.Fatal("unexpected success") | ||
} | ||
descriptor.Revoke(security.RootUser, privilege.List{p}) | ||
descriptor.Grant(security.RootUser, allowedPrivileges) | ||
|
||
descriptor.Grant("foo", privilege.List{p}) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. these non-root cases can be hoisted out of this There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. just the Revoke("foo") ones. the grant ones succeed in the if, and fail in the else. |
||
if err := descriptor.Validate(id); err == nil { | ||
t.Fatal("unexpected success") | ||
} | ||
descriptor.Revoke("foo", privilege.List{p}) | ||
descriptor.Grant("foo", allowedPrivileges) | ||
|
||
// Revoking non-allowed privileges always succeeds, | ||
// except when removing ALL for root. | ||
if p == privilege.ALL { | ||
// We need to reset privileges as Revoke(ALL) will clear | ||
// all bits. | ||
descriptor.Revoke(security.RootUser, privilege.List{p}) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this can get hoisted out |
||
if err := descriptor.Validate(id); err == nil { | ||
t.Fatal("unexpected success") | ||
} | ||
descriptor.Grant(security.RootUser, allowedPrivileges) | ||
} else { | ||
descriptor.Revoke(security.RootUser, privilege.List{p}) | ||
if err := descriptor.Validate(id); err != nil { | ||
t.Fatal(err) | ||
} | ||
} | ||
} | ||
|
||
// We can always revoke anything from non-root users. | ||
descriptor.Revoke("foo", privilege.List{p}) | ||
if err := descriptor.Validate(id); err != nil { | ||
t.Fatal(err) | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, this is annoying. Maybe we should strip keys that start with
TableDataPrefix
.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Either ignore them, or have a little helper somewhere. Still not sure and definitely not critical, hence the TODO. At the very least, it won't surprise anyone else.